Tanuki_Bayashin’s diary

電子工作を趣味としています。最近はラズベリーパイPicoというマイコンを使って楽しんでいます

Arduino UNO R4 WIFIにてサインカーブを描いてみた

※なにか気になる点がありましたらコメント欄にご記入ください。また、工作や回路を製作する場合には、細かい作業などに対して、細心の注意を払われるようお願いいたします。

【目次】

1.はじめに

 Arduino UNO R4 WIFIという製品が発売されました。Arduino UNOの新バージョンR4版にWIFI機能がついたものです。
 筆者は特に使う目的もないまま、記念用に購入しました。

購入先(一例です):
Arduino Uno R4 WiFiwww.switch-science.com

 細かい仕様に関する情報などは、他のサイトの方にお任せするとして、まず目につくのは8×12からなるLEDの表示スペース(以下「LEDマトリクス」と表記します)です。
 このようにLEDが並んでいると何かを表示させたくなるのが、マイコンボード界隈を棲み処とする工作erの性(さが)です。

 ということで、今回は新作のArduinoのLEDにサインカーブを描くことに挑んでみました。

写真1 表示させたサインカーブ

マチュアレベルの電子工作erの書いた記事です。いたらない部分もあるかと思いますが、大目に見ていただけると幸いです。
(;´∀`)

2.新型Arduinoのセットアップ

 Arduinoには開発環境として、Arduino IDEというものがあります。このArduino IDEを使ってスケッチを書いていくには、ボードの種類ごとに初期設定が必要です。
Arduinoにはたくさんの種類があるので、それぞれのタイプに応じて設定が必要になります)

 いろいろ調べるのが大変かと思い、X(旧Twitter)の界隈での知人であるmaresakuさん(@maresaku_mono)が、最近Arduino UNO R4 WIFIに関する記事を書いてくれていたので、その記事を見て初期設定を行いました。
(大変役に立ちました)

maresakuさんの記事:
maresaku.wixsite.com

 maresakuさんには謝意を示したいと思います。ありがとうございました。

3.LEDマトリクスの仕組み

3.1 サンプル・プログラムを見てみる

 LEDマトリクスは赤色の単色LEDの集合体になっています。縦8個、横12個からなります。
 このLEDをON/OFFさせるには、以下のようなやり方があります。

リスト1 サンプル・プログラム

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup() {
  Serial.begin(115200);
  matrix.begin();
}

const uint32_t happy[] = {
    0x19819,
    0x80000001,
    0x81f8000
};

void loop(){
  matrix.loadFrame(happy);
  delay(500);

}

手順
① 必要なヘッダファイル(”Arduino_LED_Matrix.h”)をインクルードする。(ライブラリを使用可能とする)

② インスタンス matrix を生成する

③ 初期設定をする。

④ 表示させるためのテーブル(”happy”)を用意し、関数”matrix.loadFrame(happy);”にて表示する。

写真2 テーブル”happy”を表示させた

ここでミソとなってくるのがテーブル ”happy”です。次節で詳しく見てみます。

3.2 テーブル”happy”について

 図1に”happy”での表示のようすを示します。

図1 テーブル”happy” の中身


要は8×12=96個のLEDを数値で表現しているのですが、図1で見るとLEDが点灯しているところが ”1” で、それ以外を ”0” で表しています。
そうすると、二進数表示の変数が8個作られます。

これだと見づらいので、16進数で表記します(12桁の2進数を16進数に置き替えているだけです)。すると各あたいは、
0: 0x000
1: 0x198
2: 0x198
3: 0x000
4: 0x000
5: 0x108
6: 0x1F8
7: 0x000

となります。今度はこれを4バイトごと(数字8個ずつ)に区切って、変数3つで表現します。
変数1: 0x00019819
変数2: 0x80000001
変数3: 0x081F8000

これをまとめたものがテーブル(配列?)”happy” となる仕掛けです。

3.3 サインカーブ用のテーブルを作る

同じように求めたサインカーブ用のテーブルを以下に示します。(sin()の値は別のスケッチで求めた)

図2 サインカーブが描かれている

16進数で表現すると、
0: 0x803
1: 0x404
2: 0x000
3: 0x208
4: 0x000
5: 0x110
6: 0x0A0
7: 0x040

テーブル
変数1: 0x80340400
変数2: 0x02080001
変数3: 0x100A0040

写真3 表示したサインカーブ

これにてサインカーブは表示できました。

ここで、もうちょっとがんばって、スクロール表示をさせてみたいと思います。
それには上のテーブルの元(8個の変数)の最上位ビットを最下位ビットに持っていき、それ以外のビットを1ビットずつ左にずらせばいいわけですが、次の章ではちょっとだけ欲張って、そこもsin()関数で求めながら、表示させていきたいと思います。

4.サインカーブをスクロール表示させる

 完成したスケッチをリスト2に示します。(いきなりですが。汗)

スト2 完成したスケッチ

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup() {
  Serial.begin(115200);
  matrix.begin();
}

uint32_t sine[3];

const uint32_t p[3] = {
  0, 0, 0
};

void loop(){

  int y[12], h[8];

  for(int k=0; k<12; k++){

    for(int i = 0; i<8; i++){
      h[i] = 0;
    }
  
    for(int i=0;i<12;i++){
      y[i] = (int)( sin(PI / 6.0 * (i + k)) * 3.3 + 3.6);
      //Serial.println(y[i]);
      h[y[i]] += 1;
      for(int j=0;j<8;j++){
        h[j] *= 2;
      }
    }

    sine[0] = (h[0]<<20) + (h[1]<<8) + (h[2]>>4);
    sine[1] = ((h[2]&0xF)<<28) + (h[3]<<16) + (h[4]<<4) + (h[5]>>8);
    sine[2] = ((h[5]&0xFF)<<24) + (h[6]<<12) + h[7];

    matrix.loadFrame(p);
    delay(1);

    matrix.loadFrame(sine);
    delay(100);
  }

}

 基本は3章で見てきたのと同じです。
  いろいろ付け加わっていますが、ひとつづつ見ていきます。

① 配列sine と p が定義されています。(10行、12行)
  sine の中身はloop()関数内で求めます。
  p は要素がすべて0で、39行目で使用し、sineを表示する前にすべてのLEDを消灯しています。

② y とh が定義されています。(18行)
  y は各列ごとのsin() 関数の値が入ります。(27行)
  h は3章で見た8個の変数に当たり、1列ごとに(1ビットごとに)yが1となるところを1としています。(30~33行)
  (hに関しては後でもう少し詳しく説明します)

③ k のループは後ほど見ます。(20行)

④ h の配列の中身をすべて0にします。(23行)

⑤ すこし飛ばして、35~37行では求めたh の値から、テーブルsine の値を求めています。これは3章で見た、12ビットの値を4バイトずつに変換するところに当たります。


  説明すると、h[0]<<20 の ”<<” はシフト演算子と呼ばれ、ここではh[0]を20ビット左にシフト(ずらし)します。
  (シフト演算子は演算の優先順位が低いので、括弧でかこっています。また、ずらして空いた桁には0が埋められます)

  またh[2]&0xFについてですが、"&"はビット演算子のアンドで両方1のとき1になります。
  &0xFの場合、2進数表示で0のところは強制的に0になり、1の部分はh[2]の該当する部分の値がそのまま残ります。
  (0であれば0,1であれば1)

⑥ 39行で一旦、すべてのマトリクスの表示を消しています(①で述べました)。

⑦ 42行目でテーブルsine の内容をアウトプットしています。delay()で時間調整をしています。

⑧ おあずけにしてたk のループですが、27行目でy を求めるときに使っています。これは位相差に当たり、この値を0~11に変化させることで、サインカーブを右から左に動いているように見せています。

⑨ 27行を説明すると、π/6の整数倍ごとにsin() の値を求めています。i が0~11に変化する間に、sine の表示は1周します。

⑩ 最後に残ったのがh の計算です。(29~32行目)
  ここでは最上位ビット(表示の一番左)から計算しています。

  h[y[i]] += 1 とあるので、h[] のy[i] 番目の要素を1にしています。(他の要素はすべて0です)
  つまりそこだけLEDが点灯します。

  y[i] の値が大きいほど点灯するLEDは下へ行くので、y[i] を求めるときには注意が必要です。
  LEDマトリクスの上の方を+としたいのであれば、sin() 関数の頭に”ー”を付けて符号を反転させる必要があります。

  そして30~31行で2倍にしているので、各要素ごとに1ビット左にシフトしています。
  これをi = 0~11 まで続けます。つまりすべての列のy の値をh[8] に格納することになります。

このような感じでサインカーブのスクロールを実現しています。


余談になりますが、27行目のy[i] の式ですが、はじめは中心を3.5として振幅も最大で3.5とおいて表示させてみました。

しかしドットの粗さからか、いまいちぎこちないサインカーブだったので、少し微調整をして上のような値に落ち着きました。


yのところで、sin() を別の関数にすれば、別の曲線が描けることになり、さらにはアナログ入力の値を(適当に係数倍して)y[i] に代入すれば、LEDのマトリクスに時系列で表示できます。

そうです!
これは超簡易オシロスコープを実現する、一歩手前のスケッチなのでした!!!

(解像度が低いので実用的ではないと思いますが‥)

※もっと手間の少ないスケッチや分かりやすいスケッチもあるかと思います。
 なにかアイディアがありましたら、コメント欄からご指摘いただけるとありがたいです。
(義務でもないし、義理もないでしょうが・・)

5.動画

最後ににサインカーブをスクロールする動画をご紹介します。

youtu.be

以上となります。
お付き合い下さりありがとうございました。

WIFI機能は使わなかったですね (;´∀`)