本文へスキップ

アトメル社のAVRマイコンをつかった電子工作および無線を使った電子工作を紹介します。





ホーム > 工作室トップ > LED調光

LED調光

マイコンのPWM機能を使ってLEDの調光を行う前に基礎実験としてLEDをパルス駆動してLEDの光具合および消費電流の実験をした後、マイコンのPWM機能を使用したLED調光回路を作ります。
PWM調光とは、LEDのON/OFFを繰り返して点灯する方法です。ON時間を可変することにより調光することができます。速い周波数でON/OFF点灯することにより 人の目には点滅しているようには見えません。

1.LEDをパルス駆動で動作させる。

1.1.実験回路


(1)LEDの駆動トランジスタ定数決定
電源電圧Vddはニッケル水素電池4本4.8Vで動作させます。
LEDはトランジスタでON/OFFを行います。
LEDには20mA程度を流します。
hFE=70とします。
トランジスタのコレクタ電流Ic=hFE X Ibより
Ib=Ic/hFE=20mA/70=0.3mA
ベース抵抗R2=(電源電圧-ベースエミッタ間電圧VBE)/ベース電流Ib
=(4.8V-0.6V)/0.3mA=14kΩ
14kΩ以下のベース抵抗を選択することで20mA流すことができますので今回はR2=1kΩとします。(安全のため10倍以上のIcが流すことができる能力を持てるようにベース抵抗を決めています。)
(2)電流制限抵抗R1の決定
20mAの電流を流したときに、高輝度白色LEDの順方向電圧Vfは2.8V~3.8Vです。(オプトサプライ社OSPW5111A-Z3のカタログより)
電源電圧Vdd=4.8V
コレクタ電流Ic=20mA
順方向電圧Vf=2.8V
電流制限抵抗R1=(4.8V-2.8V)/20mA=100Ω
順方向電圧Vf=3.8Vのものを使用したときのコレクタ電流は(4.8V-3.8V)/100Ω=10mA
従って電流制限抵抗R1=100Ωは順方向電流の最大値30mAを超えずに使用できます。
順方向電圧(If=20mA)[V] 最小 標準 最大
2.8 3.3 3.8
順方向最大電流(Ifmax)[mA] 30

(3)パルス発信器
方形波パルスを出力してトランジスタをON/OFFします。パルス発信器はパルス周期および、デューティ比を変更できます。

1.2.実験結果

1.2.1.周波数を可変
デューティ比=50%と固定して周波数を変更したときの消費電流およびLEDが点滅を始める周波数を実験します。
電源はニッケル水素電池4本を使用。(実測値5V)
周波数[Hz] 周期[ms] 電流[mA] LEDの点灯状態
10000 0.1 10.1 点灯
5000 0.2 10.0 点灯
1000 1.0 9.8 点灯
500 2.0 9.8  点灯
100 10.0 9.8 点灯
50 20.0 9.9 点灯
40 25.0 9.9 点滅

1.2.2.デューティ比を可変
周波数を100Hzに固定してデューティ比を可変したときの消費電流およびLEDが点滅を始めるデューティ比を実験します。
デューティ比 電流[mA] LED点灯状態
100 24.1 点灯
95 18.9 点灯
90 17.9 点灯
80 15.9 点灯
70 13.8 点灯
60 11.8 点灯
50 9.8 点灯
40 7.8 点灯
30 5.9 点灯
20 3.9 点灯
10 2.0 点灯
5 1.0 点灯

1.2.3.結果
パルス周波数100Hzでデューティ比を可変としてLEDの明るさをかえる(調光)ことができることがわかりました。。
10%程度の変化ではLEDの明るさは変わらないように見えました。

2.PWMでLEDを調光する。

2.1.仕様

項目 内容
電源 ニッケル水素電池4本(4.8V)
マイコン ATtiny13A
PWM周期 100Hz
デューティ比 5%,25%,50%,75%,100%の5段階
デューティ比の変更 UP/DOWN押しボタンスイッチによる。

2.2.回路

回路図

PWM出力はOCR0Bから出力します。
UP/DOWNスイッチはタクトスイッチで行います。

組立図

ブレットボード上に回路を構成します。
部品表
名称 形名 メーカ 購入先 数量
白色LED OSPW5111A-Z3 オプトサプライ 秋月電子
抵抗 100Ω 1/4W 秋月電子
抵抗 1kΩ 1/4W 秋月電子
抵抗 10kΩ 1/4W   秋月電子
抵抗 100kΩ 1/4W
トランジスタ 2SC1815 東芝 秋月電子
マイコン ATtiny13A アトメル 秋月電子

2.3.フローチャート

フローチャート

・使用しないポートは出力に設定しておきます。
・スイッチの検出は割り込みで行います。
・UP/DOWNスイッチを押していき上限/下限まできたら上限/下限の状態を維持しておきます。
・スイッチがずっと押されている間は何もしません。
・スイッチを両方押した場合はUPスイッチを優先します。

2.4.プログラム

2.4.1.PWMの設定法
ATtiny13Aは4種類のタイマモードを持っています。そのうちの高速PWMモードを使用します。
タイマモード 概要
タイマモード概要標準(フリーラン)モード 電子さいころで説明したように単純にカウントアップしてき最大値255まで来ると次は0に戻りまたカウントアップしていきます。
周期は255となります。 
CTCモード コンペアレジスタAに設定された値(最大値は255)までカウントアップしていき次は0に戻りカウントアップしていきます。
コンペアレジスタAに設定された値が周期となります。
高速PWMモード コンペアレジスタAに設定された値をタイマの周期とし、コンペアレジスタBをパルス幅として動作します。タイマ値が’0’のとき出力は’H’となっています。次にコンペアレジスタBの値までカウントアップすると出力は’0’となります。コンペアレジスタAの値までカウントアップすると’0’に戻るとともに出力を’H’にします。(出力の設定を非反転に設定した場合)
以上のようにコンペアレジスタAが周期、コンペアレジスタBがパルス幅となります。
フェーズコレクトPWM 高速PWMと同様ですがTOPまでカウントアップすると今度は減算してBOTTOMまで減算していきます。

2.4.2.PWMレジスタ設定
PWM設定 高速PWMに設定 WGM02:00 = 111
PWM出力ポート設定 PB1( OCR0B )に非反転出力 COM0B1:0 = 10
設定周期設定 周期は100Hzとする。
OCR0AにTOP値を設定する。TOP値の最大値は255 (0xff)までなので分周比は64とする。
出力周波数F = 元クロックfclk / ( 分周比N X(1+TOP ))
TOP = fclk / ( N X F ) - 1=1MHz / ( 64 X 100) - 1
= 155 
分周比CS02:00 = 010
周期OCR0A = 155
デューティ比設定 デューテイ比はOCR0Bに設定する。
デューティ比は50%とする。
デューティ比0.5=(OCR0B+1)/(OCR0A+1)
OCR0B=0.5X(OCR0A+1)-1
=0.5X(155+1)-1=77
OCR0B = 77
スタート CS02:CS00を'0'以外に設定するとスタートする。 CS02:00
PWM設定の最後に設定する。

TCCR0Aレジスタ
COM0A1 COM0A0 COM0B1 COM0B0 WGM01 WGM00

TCCR0Bレジスタ
FOC0A FOC0B WGM02 CS02 CS01 CS00

割込フラグレジスタTIFR0
OCF0B OCF0A TOV0

TIFR0レジスタ内容
OCF0B 比較レジスタOCR0BとTCNT0(タイマカウンタ)が一致したときにフラグが立つ
OCF0A 比較レジスタOCR0AとTCNT0が一致したときにフラグが立つ
TOV0 TCNT0がオーバーフローするとフラグが立つ

2.4.3.割込設定
ポート状態変化割込許可 ポートの状態が変化したときに割込を動作 GIMSKのPCIEを1に設定
 ポート3とポート4の状態の変化で割込許可 PCMSKのPCINT3とPCINT4を1に設定 

GIFR
INTF0 PCIF

PCMSK
PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0

割り込み処理はSIGNAL(割り込みベクタ)内に処理を記述します。つまり以下のように記述します。
SIGNAL(PCINT0_vect)
{
         割り込み処理を記述
}

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define   PULS_CYCLE 155

//                           5% 25% 50% 75% 100% デューティ比
uint8_t PulsWidth[] = { 7,  38, 77, 116, 155};

union states    // スイッチ状態フラグ
{
    uint8_t BYTE;
    struct
    {
        uint8_t :4;              // 未使用
        uint8_t up:1;           // UPスイッチON
        uint8_t keep_up:1;    // UPスイッチONしたことを記憶
        uint8_t dn:1;           // DOWNスイッチON
        uint8_t keep_dn:1;   // DOWNスイッチONしたことを記憶
    } BIT;
};

union states u_state;

void InitHard(void);     // 初期設定

int main(void)
{
    static int8_t pulse = 2;

    InitHard();
    sei();                   // 割り込み許可
    while(1)
    {
        if ( (u_state.BIT.up == 1) && (u_state.BIT.keep_up == 0) ) // UPスイッチをON
        {
            u_state.BIT.keep_up = 1;  // UPスイッチがONされたことを記憶
            if ( ++pulse > 4)             // デューティ比を大きくする
            {
                pulse = 4;                  // デューティ比が100%を超えない
            }
            TIFR0 |= 1 << OCF0A;     // OCF0Aを一度クリアする
            while(!(TIFR0 & (1 << OCF0A)));  // OCF0Aが’1’になるまで待つ。(OCR0Aと一致するま で)その後にOCR0Bを変更する。
            OCR0B = PulsWidth[pulse];    // デューティ比を設定
        }
        else if ( (u_state.BIT.dn == 1) && (u_state.BIT.keep_dn == 0)) // DOWNスイッチをON
        {
            u_state.BIT.keep_dn = 1;   // DOWNスイッチがONされたことを記憶
            if ( --pulse < 0)              // デューティ比を小さくする。
            {
                pulse = 0;                  // デューティ比を5%より小さくしない
            }
            TIFR0 |= 1 << OCF0A;     // OCF0Aを一度クリアする
            while(!(TIFR0 & (1 << OCF0A)));  // OCF0Aが’1’になるまで待つ。(OCR0Aと一致するま で)その後にOCR0Bを変更する。 
           OCR0B = PulsWidth[pulse];   // デューティ比を設定
        }
    }
}

void InitHard(void)
{
    // PB1:出力に設定(PWM出力OC0A)
    DDRB = (1 << DDB0) | (1 << DDB1) | (1 << DDB2);
    // PWM設定及びスタート
    TCCR0A = (1 << COM0B1) | (1 << WGM01) | (1 << WGM00); // 非反転出力, 高速PWM動作
    TCCR0B = (1 << WGM02);
    OCR0A =PULS_CYCLE;           // 周期100Hzに設定
    OCR0B =PulsWidth[2];            // デューティ比50%に設定
    // タイマスタート
    TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); // 64分周
    // PB3, PB4割り込み設定
    GIMSK = 1 << PCIE;                                    // 入力ポートの状態変化で割り込み許可
    PCMSK = (1 << PCINT3) | (1 << PCINT4);      // 入力ポートPB3とPB3の割り込み許可
}

SIGNAL(PCINT0_vect)   // UP/DOWNスイッチの状態(ON/OFF)が変化すると割り込み発生
{
    _delay_ms(10);            // チャタリング待ち

    if ( !(PINB & 0x10) )    // UPスイッチON
    {
        u_state.BIT.up = 1; // UPスイッチONを記憶
    }
    else if ( !(PINB & 0x08)) // DOWNスイッチON(DOWNスイッチよりもUPスイッチが優先される。
    {
        u_state.BIT.dn = 1;     // DOWNスイッチONを記憶
    }
    else if ( ((PINB & 0x10) == 0x10) && (u_state.BIT.keep_up == 1)) // UPスイッチOFF
    {
        u_state.BYTE = 0;     // スイッチ状態フラグをオールクリア
    }
    else if ( ((PINB & 0x08) == 0x08) && (u_state.BIT.keep_dn == 1)) // DOWNスイッチOFF
    {
        u_state.BYTE = 0;     // スイッチ状態レジスタをオールクリア
    }
}

2.5.実行

プログラムを実行すると最初はLEDはデューティ比50%で調光します。
以下に各デューティ比での消費電流を示します。
参考としてスリープモードを使用したときの消費電流を示します。
今回の実験ではLEDの消費電流が大きいのでマイコンの消費電流を削減するためにスリープモードを使用しても消費電流削減の効果は顕著には見られません。

電源:ニッケル水素電池4本(4.8V)
デューティ比
[%]
スリープモード無し(本実験回路)での消費電流
[mA]
スリープモード有りでの消費電流
[mA]
2.0 1.3
25 6.2 5.3
50 11.5 10.3
75 16.5 15.4
100 21.7 20.5