PWMの実験(ATtiny26L)
(AVRを始めて、不勉強の中データシートだけを頼りにPWMを動かしましたが、暗中模索の実験では余分なものまで書いていましたので書き換えました。20060612)
Tiny26には、2つのPWM出力があり、さらに、これに加えてこれらの逆位相のものが取り出せますが、単純にOC1Aピン(PB1ピン)のPWM出力に正論理で点灯する
LEDをつないだ最も簡単な実験をしました。
デューティの変化がわかるように時間(ウエイトルーチン)でデューティを変えています。
ハードウエアはTiny26Lに電源の他には2番ピンに電流制限抵抗を付けたLEDを接続したものです。Hで点灯します。
PWM周波数は非常に広範囲にとれるようですが、ここではクロックをデフォルトの1MHzとして、100Hz(10ms周期)程度にします。
このプログラムでは、タイマ/カウンタ1が、クロックの1/32(1MHz/32≒31kHz)で0〜255をカウントします。このとき、TCCR1Aレジスタの設定により、
OCR1Aレジスタにプログラムで設定した値と等しくなると出力端子OC1AがHにセットされ、さらにカウンタが進んで255から0に戻るときにLにセットされます。
すなわち、カウンタが0〜255と進むうち、OCR1Aレジスタ以上の時はHになります。このレジスタの値を小さくするとデューティが大きくなります。
PWMの周波数は f=タイマカウンタの周波数/256 で、 タイマカウンタの周波数=クロック/分周比 ですから
1MHzのクロックで分周比を32とすると f=122Hz(周期は約8ms)になります。
PWM動作にはいくつかのレジスタが関係しています。要点を書いてみます。
■ タイマ/カウンタ1制御レジスタA (Timer/Counter1 Control Register A) TCCR1A PWMの許可と1〜4番ピンの状態を決める。
COM1A1(bit7) | COM1A0(bit6) | 出 力 |
0 | 1 | OC1A: 比較一致でクリア(Low)、
#OC1A: TCNT1=$00でクリア(Low)<逆位相> |
1 | 0 | OC1A: 比較一致でクリア(Low) |
1 | 1 | OC1A:比較一致後の1前置分周出力クロックでセット
(High) |
COM1B1(bit5) | COM1B0(bit4) | 出 力 |
0 | 1 | OC1B: 比較一致でクリア(Low)、
#OC1B: TCNT1=$00でクリア(Low)<逆位相> |
1 | 0 | OC1B: 比較一致でクリア(Low) |
1 | 1 | OC1B:比較一致後の1前置分周出力クロックでセット
(High) |
PWMの許可は、PWM1A(bit1), PWM1B(bit0) である。
いま関係するのはこのうちのAだけです。
■ タイマ/カウンタ1制御レジスタB (Timer/Counter1 Control Register B) TCCR1B カウンタ1の分周比を決める。
bit3--0 1/1=1 /2=2 /4=3 /8=4 /16=5 /32=6 /64=4 ... /1024=11 ../16384=15
■ タイマ/カウンタ1 (Timer/Counter1) TCNT1 0〜255をカウント。設定はしなくてよい。
■ タイマ/カウンタ1 比較Aレジスタ(Timer/Counter1 Output Compare Register A) OCR1A OC1Aのデューティを決めるレジスタ。
■ タイマ/カウンタ1 比較Bレジスタ(Timer/Counter1 Output Compare Register B) OCR1B OC1Bのデューティを決めるレジスタ。いまは関係ありません。
■ タイマ/カウンタ1 比較Cレジスタ(Timer/Counter1 Output Compare Register C) OCR1C のこぎり波の最高を定めます。
普通は255でよいでしょう。小さい値を設定して、TCCR1Bのビット7(CTC1)をセットするとカウンタはその数値でクリア
されます。今回は255とします。
プログラムを考えます。
TCCR1Aでは、COM1A1,COM1A0, PWM1Aをセットします。 TCCR1A=_BV(COM1A1)|_BV(COM1A0)|_BV(PWM1A);
TCCR1Bは、32分周しますから bit3--0に 0110 を書きます。
OCR1Aは、デューティを決める値ですからプログラム中で 0〜255 に変えます。
OCR1Bは使いません。
OCR1C のこぎり波の最高は255を使うので255に設定します。
これをまとめるとこのようになりました。
「OC1Bに同様の信号を出力する」場合は、
レジスタのAとBを変えればよいわけですから
TCCR1Aでは、COM1B1,COM1B0, PWM1Bをセットします。 TCCR1A=_BV(COM1B1)|_BV(COM1B0)
|_BV(PWM1B);
OCR1Bは、デューティを決める値ですからプログラム中で 0〜255 に変えます。
「OC1AとOC1Bに同時に出力する」時はAとBの両方のレジスタをセットします。
このところ出てきたいくつかの記号(式、関数)について少し書きます。
_BV() は()の数値で表されるbitをセット(1を書く)する関数です。アンダースコア"_"に注意してください。
_BV(6)は2進では"01000000"になります。 _BV(PWM1A)の"PWM1A"は定義ファイルで"1"と決められています。従って"00000010"
となります。
"|"記号 これはビットごとのOR記号です。"1|8"は"1"が00000001、"8"は00001000ですから、00001001="9"となります。
「AとBのセットされているビットをともに有効にしたい」時に使います。
因みに、ビットごとのAND記号は"&"を使います。ある8ビット数 xの第3ビットを調べたいときは、x&_BV(3)を調べれば、
第3ビット以外は0とのANDで必ず0になってしまします。このようにマスクするときによく使われます。