マイコンでLEDを点灯させている時、明るさを自由に変化させられたら便利だなぁ、と思ったことがあるのではないでしょうか。
力技でやれば出来ない事はないですが、そのマイコンがLED制御以外も行いたい場合ちょっと面倒な事になったりします。
そこで、AVRの内蔵機能であるPWMを使用してLEDの明るさ制御をしてみようと思います。
PWMってなに?
PWMとはPulseWidthModulationの略で、パルス幅変調を言います。
一定周期のパルス波をオンまたはオフ(デューティ比)で変化させて実現します。
デューティ比は1周期の分解能を表すことが出来、分解能が高いほどより繊細な制御が可能となります。
1周期が1ミリ秒の時は1KHzのPWMとなり、1ミリ秒の中でデューティ比に沿ったパルスがオン・オフされます。
AVRでのPWM
AVRのPWM機能は機種によって扱いが微妙に異なる部分があります。
その為今回は電子ホタルを制作した時に使用したTiny45のPWM機能に絞ってお伝えします。
Tiny45にはタイマーが2個あり、PWM機能はこのタイマーに割り当てられているのでどちらかのタイマーをPWMに使う事になります。
電子ホタルではタイマー0を明るさの変化値の更新に、タイマー1をPWM機能に割り当てました。
PWMを使用するための手順は以下の流れです。
PWM出力ピンはPB1(OC1A)
1.動作クロック変更(8MHz→1MHz)
↓
2.PB1を出力へ設定
↓
3.タイマー1制御レジスタ設定
・分解能最大値設定 OCR1C
・タイマー1制御レジスタ設定 TCCR1
・タイマー1制御レジスタ設定 GTCCR
・PWM値設定 OCR1A
↓
4.割り込みスタート
1.動作クロック変更(8MHz→1MHz)
CLKPR = 0x80; // 動作クロック変更要求
// 4clk中に済ませる
CLKPR = 0x03; // 8MHz / 8 = 1MHz設定
必ず必要な処理ではないですが、バッテリーでも動かす事も考慮しているので
クロックを落とす事で消費電流を抑える様にしています。
動作クロック設定時はCLKPRに0x80を書き込んでから4クロック以内に処理を終えないとクロック操作が無効になる点は注意してください。
2.PB1を出力へ設定
PORTB = 0b00000000; // 全ポートオフ
DDRB = 0b00000010; // PB1出力へ
AVRでは入出力の設定にDDRxを使用します。
そして実際のポートオン・オフはPORTxに対して行います。
3.タイマー1制御レジスタ設定
・分解能最大値設定 OCR1C
OCR1C = 255; //
・タイマー1制御レジスタ設定 TCCR1
TCCR1 = 0b01100001; // sck(1MHz)/ 1 3906Hz動作
・タイマー1制御レジスタ設定 GTCCR
GTCCR = 0b00000000;
TCCR1のプリスケーラが1でOCR1Cが255のため、3906Hz = 1000000 / 255
約4KHzがPWM周波数となります。
・PWM値設定 OCR1A
OCR1A = 0;
初期値として0を与えてPWMはオフの状態からスタートする。
4.割り込みスタート
以降タイマー0の計時割り込みに応じて明るさデータを取得しOCR1Aへ書き込む事でLEDの照度を変更していきます。
明るさデータはプログラム内に埋め込まれていてpgm_read_byte関数によって読み出されています。
またホタルの発光用データは5種類あって、タイマー0の計時割り込み内でスイッチを読み取りメイン関数内で切り替えを行います。
実際に制作した電子ホタルの動画はこちらになります。
今後の課題
電子ホタルに使用しているATTiny45はフラッシュメモリが4kbのため、あまり細かく明るさを制御できていません。
現行では明るさの変化が飛び飛びに保存されている構造で、そのままでは不自然な変化となるのでプログラムで間の部分を補完しています。
最上位版のATTiny85ならフラッシュメモリは8kbと倍ありますから解像度を上げるか1周期の明滅時間を延ばすことでより自然な光り方に見えると考えています。
もっと大容量のAVRを使うかEEPROMを積んだりも出来るのですが、お手軽に持ち出せることを大前提に考えているので外付け部品は極力減らして作りたいところです。
まとめ
普段の生活でもPWMが使われている事は多かったりします。
一番身近なところでは携帯電話用のACアダプタかと思います。
直流モーターやサーボの制御にも広く使われていますし音楽の再生にも使えたり、もちろんLEDの明るさ制御も出来てしまいます。
みなさんもPWMを使って面白い使い方を考えてみてはいかがでしょうか。