NeoPixel制御ボードのサンプルプログラム⑥

- ## 商品概要
RP2040マイコンを使って、NeoPixelを制御して楽しもうというコンセプトです。
ステレオミニジャックからADコンバータに音声信号を入力してNeoPixelを振幅に合わせて
光らせるサンプルプログラムですが、ADのサンプリングと表示の更新タイミングが
まだまだ調整必要そうなので、うまくいったら更新入れるようにします。
サンプリング間引き過ぎも難しいですね。

- ## プログラム環境
ArduinoIDE バージョン：2.3.2
Adafruit NeoPixel Library 1.12.2

- ## ハードウェアの主な仕様
　①マイコン:PR2040-ZERO（RaspberryPiPico系）
　②NeoPixel接続ピン　 GPI08（R1でショート）
　③プッシュスイッチ１：GPI07
　④プッシュスイッチ２：GPI06（2個搭載しているボードのみ）
　⑤音声入力：GP26

 - ## メインプログラム（ArduinoIDEのスケッチ）
AD入力信号をADコンバータで値を取得して
NeoPixelをレベルによって光らせるサンプルプログラムです。

```c++
// ADコンバータ入力とLED制御

#include <Adafruit_NeoPixel.h>

// NeoPixelの設定
#define PIN 8 // NeoPixelのデータピン
#define NUMPIXELS 36 // NeoPixelのLED数
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); // NeoPixelオブジェクトの作成

// ADコンバータ入力ピン
#define ADC_PIN 26 // ADコンバータの入力ピン

void setup() {
  // シリアルモニタの初期化
  Serial.begin(115200);
  // NeoPixelの初期化
  pixels.begin();
  pixels.setBrightness(24); // 明るさを24に設定
  // ADC_PINを入力モードに設定
  pinMode(ADC_PIN, INPUT);
  analogReadResolution(12); // ADコンバータの解像度を12ビットに設定
}

void loop() {
  // ADコンバータの値を読み取る
  int adcValue = analogRead(ADC_PIN);
  // シリアルモニタに表示
  Serial.println(adcValue);

  // NeoPixelの制御
  if (adcValue < 2560) {
    // 全てのLEDを消灯
    pixels.clear();
  } else if (adcValue <= 3072) {
    // 14, 15, 20, 21を青色に点灯
    setPixelsColorRange({14, 15, 20, 21}, pixels.Color(0, 0, 255));
  } else if (adcValue <= 3584) {
    // 14, 15, 20, 21を青色に点灯
    setPixelsColorRange({14, 15, 20, 21}, pixels.Color(0, 0, 255));
    // 7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28を緑色に点灯
    setPixelsColorRange({7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}, pixels.Color(0, 255, 0));
  } else {
    // 14, 15, 20, 21を青色に点灯
    setPixelsColorRange({14, 15, 20, 21}, pixels.Color(0, 0, 255));
    // 7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28を緑色に点灯
    setPixelsColorRange({7, 8, 9, 10, 13, 16, 19, 22, 25, 26, 27, 28}, pixels.Color(0, 255, 0));
    // 0, 1, 2, 3, 4, 5, 6, 11, 12, 17, 18, 23, 24, 29, 30, 31, 32, 33, 34, 35を赤色に点灯
    setPixelsColorRange({0, 1, 2, 3, 4, 5, 6, 11, 12, 17, 18, 23, 24, 29, 30, 31, 32, 33, 34, 35}, pixels.Color(255, 0, 0));
  }

  // NeoPixelの更新
  pixels.show();
  delay(20); // サンプリング間隔を20ミリ秒に設定
}

// 複数のピクセルを同じ色に設定する関数
void setPixelsColorRange(const std::vector<int>& indices, uint32_t color) {
  for (int index : indices) {
    pixels.setPixelColor(index, color);
  }
}

```

ADコンバータの解像度を12bitに初期設定をして、0から4095でアナログ値を取得するようにしています。
arduinoUNOは、確か10bitでしたのでこの関数は使用するマイコンを選びそうですね。

```c++
  // ADC_PINを入力モードに設定
  pinMode(ADC_PIN, INPUT);
  analogReadResolution(12); // ADコンバータの解像度を12ビットに設定
```

AD変換の結果はシリアルモニタで見ることが可能ですが、
横軸を任意に調整できないのでざっくり確認ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/8dabc9a6-cffd-e1be-f981-9970e4969620.png)

入力にSin波を入力した場合です。
中点は2048付近の信号ということが分かりますね。
振幅は0から4095ぐらいがADコンバータの変換できる範囲になりますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/725b57b6-bbef-c016-ad47-28e4c8dbc003.png)
入力に三角波を入れてみました。
トップとボトムでサンプリングのタイミングが合わないとこんな感じになってしまうようです。
この辺りは、ADコンバータの取り込み間隔とLEDの更新間隔をバランスが効くようです。
LED表示更新を100msecにするとADコンバータの取り込み間隔が伸びてしまい
更新間隔を短くするとLEDが激しく点滅してしまう感じです。
なるべくADコンバータは取り込み続けてLED表示更新間隔を広げる処理に
しないとLED更新が早過ぎて目がちかちかし過ぎてしまいました。

- ## LEDの色設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782127/08de6834-565d-6685-a169-419a3eedd3dc.png)

ADコンバータ結果
　2560未満　LED全部消灯。
　3072以下　青色の中央4つ点灯
  3584以下　緑色で周囲を点灯
  それ以上　赤色で最外周を点灯

という設定にしています。

入力信号の振幅が小さい場合は、
　ADコンバータの値を調整することで音声の大きさでLEDを光らせることができるようになります。

 サンプルプログラムの完成度が低くて申し訳ありません。
 今回のサンプルプログラムでADコンバータの値取り込み値からNeoPixelに
 音声信号の大きさに合わせて光らせる流れが確認できると思いますので参考にしてみてください。

 電脳好奇心　うたたねこ