AVRでLEDホタル(3)の続きです。
秋月のフルカラーLEDを複数点灯しています。
ATMega88のPWM出力は最大6個なので、全部をPWMにつなげるわけにはいきません(RGBx4 = 12)。ダイナミック点灯で、左をちょっと光らせて、一つ右に移ってを繰り返しています。
このLEDはカソードコモンなのでNPNのトランジスタ(2SC1815)をカソード側につないで、点けるか消すかを制御しています。アノード側はPWMの出力を4つのLEDに分配しています。緑の配線がそれなんですが、痛々しいくらい高密度配線です。
携帯のカメラを一番暗くしてみました。
ソースコードです。
PWMの初期化は毎回同じなので、次からは省略できるようにサブルーチンにしました。LEDの左から順にPC3, PC2, PC1, PC0につながっています。PC3に1を書くと一番左が点灯します。
ダイナミック点灯は結構高い周波数で切り替えないとちらつきます。今回は4ミリ秒毎に切り替えているので250Hzです。
本来ならダイナミック点灯の切り替えは割り込みを使ってやるぺきですが、割り込みの使い方を分かっていません。
今回わかったこととしては、LED毎に明るさのばらつきが微妙にあることです。同じ色を出しているつもりでも、4つが各々微妙にちがったりします。もうひとつはRGBでも明るさのカーブが違うことです。明るいときはうまくバランスしてても暗めにすると青みがかったりします。完璧を目指すならLED一つ一つについて、PWMのパラメータを変えたりしないといけないでしょうが、とても大変そうです。
とりあえずタイマー1が空いているので、次は割り込みに挑戦してみたいと思っています。
秋月のフルカラーLEDを複数点灯しています。
ATMega88のPWM出力は最大6個なので、全部をPWMにつなげるわけにはいきません(RGBx4 = 12)。ダイナミック点灯で、左をちょっと光らせて、一つ右に移ってを繰り返しています。
このLEDはカソードコモンなのでNPNのトランジスタ(2SC1815)をカソード側につないで、点けるか消すかを制御しています。アノード側はPWMの出力を4つのLEDに分配しています。緑の配線がそれなんですが、痛々しいくらい高密度配線です。
携帯のカメラを一番暗くしてみました。
ソースコードです。
#include <avr/io.h> #include <util/delay.h> typedef unsigned char byte; void pwminit(void) { // MEGA88 タイマー関連ポート // OC0A/PD6 12pin 赤 // OC0B/PD5 11pin 緑 // OC1A/PB1 15pin // OC1B/PB2 16pin // OC2A/PB3 17pin ... MOSI // OC2B/PD3 5pin 青 // 76543210 DDRD |= 0b01101000; // PD6(12), PD5(11), PD3(5) 出力 // 14.9.1 タイマ/カウンタ0制御レジスタA (p.64) // ++--------COM0A1:COM0A0 10 上昇時一致でL下降時一致でH // ||++------COM0B1:COM0B0 10 上昇時一致でL下降時一致でH // |||| ++--WGM01:WGM00 01 位相基準PWM動作 TCCR0A = 0b10100001; // 17.11.1 タイマ/カウンタ2制御レジスタA (p.99) // ++--------COM2A1:COM2A0 10 OCR2A停止 // ||++------COM2B1:COM2B0 00 上昇時一致でL下降時一致でH // |||| ++--WGM21:WGM20 01 位相基準PWM動作 TCCR2A = 0b00100001; // 14.9.2 タイマ/カウンタ0制御レジスタB (p.65) // ++--------FOC0A:FOC0B 00 // || +-----WGM2 0 TOP = 0xff // || |+++--CS02:CS01:CS00 001 clkio/1 TCCR0B = 0b00000001; // start timer // 17.11.2 タイマ/カウンタ0制御レジスタB (p.100) // ++--------FOC2A:FOC2B 00 // || +-----WGM22 0 TOP = 0xff // || |+++--CS22:CS21:CS20 001 clkio/1 TCCR2B = 0b00000001; // start timer } int main() { byte led[4][3] = { {0x80, 0x00, 0x00}, // PC3のR, G, B {0x00, 0x80, 0x00}, // PC2のR, G, B {0x00, 0x00, 0x80}, // PC1のR, G, B {0x80, 0x80, 0x00}, // PC0のR, G, B }; byte p = 0; pwminit(); // 76543210 DDRC = 0b00001111; // PC3(26), PC2(25), PC1(24), PC0(23) 出力 while(1){ _delay_ms(4); // 4ミリ秒 250Hz PORTC = 0; OCR0A = led[p][0]; // duty比設定 赤 OCR0B = led[p][1]; // duty比設定 緑 OCR2B = led[p][2]; // duty比設定 青 PORTC = 8 >> p; p = (p + 1) & 3; // p = 0~3の繰り返し } }
PWMの初期化は毎回同じなので、次からは省略できるようにサブルーチンにしました。LEDの左から順にPC3, PC2, PC1, PC0につながっています。PC3に1を書くと一番左が点灯します。
ダイナミック点灯は結構高い周波数で切り替えないとちらつきます。今回は4ミリ秒毎に切り替えているので250Hzです。
本来ならダイナミック点灯の切り替えは割り込みを使ってやるぺきですが、割り込みの使い方を分かっていません。
今回わかったこととしては、LED毎に明るさのばらつきが微妙にあることです。同じ色を出しているつもりでも、4つが各々微妙にちがったりします。もうひとつはRGBでも明るさのカーブが違うことです。明るいときはうまくバランスしてても暗めにすると青みがかったりします。完璧を目指すならLED一つ一つについて、PWMのパラメータを変えたりしないといけないでしょうが、とても大変そうです。
とりあえずタイマー1が空いているので、次は割り込みに挑戦してみたいと思っています。
ばらつきが観測されたLEDを相互に交換して比べると、LEDが原因かその他の原因かがわかります。
なるほど、手っ取りばやいですね。試してみたところ、1個薄いのがいました。気にするほど違うというわけではないのでそのままにしてます。
せっかくソフトで明るさを変えれるようにしてるので校正もソフトでやっちゃうのが筋なんでしょうね。フルカラーLEDの場合、フィラメントというか光るものが配置されている場所もRGBで微妙に異なっているので、見る角度でも微妙に色が変わって見えたりします。気にしだすときりがないという感じです。