スイッチサイエンスにフルカラーシリアルLEDがあったので試しに購入。簡単に点くかと思ったら意外とタイミングが厳しく、8MHz動作のAVRの場合割り込み禁止してアセンブラでクロック数を数えながら無駄なく書かないとうまく点きませんでした。
写真は明るいキッチンカウンターの上でとっていますが、LEDが強すぎてLED以外の部分が真っ暗になってしまってうまく撮れなかったので見た目に合わせて色補正かけています。実際に見るとかなり眩しいです。
このLEDは1m60個のフルカラーLEDで、今回は半分に切って50cm30個で使っています。
本当は1灯ずつフルカラーで色を指定できるのですが、実際に使うとなると全体を同じ色で光らせれば十分なのでLEDの個数とR,G,Bを指定してPORTC4につないだシリアルLED を光らせる関数を作りました。
この関数を呼ぶと30us x LEDの個数分割り込み禁止になります。
1m品の場合60個なので1.8msの間blockされます。UARTでフロー制御していない場合、AVRはFIFOが1段しかないので4800bps以下に設定しないと通信を取りこぼします。
HA2moduleで接続しているので、XBeeを4800bpsで接続してコントロールサーバー経由で制御するようにしています。
void SetLED(unsigned char count, unsigned char r, unsigned char g, unsigned char b) {
asm volatile(
" in __tmp_reg__,__SREG__ \n" // interrupt block 30us x count
" cli \n"
" in r6, %[port] \n"
" or r6, %[tmp] \n"
" mov r5, r6 \n"
" eor r5, %[tmp] \n"
" mov r2, %[byteg] \n"
"loop: \n"
" ldi %[tmp], 8 \n" // 1
"loopg: \n"
" out %[port], r5 \n" // 1
" nop \n" // 1
" sbrs r2, 7 \n" // 1 - 2
" out %[port], r6 \n" // 1
" lsl r2 \n" // 1
" mov r3, %[byter] \n" // 1
" dec %[tmp] \n" // 1
" out %[port], r6 \n" // 1
" brne loopg \n" // 2
" \n"
" ldi %[tmp], 8 \n" // 1
"loopr: \n"
" out %[port], r5 \n" // 1
" nop \n" // 1
" sbrs r3, 7 \n" // 1 - 2
" out %[port], r6 \n" // 1
" lsl r3 \n" // 1
" mov r4 , %[byteb] \n" // 1
" dec %[tmp] \n" // 1
" out %[port], r6 \n" // 1
" brne loopr \n" // 2
" \n"
" ldi %[tmp], 8 \n" // 1
"loopb: \n"
" out %[port], r5 \n" // 1
" nop \n" // 1
" sbrs r4, 7 \n" // 1 - 2
" out %[port], r6 \n" // 1
" lsl r4 \n" // 1
" mov r2, %[byteg] \n" // 1
" dec %[tmp] \n" // 1
" out %[port], r6 \n" // 1
" brne loopb \n" // 2
" dec %[count] \n" // 1
" brne loop \n" // 2
" out __SREG__,__tmp_reg__\n"
:
: [count] "r" (count),
[byter] "r" (r),
[byteg] "r" (g),
[byteb] "r" (b),
[tmp] "r" ((1 << PORTC4)),
[port] "I" (_SFR_IO_ADDR(PORTC))
: "r0", "r2", "r3", "r4", "r5", "r6");
}
0 件のコメント:
コメントを投稿