LEDの輝度の調節、モーターの回転の速度制御、音の出力など、様々な用途があるPWMですが、AVRで出力してみます。
私もロボットのモーターの速度制御でよく使用しています。
今回、PWMについての説明は省略したいと思います。
PWMって何?って方はこちらや「PWM」で検索してみてください。→モータ制御に欠かせない技術“PWM”って何?
デバイスは秋月でも安く購入できるようになったATMEGA88でのPWM出力方法を解説していきたいと思います。
今回は、タイマ1の高速PWM動作でPB1からPWMを出力してみたいと思います。
なぜタイマ1を使用するかと言えば、一つは16bitのタイマであること。
2つ目に私はよくwait関数をタイマ0を使って書くのでタイマ1をPWMに使うことが多いということです。
別にPWMはタイマ0でも出力可能ですし、もう一つのタイマ2でも出力は可能です。
タイマ1の方法と他のタイマでの方法はそこまで変わることはないので応用すればどのタイマでも出力することが可能です。
では、出力するためにタイマ1のレジスタを設定して行こうと思います。
タイマ1には、
が存在します。
このレジスタだけ列挙して行きますと、数が数だけに設定が大変そうに見えますが、実際この中で使用するのは一部だけです。
今回のPWMの出力で必要なレジスタは、TCCR1A・TCCR1B・TCNT1・OCR1A・ICR1となります。
では、それぞれのレジスタを設定して行きましょう。
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
TCCR1A | COM1A1 | COM1A0 | COM1B1 | COM1B0 | - | - | WGM11 | WGM10 |
TCCR1Aの中はこのようになっています。
COM1A1 | COM1A0 | 動作内容 |
---|---|---|
0 | 0 | 標準ポート動作 |
0 | 1 | トグル動作 |
1 | 0 | 一致でL、非一致でH(非反転動作) |
1 | 1 | 一致でH、非一致でL(反転動作) |
まず、PWMの比較出力選択を行いましょう。
COM1A1とCOM1A0では出力を非反転動作で出力させたいので、COM1A1を1、COM1A0を0に設定します。
WGM13 | WGM12 | WGM11 | WGM10 | 動作内容 | TOP値 | OCR1更新時 |
---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 高速PWM動作 | ICR1 | BOTTOM |
1 | 1 | 1 | 1 | 高速PWM動作 | OCR1A | BOTTOM |
次に動作モードを高速PWM動作に設定して行きます。
実際には16種類モードがありますが、ここでは説明の都合上2種類の高速PWM動作の欄だけ抜き出してあります。
また、TCCR1AにはWGM13とWGM12が存在しませんが、この後で説明するTCCR1Bにありますので心配ありません。
2種類の高速PWM動作がありますが、違いはTOP値になります。
TOP値というのはカウンタの上限となる値です。このTOP値とカウンタが一致したときにカウンタがクリアされます。
今回はOCR1Aを比較レジスタとして利用したいので、TOP値がICR1となるようにWGM11を1、WGM10を0に設定します。
TCCR1Aにはビットが他にも存在しますが、今回の動作には必要ないので飛ばします。
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
TCCR1B | ICNC1 | ICES1 | - | WGM13 | WGM12 | CS12 | CS11 | CS10 |
TCCR1Bの中はこのようになっています。
WGM13とWGM12はTCCR1Aで説明した通り、両者とも1に設定します。
CS12 | CS11 | CS10 | 動作内容 |
---|---|---|---|
0 | 0 | 0 | タイマ停止 |
0 | 0 | 1 | 分周無し |
0 | 1 | 0 | 8分周 |
0 | 1 | 1 | 64分周 |
1 | 0 | 0 | 256分周 |
1 | 0 | 1 | 1024分周 |
このCS12〜CS10でタイマ1の動作クロックを設定します。
CPUのクロックをどの位分周するかを指定します。
今回は64分周してみます。ここの分周の値は各自必要な動作にあわせて変更してください。
64分周なので、CS12を0、CS11を1、CS10を1に設定します。
TCCR1Bにはビットが他にも存在しますが、今回の動作には必要ないので飛ばします。
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
TCNT1H | - | - | - | - | - | - | - | - |
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
TCNT1L | - | - | - | - | - | - | - | - |
TCNT1の中はこのようになっています。
TCNT1は16ビットのレジスタですが、TCNT1HとTCNT1Lの2つの8ビットレジスタとしてもアクセスすることが可能です。
今回はカウンタの中身をクリアするだけなので、TCNT1に0を設定します。
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
OCR1AH | - | - | - | - | - | - | - | - |
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
OCR1AL | - | - | - | - | - | - | - | - |
OCR1Aの中はこのようになっています。
OCR1Aも16ビットのレジスタですが、OCR1AHとOCR1ALの2つの8ビットレジスタとしてもアクセスすることが可能です。
この比較レジスタの値とカウンタの値が一致したときピンに変化を起こします。
今回の場合は非反転動作で動かしているので、一致するまではHを出力し、一致した時Lを出力します。
値は適当に0x07FFと設定しておきます。このOCR1Aの値を変化させることによってデゥーティ比を変化させます。
ここも各自で使用用途に応じて設定してください。
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
ICR1H | - | - | - | - | - | - | - | - |
bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
ICR1L | - | - | - | - | - | - | - | - |
ICR1の中はこのようになっています。
ICR1も16ビットのレジスタですが、ICR1HとICR1Lの2つの8ビットレジスタとしてもアクセスすることが可能です。
先ほどTCCR1AのWGMの設定でも説明した通り、カウンタの上限となる値を設定します。
値は適当に0x0FFFと設定しておきます。ここも各自で使用用途に応じて設定してください。
長々説明してきましたが、以上で設定が終わりました。
上記で設定した内容をC言語で書きまとめると以下のようになります。
TCNT1 = 0;
ICR1 = 0x0FFF;
OCR1A = 0x07FF;
TCCR1A = 0x82; //1000 0010
TCCR1B = 0x1B; //0001 1011
順番はタイマが比較レジスタなどのが設定される前に動作を開始すると困るので、
カウンタ動作の開始を決めるTCCR1Bを必ず最後に行ってください。
これでPB1からデューティ比50%のPWMが出力できました。
もしここでデューティ比を25%にしたいなら、TOP値(ICR1)の25%である0x03FFをOCR1Aに設定すればよいだけです。
HERO'S and heavy friends様より、mega88.pdf(MEGA88シリーズ翻訳日本語版データシート)
[08/09/23] : 掲載開始