はじめに
こんにちは!
最近はATtiny13ばっかりの記事ですが私自身の備忘録として細かいこともまとめていこうと思います。
今回はArduino関数であるanalogWrite()をATtiny13のレジスタ操作で再現しますよ。
詳細は次項から説明しますが、ATtiny13には8bitタイマ/カウンタの機能があり、これを使用してPWMを作っていこうと思います。
では、どうぞ!
8bitタイマ/カウンタ説明
ATtiny13には8bitタイマ/カウンタが2ピン(OC0A, OC0B)備え付けられております。
ざっくりとですがタイマ/カウンタレジスタは【TCNT0】であり、タイマ/カウンタ比較レジスタ【OCR0A, OCR0B】と比較することでPWMを作り出すことが出来ます。
- タイマカウンタ:TCNT0(カウント中の書き込みは厳禁です。)
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
(MSB) | (LSB) |
- タイマカウンタ比較レジスタ:OCR0A, OCR0B
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
(MSB) | (LSB) |
これらの設定に関してはタイマ/カウンタ制御レジスタ【TCCR0A】と【TCCR0B】で行う必要があります。
- タイマカウンタ制御レジスタ:TCCR0A
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
COM0A1 | COM0A0 | COM0B1 | COM0B0 | – | – | WGM01 | WGM00 |
- タイマカウンタ制御レジスタ:TCCR0B
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
FOC0A | FOC0B | – | – | WGM02 | CS02 | CS01 | CS00 |
動作設定に関してはWGM02, WGM01, WGM00を設定することで出力波形の種別の選択ができます。6動作ありますが、基本4動作に分類され残りの2動作に関してはタイマ波形のTOP値、タイマ/カウンタ漏れ割り込みフラグ【TOV0】の設定の違いになります。
WGM02 | WGM01 | WGM00 | 動作種別 | TOP | OCR0x更新時 | TOV0設定時 |
0 | 0 | 0 | 標準 | FF | 即時 | MAX |
0 | 0 | 1 | 8bit位相基準PWM | FF | TOP | BOTTOM |
0 | 1 | 0 | CTC | OCR0A | 即時 | MAX |
0 | 1 | 1 | 8bit高速PWM(本記事) | FF | BOTTOM | MAX |
1 | 0 | 0 | 予約 | |||
1 | 0 | 1 | 位相基準PWM | OCR0A | TOP | BOTTOM |
1 | 1 | 0 | 予約 | |||
1 | 1 | 1 | 高速PWM | OCR0A | BOTTOM | TOP |
- 標準動作:単純な加算カウント8bit(255)を超えて値がオーバーフローすると0からカウントリスタートする(非PWM)。
- CTC動作:OCR0Aがカウンタに対するTOP値となり、カウントがOCR0Aに達すると0に戻る。カウントがTOPに達するときに割り込み(TOV0)が生成できるのでこの時にOCR0Aを更新することでカウンタに対するTOP値を更新することができる(非PWM)。
- 高速PWM動作:片傾斜の三角波に対してOCR0Aを比較することでPWMを生成することができる。次項の両傾斜三角波によるPWM動作に比べて動作周波数を1/2にすることができる。(今回はこちらでテストしていきます。)
- 位相基準PWM動作:両傾斜の三角波に対してOCR0Aを比較することでPWMを生成することができる。高速PWM動作に比べて動作周波数は低くなるが、メリットとして両傾斜の三角波を使用しているので、その対称性からPWM波形の位相がずれにくくなります。モーター制御に有利らしい。
また、COM0x1, COM0x0の設定により比較出力(PWM)の選択を行うことが出来ます。本記事では非反転出力を扱っていきます。その他の設定に関してはデータシートの参照をお願い致します。
実装_高速PWM
コード
実装という事で今回は高速PWMのみをピックアップしていきます。コードに関してはArduino関数であるanalogWrite(pin, int8_t)の雰囲気でhsPWM(bool, int8_t)とする関数を作っていきますね。
<引数>
- bool: 0または1(PB0,PB1出力のため)
- int8_t: 0~255
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <avr/io.h> uint8_t hsPWM(bool pin, int8_t pwm){ //*内臓クロック9.6MHz //TCNT0 = 0; // タイマ0の初期値 if(pin==0){ DDRB |= 0b00000001;//PB0出力設定 TCCR0A |= 0b10000011;//PB0非反転出力,高速PWM TCCR0B |= 0b00000010;//8bit高速PWM,8分周比 OCR0A = pwm;//8bitタイマ/カウンタ比較レジスタA return OCR0A; }else{ DDRB |= 0b00000010;//PB1出力設定 TCCR0A |= 0b10000011;//PB0非反転出力,高速PWM TCCR0B |= 0b00000010;//8bit高速PWM,8分周比 OCR0B = pwm;//8bitタイマ/カウンタ比較レジスタA return OCR0B; } } void setup() { } void loop() { hsPWM(0, 127);//8bit高速PWM関数 } |
返り値は8bitPWM出力です。システムクロック9.6Mzに対するタイマクロックの分周比は行っていませんが【TCCR0B】レジスタで8分周~1024分周まで設定することが出来ます。次項で少し説明します。
テスト回路はPB0に適当な抵抗を繋いだLEDを接続してみてください。hsPWMの第二引数を調整することでLEDの調光ができるかと思います。
タイマ/カウンタ入力クロック(分周)について
ATtiny13の8bitタイマ/カウンタの入力クロックはシステムクロック(デフォルト9.6MHz)に対して0~1024の分周比を取ることが出来ます。本記事ではLED調光に使用したので分周なしで使用しました。
例えば分周比8(9.6/8=1.2MHz)で使用した場合は83us毎にカウントアップしていきます。たとえば前述のコードで分周比8にして、比較レジスタ【OCR0A】を127に設定した場合は0.01ms(83us×127)毎にON/OFFするような出力になります。分周比1024(9.4kHz)に設定して【OCR0A】を127に設定した場合は13.5ms(0.1ms×127)毎にON/OFFされるはず、、、です(間違っていたらご指摘ください)。
その様子を以下の動画にまとめました。
※視覚的にわかりやすいようにする為にシステムクロックを9.6/8分周比で1.2MHzとしています。
おわりに
先日の記事から引き続きでArduinoの関数をレジスタ操作で再現していきました。今回のAnalogWrite()が出来ればほぼほぼ基本的な関数はマスターすることが出来たのでしょうか(細かいところは全然だと思いますが、、、)
せっかくなので、近いうちにATtiny13を使った何かを作ってみたいと思います!
ではでは~
コメント