今回はLED照明テープをマイコンで好きなように点灯させる方法です。LED照明テープとは、RGB LEDがテープにならべられた装飾用の照明です。
名前はRGBテープ照明とかカラーLEDテープライトとか色々な呼称があるようで、電源とコントローラ装置がついているセットが多く販売されているようです。
今回はこのテープをArduino-IDEを使って好きなように動かそうというわけです。
必要な長さに切って使うことができるので、余りが出ます。手元にある余りは次の写真で、それぞれ半端な長さです。
この照明テープは次の写真のように、3つのLEDが1単位で自由に切って使えます。つまり、LED3つずつが1ユニットになっており、各ユニットが1つのIC (WS2811)でコントロールされています。電源はLED3つを直列に設定しているようで12Vと書いてあります。
3つ並んだ銅メッキの端子ランドの位置で、ハサミで自由にカットできます。
コントロールICの電源はその12Vから内部でレギュレータを通して供給されているようです。入り口に電源供給ワイヤが余分についていたりするためDIYで扱うときは気を付けないといけませんね。これをマイコン電源につないでこわさないよう。
電源はLEDとコントロールICの両方に使う用途ですが、原理から見れば12Vでなくて9V供給でも大丈夫そうですね。LEDは非常に明るい(眩し過ぎる)LEDですし。
少し新しい型では、LED3つずつの単位ではなく、1つずつ自由にコントロールできるものがあります。この場合はLED電源とIC(WS2812B)は共通の5V供給となっています。次の写真ですが、ICとLEDとが一体になっています。
さらに、WS2813になると途中のICが壊れてもそこから先のICに信号が伝わるように工夫されています。長いテープの途中では電圧降下が起きるため電源の追加供給が必要となりますが、最近のWS2815では12V電源にすることで追加供給が不要にされています。
どれも、制御するためのデータは「1ワイヤプロトコル(1線式プロトコル)」で送信します。1線式といってもCRC(巡回冗長検査符合)などはなく、RGBの明るさ(デューティ比)を255までの数値で3つ並べた3バイトを順次送信するという簡単なものです。
ここで使ったものは1ICあたり3バイトをBRGの順に送ります。ICのユニット数分だけ、バイト間をあけずに一気に送り込む必要があります。つまりICが10個並んでいる場合は30バイトを切れ目なく送るわけです。すると照明の状態がその並びの通りにセットされて維持されます。変更するときは、リセット信号(単に50μS以上のオフ)を出して、再び新しい並び順に送ればよいわけです。
ところが、
LEDテープの1ワイヤプロトコルはタイミングの制約が厳しく、遅いマイコンでやるのは難しいのです。
1ビットがHとLの組み合わせで、Hが長くLが短いのが1、逆が0です。それを1.25μS周期で送らないといけません。ビット表示の間を全くあけられませんから、遅いマイコンの場合は処理が到底間に合いません。
なぜ16MHzのArduino-Unoで動くかと言えば、ライブラリー(上の例で使っているのはFastLEDライブラリ)がハードウェア端子を直接操作しているからです。こういうライブラリーを使わない限りは、普通のC(Arduino)言語では無理です。
16MHzのPICをアセンブラーでどうかといえば、できそうですが簡単ではありませんね。PORTのビットをオンオフするには間に2サイクル取らないといけませんから、それだけで0.5μSかかってしまいます。1サイクルにするためにはPORTレジスタでなくLATレジスタを操作しなければなりませんが、それにはメモリーバンク番号を通常ではない設定のまま動かすことに。さらに信号間の処理ができないわけで・・・これじゃ普通は堪りませんね^^;
ですがライブラリーのインターフェイスに縛られず、Arduino-IDEで好きなように使いたいと考える人は多い事でしょうね。LEDテープは飾りや照明でなく、色々な表示に応用が利きそうですからね。
そこで、
Arduino-IDEで気軽に作るには、速いマイコンを使うに限ります。ここでは手持ちのTeensy4.0を使います。ある程度速ければそこまでの速度がなくともOKですが。
処理能力比較は例えば前に次の記事に書きましたが、ここでは1CPUあたりの速度で考える必要がありますね。
https://a-tomi.hatenablog.com/entry/2021/03/19/225327
さて、Arduino言語にタイミングをとるためのdelayMicrosecondsはあっても、delayNanosecondsがまだない^^; というわけで、LEDテープで好き勝手をするような自作例が見当たらないわけでしょうね。そこをどうするかさえ勝手に考えればArduino-IDEで楽勝となりそう!
まずは、切りっ放しのテープの端子にワイヤーをつなぎます。この余りテープには30個のLED、つまり10ユニットが並んでいます、右のほうに。
12V端子へオレンジ、Dinと記された端子へ黄色、そしてGnd端子に黒2本をはんだ付けし、接続部全体を透明熱収縮チューブで保護しました。LED電源としてオレンジと黒の間に9VDCを供給します。そこに念のために100μFを並列に入れてあります。
そして、Teensy4.0で、デジタル14ピンに信号を出すようにします。次の写真のように。
テストプログラムは次のように作りました。9ユニット分にそれぞれ別の色を出し、10番目のユニットには送りません(光らせない)。
/**************************************************
* LED-Tape test V.00 *
* 1st version 6/30,2021(c)Akira Tominaga *
* Remarks: *
* WS281X IC on the tape *
**************************************************/
#define Out 14 // output pin d14
// *** color definitions
#define Blue (128,0,0)
#define Red (0,128,0)
#define Green (0,0,128)
#define Purple (62,66,0)
#define Yellow (0,64,64)
#define Orange (0,100,32)
#define BlueGreen (64,0,64)
#define BluePurple (88,40,0)
#define White (43,43,43)
#define Black (0,0,0)
//
uint8_t colorD[3]; // 3 values for BRG
byte Byte; // working byte
void setup() { // ***** Teensy setup() *****
pinMode(Out, OUTPUT);
digitalWrite(Out, LOW);
delay(3000); // time to stabilize pwr
Rst(); // reset LED controller
sendColor Red; // unit 1
sendColor Orange; // unit 2
sendColor Yellow; // unit 3
sendColor Green; // unit 4
sendColor BlueGreen; // unit 5
sendColor Blue; // unit 6
sendColor BluePurple; // unit 7
sendColor Purple; // unit 8
sendColor White; // unit 9
// *** add more units if required
Rst(); // reset LED-controller
while (true) {} // stop w/ keeping lights
}
void loop() { // ***** Teensy loop() ***** unused
}
/************************************************
* User defined functions *
* **********************************************/
// ***** Send Color *** sendColor(blue,red,green) *****
void sendColor(byte b, byte r, byte g) {
Byte = b;
sendByte();
Byte = r;
sendByte();
Byte = g;
sendByte();
}
// ***** send Byte *** sendByte() *****
void sendByte(void) {
for (int k = 0; k < 8; k++) {
if (Byte &(B10000000>>k)) {
One();
} else {
Zero();
}
}
}
// ***** send a bit 0 *** Zero() *****
void Zero(void) {
digitalWrite(Out, HIGH);
shortDelay();
digitalWrite(Out, LOW);
delayMicroseconds(1);
}
// ***** send a bit 1 *** One *****
void One(void) {
digitalWrite(Out, HIGH);
delayMicroseconds(1);
digitalWrite(Out, LOW);
shortDelay();
}
// ***** delay about 0.25μS *** shortDelay() *****
// Adjust this, on your micro-controller speed
void shortDelay(void) {
for (uint8_t m = 0; m < 20; m++) {
delayMicroseconds(0);
}
}
// ***** Reset LED controller *** Rst() *****
void Rst(void) {
digitalWrite(Out, LOW);
delayMicroseconds(100);
}
// end of program
ライブラリーは何も使いませんが、かなり単純にできますね。いきなり実際のテストはせず、まずは動かして出力信号のタイミングをオシロで確認します。
点灯したいユニットの数だけsendColorを並べるだけですし、残りのユニットは点灯しません。実際の数より多くの信号を送った場合は、存在するユニット数だけが点灯します。
1を送る際は オン1μS+オフ0.25μS とし、0を送る際は
オン0.25μS+オフ1μS としました。
0.25μSを作るには、本当はdelyNanoseconds(250)とか、delayMicroseconds(0.25)とか書きたいわけなのですが、そんなことできませんね。ここではdelayMicroseconds(0)として、呼び出しのオーバーヘッド時間を使うことにしました。
オシロで見ながらぴったりになるように調整した結果、Teensy4.0の場合は空呼び出しを20回程度すればちょうどよいのですが、他の高速マイコンを使う場合は、速度に応じてshortDelay(関数内にあるこの回数を調整してください。
さてこうしてから動かしますと、問題なく意図通りに動きます!LEDが明るすぎるので、全体に色の数値を下げた状態が上のスケッチですが、それ以外は問題はないようです。これなら簡単に好きなようにプログラムをすることができますね。RGBの値を変数にしたりしてやりたい放題が^^
おお!これでカラーLEDテープ照明が自由自在だ!
ところがですよ、とても明るくきれいに光っているLEDテープをうまく写真に撮るのは結構難しい。露出を数段下げたぐらいじゃ色がリアルにでない。照明用LEDなので明るすぎますからね。次の写真の下段のように、ピントをわざと外すとようやくリアルに近い色が表現されます^^.
では今回はこのへんで。
LEDテープをDIYで好き勝手に動かしたい方のお役にたてば幸いです。
©2021 Akira Tominaga, All rights reserved.