クリスマスシーズンなので??、ArduinoとLEDで楽しい工作。
☆使ったもの
・ブレッドボード EIC-102B
・Arduino-Nano
・トランジスタアレイ TD62083AP6
・バッテリー式LEDライト(20球)×2セット
・マイコン内蔵RGB 8mmLED PL9823-F8×7個
・カーボン抵抗1/4W-100Ω×7本
・セラミックコンデンサ0.1μF×7本
・ジャンパワイヤ適宜
ホームセンターで乾電池を使って動作させるクリスマスイルミネーションを見かけた。
恐らくLEDを並列に繋いでいる適当な代物だが、遊ぶのには良い感じ!?
まず、電池ボックスから出ているワイヤーを切断し、抵抗を繋ぎ直す。
流れる電流を計ると100mAぐらいあるので、Arduinoに直差しは出来ません。
PWM出力をトランジスタアレイで受け、LEDをドライブすることにしました。
Arduinoは三角関数が使えるので、スケッチはとても簡単。
0~255の波を作り、0になる度に周期を再設定しています。
市販品のLEDイルミネーションと違って「ホワ~~~ッ」とした点滅を繰り返すので、とても良い感じです♪
周期と明るさをもう少し細かく制御すればもっと良いかもしれません。
PL9823制御のルーチンはサンプルスケッチのままだと、別系統のLEDワイヤの制御がしづらいので新規作成。
ブレッドボードの制約で7個しか繋げていませんが、電源さえ気をつければかなりの個数をドライブできるようです。
RBGの各出力はこんな感じ。
試行錯誤をしながらスケッチを描き上げました。
完成♪
右下のデジタル表示は電圧/電流です。
2種類のスケッチを作り、組み合わせて一本にしてあります。
PL9823制御部分のスケッチ
#include <Adafruit_NeoPixel.h> #define strand_Pin 6 #define strand_Pixels 7 // Parameter 1 = number of pixels in strip // Parameter 2 = Arduino pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel strip = Adafruit_NeoPixel(strand_Pixels, strand_Pin, NEO_RGB + NEO_KHZ800); const float pi = 3.14; // π unsigned long current_time; // 現在時間 unsigned long strand_time; // ストランド配色変更時間 int led_data[3]; // 0:R, 1:G 2:B double limit; int strand_pos = 0; int strand_interval = 360 / strand_Pixels; void setup() { // Serial.begin(9600); strip.begin(); strip.show(); // Initialize all pixels to 'off' limit = cos(pi * 2 / 3) + 1; } void loop() { current_time = millis(); // 現在時間を保存 if(strand_time < current_time) { // 時間になったら・・・ for(int i=0; i<strand_Pixels; i++) { // 各ピクセルのRGB値を設定 for(int j = 0; j < 3; j++) { // 0:R, 1:G 2:B led_data[j] = constrain((cos((pi * 2 * ((strand_interval * i) + strand_pos)/360) - (pi * j * 2 / 3)) + 1 - limit) * 171, 0, 255); } strip.setPixelColor(i, led_data[0], led_data[1], led_data[2]); if(++strand_pos >= 360) strand_pos = 0; } // Serial.print(led_data[0]); // Serial.print(",\t"); // Serial.print(led_data[1]); // Serial.print(",\t"); // Serial.println(led_data[2]); strip.show(); // ピクセルデータ転送 strand_time += 50; // 次の処理は50ms後 } }
ワイヤ制御部分のスケッチ
const int LED_WIRE = 2; // LEDワイヤの本数 const int ledPin[LED_WIRE] = { 9, 10 }; // LEDはピン9と10に接続 const float pi = 3.14; // π int brightness; // 輝度 0-255 int counter[LED_WIRE]; // カウンタ 0-250 で一周期 unsigned long current_time; // 現在時間 unsigned long next_time[LED_WIRE]; // 次の輝度変更時間 unsigned long interval[LED_WIRE]; // 輝度を変更する間隔(4-40mSec) void setup() { randomSeed(analogRead(0)); // 未接続ピンのノイズを利用して乱数を初期化 for(int i = 0; i < LED_WIRE; i++) { //ワイヤの本数分繰り返す counter[i] = 0; // カウンタをクリア interval[i] = random(4, 40); // 輝度を変更する間隔(4-40mSec) } } void loop() { current_time = millis(); // 現在時間を保存 // 各ワイヤの処理「0%~100%~0%」を間隔4ms~40ms、回数250回で輝度変更、1周期終えると間隔を再設定 for(int i = 0; i < LED_WIRE; i++) { // LEDワイヤの本数分繰り返す if(next_time[i] < current_time) { // 該当ワイヤの輝度変更時間が来たら brightness = constrain(int(128 - cos((counter[i] * 2 * pi)/ 250) * 128),0,255); // 輝度を計算(0~255で制限) analogWrite(ledPin[i], brightness); // 該当ワイヤのピンにアナログ出力 if( ++counter[i] >= 250) { // 1周期終えたら counter[i] = 0; // カウンタをクリア interval[i] = random(4, 40); // 間隔を4ms~40msの間で再設定 } next_time[i] = current_time + interval[i]; // 次の輝度変更時間を設定 } } }