フルカラーシリアルLED WS2812B を使った8x8RGB LEDパネルを8pinの32ビットマイコンSTM32C011J4M7につないでみました。
シリアル接続で使う信号線は1本だけなので,8pinの小さなマイコンにはぴったりです(^^)。
データ出力のタイミングをSTM32C011に合わせて,動かしてみたところです。
このパネルはかなり明るく光って目が疲れるので,光量は絞っています(^^;;;。
[ハード構成と配線]
・MPU:STM32C011JYM7 8pin
・8x8 RGB LED PANEL,WS2812B
配線はとても簡単ですが,LEDパネルは5V,MPUは3.3Vの別電源が必要です。
GNDも忘れずにお互いを繋いでおきます(^^;;;。
信号線(DIN)はLEDのロジック部が3.3Vも受けられるので直結しています。
[WS2812Bを使うソフトの概要]
フルカラーシリアルLED WS2812Bは1個の内にRGB3個のLEDを持ち,RGBそれぞれに光量を調節する1byteの記憶領域を持っていて,その記憶領域はこの型番ではGRBの順に数珠繋ぎになっています。
今回使ったパネルはそのLED64個を数珠繋ぎにしているので,64x3byteつまり64x3x8bitをシリアルに送って光らせます。
1) シリアル通信の様式
WS2812Bのシリアル通信は1bitをだいたい800KHz間隔で送る方式です。1bitあたりの時間( 1/800Kで1.25us)の中でHighのパルスの時間が長ければ"1", 短めなら"0"のbitである,という表現方法です。
私は何となくモールス信号みたいなものかと思っています(^^)。
"ツー,ツ ,ツ ,ツー" が "1 0 0 1"である,,という感じですかね。
この信号を次から次へと連続して一気に送ります。
そのタイミングの規格です。
[参考および引用] (ここはとても丁寧で親切な解説です(^^))
・赤・緑・青のフルカラーLED WS2812Bの使い方(マルツ)
2) bitを表現するパルスの作成
上図の数値を見ていると,ナノ秒の世界ではありますが案外ゆるい規格だというのが分かります(^^;;;
ポイントはパルスの長さで,380nsから580nsの間やその付近の値を避けて,パルスの長短をはっきりさせておくとそうは細かいことは気にしないで良いと思っています。
今回はArduinoでSTM32C011でも使えるdigitalWriteFast()で規格に近い,それらしいパルスを作ってみました。
ロジアナで出力を見ながら調整して作ってみたパルス発生部です。
なお,forループが二重になっているのは,なぜかループ回数が8回を越すとdigitalWriteFast()の?挙動がおかしくなるのでそれを避けたからです。
どうしてでしょうかねぇ,,何か間違っているのか,,,。
下図は上記のプログラムで出力されているパルス波形です。
だいたいですが,,以下の値ぐらいのパルスが出ています。
0:High 350ns, Low 1050ns
1:High 680ns, Low 670ns
パルスが出せれば,こちらのものです(^^)。
何の工夫もないチェックプログラムですが一応メモしておきます。
そういえばシリアル送信時には割り込みをストップしておかないとちらつきが入る機種があったので,そのままにしていますが,必要かどうかは確認してないですね(^^;;;;。
ま,それよりもいろいろなLEDパネルをもっと面白く使えるように自分なりにツールを工夫していきたいですね。
シリアル接続で使う信号線は1本だけなので,8pinの小さなマイコンにはぴったりです(^^)。
データ出力のタイミングをSTM32C011に合わせて,動かしてみたところです。
このパネルはかなり明るく光って目が疲れるので,光量は絞っています(^^;;;。
[ハード構成と配線]
・MPU:STM32C011JYM7 8pin
・8x8 RGB LED PANEL,WS2812B
配線はとても簡単ですが,LEDパネルは5V,MPUは3.3Vの別電源が必要です。
GNDも忘れずにお互いを繋いでおきます(^^;;;。
信号線(DIN)はLEDのロジック部が3.3Vも受けられるので直結しています。
[WS2812Bを使うソフトの概要]
フルカラーシリアルLED WS2812Bは1個の内にRGB3個のLEDを持ち,RGBそれぞれに光量を調節する1byteの記憶領域を持っていて,その記憶領域はこの型番ではGRBの順に数珠繋ぎになっています。
今回使ったパネルはそのLED64個を数珠繋ぎにしているので,64x3byteつまり64x3x8bitをシリアルに送って光らせます。
1) シリアル通信の様式
WS2812Bのシリアル通信は1bitをだいたい800KHz間隔で送る方式です。1bitあたりの時間( 1/800Kで1.25us)の中でHighのパルスの時間が長ければ"1", 短めなら"0"のbitである,という表現方法です。
私は何となくモールス信号みたいなものかと思っています(^^)。
"ツー,ツ ,ツ ,ツー" が "1 0 0 1"である,,という感じですかね。
この信号を次から次へと連続して一気に送ります。
そのタイミングの規格です。
[参考および引用] (ここはとても丁寧で親切な解説です(^^))
・赤・緑・青のフルカラーLED WS2812Bの使い方(マルツ)
2) bitを表現するパルスの作成
上図の数値を見ていると,ナノ秒の世界ではありますが案外ゆるい規格だというのが分かります(^^;;;
ポイントはパルスの長さで,380nsから580nsの間やその付近の値を避けて,パルスの長短をはっきりさせておくとそうは細かいことは気にしないで良いと思っています。
今回はArduinoでSTM32C011でも使えるdigitalWriteFast()で規格に近い,それらしいパルスを作ってみました。
ロジアナで出力を見ながら調整して作ってみたパルス発生部です。
なお,forループが二重になっているのは,なぜかループ回数が8回を越すとdigitalWriteFast()の?挙動がおかしくなるのでそれを避けたからです。
どうしてでしょうかねぇ,,何か間違っているのか,,,。
if ((a & 0x80) >0){ // if bit=1
for (int i=0; i<3; i++){ // HIGH_long
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, HIGH);
}
}
for (int i=0; i<2; i++){ // LOW_short
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, LOW);
}
}
}else{ // if bit=0
for (int i=0; i<2; i++){ // HIGH_short
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, HIGH);
}
}
for (int i=0; i<3; i++){
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, LOW); // LOW_long
}
}
}
下図は上記のプログラムで出力されているパルス波形です。
だいたいですが,,以下の値ぐらいのパルスが出ています。
0:High 350ns, Low 1050ns
1:High 680ns, Low 670ns
パルスが出せれば,こちらのものです(^^)。
何の工夫もないチェックプログラムですが一応メモしておきます。
// STM32C011 NeoPixel Control Test_2
// Number of GRB_LED: 64
const unsigned int lednumber_max = 64;
const byte c_order[]={1,0,2}; // send G-R-B
byte aData[lednumber_max][3]; // number of LED * RGB(3) byte
unsigned int lednumber = lednumber_max ; // Init. lednumber
void setup() {
pinMode(PA8, OUTPUT);
byte r,g,b; // LED All Clear
r=0;g=0;b=0; allset(r,g,b); sendData(); delay(500);
}
void loop(){
byte r,g,b;
int waitms=2000;
lednumber=lednumber_max;
r=0x3F;g=0x00;b=0x00; allset(r,g,b); sendData(); delay(waitms); // R
r=0x00;g=0x3F;b=0x00; allset(r,g,b); sendData(); delay(waitms); // G
r=0x00;g=0x00;b=0x3F; allset(r,g,b); sendData(); delay(waitms); // B
r=0x3F;g=0x3F;b=0x00; allset(r,g,b); sendData(); delay(waitms); // R+G
r=0x3F;g=0x00;b=0x3F; allset(r,g,b); sendData(); delay(waitms); // R+B
r=0x00;g=0x3F;b=0x3F; allset(r,g,b); sendData(); delay(waitms); // G+B
r=0x3F;g=0x3F;b=0x3F; allset(r,g,b); sendData(); delay(waitms); // R+G+B
lednumber=lednumber_max;
for (byte i=0;i<lednumber;i++){ // R,G,B,R+G,R+B,G+B,R+G+B
byte j=i%7;
if (j==0){r=0x3F;g=0x00;b=0x00;} //R
else if (j==1){r=0x00;g=0x3F;b=0x00;} //G
else if (j==2){r=0x00;g=0x00;b=0x3F;} //B
else if (j==3){r=0x3F;g=0x3F;b=0x00;} //R+G
else if (j==4){r=0x3F;g=0x00;b=0x3F;} //R+B
else if (j==5){r=0x00;g=0x3F;b=0x3F;} //G+B
else if (j==6){r=0x3F;g=0x3F;b=0x3F;} //R+G+B
aData[i][0]=r;
aData[i][1]=g;
aData[i][2]=b;
}
sendData();
delay(waitms);
}
void allset (byte r,byte g,byte b){
for (byte i=0;i<lednumber_max;i++){ //make all leds the same color
aData[i][0]=r;
aData[i][1]=g;
aData[i][2]=b;
}
}
void sendData(){
noInterrupts();
for (int numLed=0; numLed<lednumber_max; numLed++){ // LED
for (byte rgbLed=0; rgbLed <3; rgbLed++){ // G-R-B
byte a=aData[numLed][c_order[rgbLed]]; // set 1byte
for (byte i=0; i<8; i++){ // loop bit:7---0
if ((a & 0x80) >0){ // **** if bit=1 ****
for (int i=0; i<3; i++){ // HIGH_long
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, HIGH);
}
}
for (int i=0; i<2; i++){ // LOW_short
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, LOW);
}
}
}else{ // **** if bit=0 ****
for (int i=0; i<2; i++){ // HIGH_short
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, HIGH);
}
}
for (int i=0; i<3; i++){
for (int j=0; j<8; j++){
digitalWriteFast(PA_8, LOW); // LOW _long
}
}
}
a=a*2; // set bit7
} // next bit
} // next byte(R-G-B)
} // next LED
interrupts();
}
そういえばシリアル送信時には割り込みをストップしておかないとちらつきが入る機種があったので,そのままにしていますが,必要かどうかは確認してないですね(^^;;;;。
ま,それよりもいろいろなLEDパネルをもっと面白く使えるように自分なりにツールを工夫していきたいですね。