Sim's blog

電子工作はじめてみました

AVRでLEDダイナミック点灯

2008-09-19 01:09:41 | AVR
AVRでLEDホタル(3)の続きです。

秋月のフルカラー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が空いているので、次は割り込みに挑戦してみたいと思っています。


最新の画像もっと見る

2 コメント

コメント日が  古い順  |   新しい順
LED毎に明るさのばらつき (のりたん)
2008-09-19 05:58:10
LED毎に明るさのばらつきがあるとの事ですが、本当にLEDのせいでしょうか?

ばらつきが観測されたLEDを相互に交換して比べると、LEDが原因かその他の原因かがわかります。
re:LED毎に明るさのばらつき (Sim)
2008-09-19 08:48:12
こんにちは、のりたんさん
なるほど、手っ取りばやいですね。試してみたところ、1個薄いのがいました。気にするほど違うというわけではないのでそのままにしてます。
せっかくソフトで明るさを変えれるようにしてるので校正もソフトでやっちゃうのが筋なんでしょうね。フルカラーLEDの場合、フィラメントというか光るものが配置されている場所もRGBで微妙に異なっているので、見る角度でも微妙に色が変わって見えたりします。気にしだすときりがないという感じです。

コメントを投稿