プログラミングと工作と

PythonとかPascalとかAVRマイコンとか、コンパイラつくったり電子工作なんかを楽しんでいるおっさんの記録

AVRマイコン アセンブリ言語入門 ― 8bitタイマその4

さて、今回はいよいよ8bitタイマを使ったLED点滅プログラムを作ってみます。

まずは、レジスタの設定値を決めます。
前回の復習 ー 設定する項目は

  1. 動作モード:ノーマルモードかCTCモードか等
  2. プリスケーラの値
  3. カウント比較値
  4. 割込み要求の設定

になります。

今回は、200msごとにLEDを点滅させてみます。
この200msを8bitタイマを使って作り出します。

 

CPUクロックはデフォルトでは1MHzなので、クロック1パルスが1μs、
プリスケーラを1024にしてカウント比較値を196にすると
1μs×1024×196 = 200.704ms
これで行きます。

 

使用するのはタイマ0、動作モードは以前話したようにCTCモード一択なので、これでレジスタ値が全部決まります。

  1. 動作モード :CTCモード  ->  WGM02〜WGM00 = 010
  2. プリスケーラの値 :1024  ->  CS02〜CS00 = 101
  3. カウント比較値 :196  ->  OCR0A = 0b11000100 = 0xC4

前回の表にこれらの値を入れると、それぞれのレジスタ値は以下になります。

TCCR0A = 0b00000010
TCCR0B = 0b00000101

OCR0A = 0b11000100 = 0xC4

さあ準備が出来ました。
プログラムを書いていきます。

 

/*
 * LED_Timer.asm
 *
 *  Created: 2015/09/16 20:56:21
 *   Author: Takachiho
 */ 
;  PortBのBit0に接続したLEDを、
; Timer0のCTCモードを使って点滅させる
;  約200ms間隔で点滅させる

.include "m168pdef.inc"

;************************************************
; 各種定義
;************************************************
;--------------------
; 汎用レジスタ
;--------------------

.def	STACK = R16     ;汎用レジスタR16に'STACK'という名前をつける

;--------------------
; 割り込みベクタ定義
;--------------------

.CSEG
		RJMP	MAIN
.ORG	0x001C          ;8bitタイマ0からの割込みが発生すると
                        ;マイコンはこのアドレスを実行する。
		RJMP	ICTC0   ;ラベルICTC0へジャンプする。

;************************************************
;  割り込みルーチン タイマ0
;************************************************

ICTC0:
;------- ステータスレジスタの内容を退避  --------

		IN	STACK,	SREG

;------- LED ON/OFF を切り替え ------------------

		IN  	R17,	PORTB       ;PortBの内容をR17へコピーする
		LDI 	R18,	0x01        ;R18へ値0x01 = 0b00000001を代入
		EOR 	R17,	R18         ;R17とR18の排他的ORの結果をR17へ
		OUT 	PORTB,	R17         ;R17の結果をPortBへ代入する
		
		;排他的論理和(エクスクルーシブオア)は、ビット反転に使われる。
		;'1'とのEORをとると、相手が'1'なら'0'へ、'0'なら'1'へ
		;反転する。
		;この性質を利用して、LEDが点灯'1’しているなら消灯'0'
		;消灯しているなら点灯させる動作を行わせる。

;------- ステータスレジスタの内容を復帰  --------

		OUT		SREG,	STACK

		RETI

;************************************************
;  メイン・ルーチン (MAIN)
;************************************************
MAIN:

;------- 全割り込み禁止 -------------------------

		CLI

;------- PORT 設定  -----------------------------

		LDI		R17,	0b11111111  ;ポートBは全て出力に設定
		OUT		DDRB,	R17
		LDI		R17,	0b00000001  ;bit0以外すべて'0'出力
		OUT		PORTB,	R17

		LDI		R17,	0b11111111  ;ポートCは全て出力に設定
		OUT		DDRC,	R17
		LDI		R17,	0b00000000  ;すべて'0'出力
		OUT		PORTC,	R17

		LDI		R17,	0b11111111  ;ポートDは全て出力に設定
		OUT		DDRD,	R17
		LDI		R17,	0b00000000  ;すべて'0'出力
		OUT		PORTD,	R17

;------- 8bitタイマレジスタ設定 ---------------

    ;-------  動作モード 設定  -------

		LDI		R17,	0b00000010	;CTCモードを指定
		OUT		TCCR0A,	R17

    ;-------  プリスケーラ 設定  -------

		LDI		R17,	0b00000101	;プリスケーラ 1024
		OUT		TCCR0B,	R17

    ;-------  比較値 セット  -------

		LDI		R17,	0xC4        ;比較値196 = 0xC4に設定
		OUT		OCR0A,	R17

    ;-------  タイマ割り込み許可  -------

		LDS		R17,	TIMSK0          ;TIMSK0レジスタの値をR17へ
		SBR		R17,	(1 << OCIE0A)   ;ビット1(OCIE0A)を'1'へセット
		STS		TIMSK0,	R17             ;TIMSK0レジスタに値を代入
		
		;TIMSK0レジスタのビット1(OCIE0A)を'1'へセットすることにより
		;カウント値がOCR0Aレジスタ(タイマ/カウンタ0比較レジスタA)の値と
		;一致した時、割込みを発生させる。

;-------  全割り込み許可  -----------------------

		SEI


MAIN01:
		RJMP	MAIN01

 

で、実行させました。

 

f:id:takashira:20151123215602j:plain

大成功!
・・・って、写真じゃ点滅しているところがわからないですね。

 

あと、プログラムの割込みのあたりが良くわからないかもしれません。
次回は割込み動作の説明をしたいと思います。