またしてもLチカです。記事の投稿間隔がすごく短いですが、Lチカシリーズとしてまとめて投稿しています。
今回は、PWM を用いてLチカをしたいと思います。
コード
とりあえずコードを以下に。割り込みは使いません。
.include "../m328pdef.inc"
.device atmega328p ; state device name explicitly in order to check memory range
.cseg ; the start point of code
; IRQ vector table
.org 0x0000 ; On RESET
rjmp main
.def tmp = r16 ; alias tmp = r16
setup_TMR:
ldi tmp, (0b11 << COM1A0) | (0b10 << WGM10) ; fast PWM for PB1, High on match
sts TCCR1A, tmp
ldi tmp, (0b100 << CS10) | (0b11 << WGM12) ; division by 256, match by OCR1A
sts TCCR1B, tmp
; when counter matches OCR1A, PB1 is set in the next clock edge.
ldi tmp, high(6250 - 1) ; per 200msec
sts OCR1AH, tmp ; higher
ldi tmp, low(6250 - 1) ; per 200msec
sts OCR1AL, tmp ; lower
; when counter matches ICR1H, V=1 and counter will be reset in the next clock edge.
ldi tmp, high(15625 - 1) ; per 500msec
sts ICR1H, tmp ; higher
ldi tmp, low(15625 - 1) ; per 500msec
sts ICR1L, tmp ; lower
ret
main:
rcall setup_TMR
sbi DDRB, PB1
loop:
rjmp loop
タイマーの設定
今回はタイマー1(TC1)を用います。
setup_TMR:
ldi tmp, (0b11 << COM1A0) | (0b10 << WGM10) ; fast PWM for PB1, High on match
sts TCCR1A, tmp
ldi tmp, (0b100 << CS10) | (0b11 << WGM12) ; division by 256, match by OCR1A
sts TCCR1B, tmp
; when counter matches OCR1A, PB1 is set.
ldi tmp, high(6250 - 1) ; per 200msec
sts OCR1AH, tmp ; higher
ldi tmp, low(6250 - 1) ; per 200msec
sts OCR1AL, tmp ; lower
; when counter matches ICR1H, V=1 and counter will be reset in the next clock.
ldi tmp, high(15625 - 1) ; per 500msec
sts ICR1H, tmp ; higher
ldi tmp, low(15625 - 1) ; per 500msec
sts ICR1L, tmp ; lower
ret
まず、タイマーにはいろいろな動作がありますが、その一覧を以下に示します。
WGMxx
では 高速 PWM 動作(14番)にしています。14番では、カウンタ値と OCR1A
の比較によるピン出力ができ、タイマー周期は ICR1
で決定できます。15番にすると比較値とタイマー周期が一致するので、例えばピン状態のトグル等の設定をする場合には良いのでしょう。通常の PWM ですと比較値と周期は一致してはいけないので、今回は二者を別々に取っています。
続いて、比較値とタイマー周期の書き込みです。例によって ldi
と sts
で行っていますが、ココで注意。この値は 16bit 値なので、AVR が 8bit マイコンであるという性質上、16bit を 8bit + 8bit で書き込むという動作をします。今回の場合はないですが、同様に 16bit 値を読み出すということもあるでしょう。その際、
- 書き込みは上位から
- 読み込みは下位から
という原則があるようです。確かに下位から書き込んでもうまく設定できてなさそうな雰囲気が出てきます。
本プログラムでは比較値を 200msec 分、周期を 500 msec 分としました。その際、high()
、low()
というマクロがあるようです。今回のような場合に役立ちますね。
ということで、以上です。今回は新しいアセンブリ命令はありませんでした。