前へ 目次 次へ
LEDを1mS間隔で点滅してみる
 

LEDを点灯できたところで、 次はLEDを点滅させてみましょう。

 
システムのクロックとプログラム実行のクロック
 

PICの命令は、4システムクロック単位で実行されます。 つまり、システムクロックが20MHzである場合には、 多くの命令が5MHzの実行クロックで動作していることになります。

ただし、分岐がある場合には、 先回りして読み込まれた命令が捨てられるために、 倍の8システムクロックを必要とします。

この性質を用いれば、プログラムから実行時間を見積もることができることになります。 割り込みなどを用いることなく、 LEDを希望する時間間隔で点滅させることができるわけです。

システムクロックが20MHzである場合には、 5MHz単位で実行されますから、 1命令は
 1/(5M)=1/5000000=0.0000002秒
単位で実行されることになります。 5000実行クロックで1mS=0.001秒というわけです。

 
Wレジスタ
 

Wレジスタというのは、 データの転送や演算の際に、 作業場所として利用されます。

たとえば、あるメモリに値をセットする場合には、 一旦Wレジスタに値を代入して、Wレジスタの値をメモリに転送するという方法をとったりします。


LEDを1mS間隔で点滅するプログラムの例
 
;	LEDを点滅させる1mS 2002/04/16(Tue)

	LIST	P=16F84		;アセンブラにPICデバイスの情報を与える
STATUS	EQU	H'0003'		;STATUSレジスタは3番地
RP0	EQU	H'0005'		;ページ操作ビットは5bit目
PORTB	EQU	H'0006'		;ポートBは6番地
TRISB	EQU	H'0086'		;TRISBは86番地
CNT	EQU	H'0010'		;ワークメモリの利用

	CLRF	PORTB		;PORTBのポートを0にクリア
	BSF	STATUS,RP0	;STATUSの5ビット目を1にする(ページ1に変更)
	CLRF	TRISB		;TRISB=0で、すべてアウトプットに設定
	BCF	STATUS,RP0	;STATUSの5ビット目を0にする(ページ0に変更)
LOOP
	BSF	PORTB,7		;PORTBの7ビット目を1にする
	MOVLW	D'250'		;Wレジスタに250をセット
	MOVWF	CNT		;CNTに250をセット

DLY1	GOTO	$+1		;次の命令へ(クロック数稼ぎ)
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	NOP			;何もしない(クロック数稼ぎ)
	DECFSZ	CNT,1		;CNTが0になったら次の命令をスキップ
	GOTO	DLY1		;DLY1のループ

	BCF	PORTB,7		;PORTBの7ビット目を0にする
	MOVLW	D'250'		;Wレジスタに250をセット
	MOVWF	CNT		;CNTに250をセット

DLY2	GOTO	$+1		;次の命令へ(クロック数稼ぎ)
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	NOP			;何もしない(クロック数稼ぎ)
	DECFSZ	CNT,1		;CNTが0になったら次の命令をスキップ
	GOTO	DLY2		;DLY2のループ

	GOTO	LOOP
	END			;終了
プログラム解説
 
CNT	EQU	H'0010'

ワークメモリのアドレスは(ページ0の)H'000C'からH'004F'までです。 変数などを用いたい場合に利用します。 ここでは切りが良いのでH'0010'を使いました。


LOOP

これはラベルといい、 この行に名前を付けるために使います。 つまり、以後「LOOP」はこの行のことをあらわします。 GOTO文の移動先として指定しています。


	MOVLW	D'250'

MOVLWは指定した値をWレジスタに読み込みます。 値は1バイト(8Bit)で指定します。 ここでは10進数250を指定しています。

この値は繰り返しの回数として使います。


	MOVWF	CNT

MOVWFはWレジスタの値を指定したメモリに転送します。 ここでは10進数250をCNTに転送しています。


	GOTO	$+1

GOTOはプログラムの流れを変える働きをします。 指定した行へ移動します。 ここの命令は次の行へ移動するというだけのものです。

GOTOは分岐になるので、2実行クロックを要します。 ここでは、単にクロック数を稼ぐためだけに使っています。


	NOP

何もしません。 タイミングの調節に使います。 1実行クロックを要します。


	DECFSZ	CNT,1

DECFSZは、最後に指定した値が0か1かで演算結果の格納先が異なります。 0ならばWレジスタに、1ならば指定したメモリに格納されます。 ここでは、1が指定されているので、 メモリCNTに格納されることになります。

DECFSZは、指定したメモリの値から1を引き指定したメモリもしくはWレジスタに格納します。 ここでは、最後に指定した値が1ですので、 CNTの値から1を引き、CNTに戻します。 結果が0の場合には次の行をとばします。

この命令は、次の行の命令とともに、 CNTに最初に設定された値だけ(ここでは250)ループをまわすのに利用しています。

演算結果が0でなければ1実行クロックを、 0ならば2実行クロックを要することになります。

 
ループの時間を計算する
 

ループにかかる時間を計算してみましょう。

DLY1	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	GOTO	$+1	2クロック
	NOP		1クロック
	DECFSZ	CNT,1	1クロック
	GOTO	DLY1	2クロック

このループは計20実行クロックを要することが分かります。 CNTは250ですから、このループは250回実行され、 ループを抜けるまでに、
 20X250=5000
実行クロックを要するわけです。 これは、システムクロックが20MHzの場合には、 1mS(0.001秒)に相当します。

 
実行してみる
 

さて、実行してみましょう。

あれ? 点滅せずに、つきっぱなしですね。 1mSでの点滅は人間の目には識別できないのですね。

オシロスコープで見てみると、 確かに1mSごとに点滅を繰り返していることが分かります。

では、0.1Sでの点滅に書き換えてみてください。 次回では、0.1Sでの点滅を、サブルーチンを使って記述してみます。

 
2002/03/08(Sat)
PICのトップページへ
トップページへ
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送