PIC16F84電子遊戯(6)
最終更新日:2001年1月7日
99分タイマー(1ページ)へ (2ページ) (3ページ)へ (4ページ)へ

99分タイマーの7セグメントLED表示
7セグメントLEDの表示は一桁ずつ表示するダイナミック点灯方式です。
LEDのコモンをひとつずつ「L」に落としながら74HC4511にデータを送ります。
簡単な動作手順を説明します。
1秒のデータをRB3-0に出力する RB4を「L」にする 時間待ち RB4を「H」にする
10秒のデータをRB3-0に出力する RB5を「L」にする 時間待ち RB5を「H」にする
1分のデータをRB3-0に出力する RB6を「L」にする 時間待ち RB6を「H」にする
10分のデータをRB3-0に出力する RB7を「L」にする 時間待ち RB7を「H」にする
これをメインルーチンで繰り返すことによりLEDを点灯させます。
時間待ちはループを組んで時間を稼ぎます。
ここで秒と分のデータを記憶するRAMを設定しておきましょう。
sec1_data sec10_data min1_data min10_data
1秒のデータ 10秒のデータ 1分のデータ 10分のデータ
(分と秒のRAM定義)
ついでに表示の時間待ちで使用するRAMも設定しておきましょう。
ここに初期値FFHを入れてこれをひとつずつ減らしゼロになるまで時間を待ちます。
時間待ちには色んな方法が考えられますが、とりあえず簡単な方法としました。
初期値FFHを変えることにより待ち時間を変えることが出来ます。
wait_data
時間待ち
(wait_data)
ここまでで一度テストプログラムを考えます。
目的は7セグメントLED表示部分、1秒ごとのカウント部分、タイマーの減算部分の確認をします。
電源を入れると「99分00秒」からスタートしてどんどん時間表示が1秒おきに変化します。
キーなどは効きません。もちろん「00分00秒」とタイムアップしても何も起きません。
こんなに簡単にテストプログラムが組めるのもマイコンがフラッシュのお陰です。
どんどんプログラムが楽しくなって行きますね。
99分タイマーのテストプログラム
ではテストプログラムのソースリストを見ていただきましょう。
;**********************************************************************
;    Filename:	    timer.asm                                     *
;    Date:          2001/1/6                                          *
;    File Version:                                                    *
;**********************************************************************

	list      p=16F84             ; list directive to define processor
	#include <p16F84.inc>         ; processor specific variable definitions

	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

;***** VARIABLE DEFINITIONS
w_temp        EQU     0x0C        ; variable used for context saving 
status_temp   EQU     0x0D        ; variable used for context saving

count_data	EQU	0x10		;1sec keisoku count ram
sec1_data	EQU	0x11		;1sec LED data ram
sec10_data	EQU	0x12		;10sec LED data ram
min1_data	EQU	0x13		;1min LED data ram
min10_data	EQU	0x14		;10min LED data ram
wait_data	EQU	0x15		;wait data ram

tm0_setdata	EQU	63h		;255-156=99=63H  156*128=19.968msec
cnt_setdata	EQU	32h		;19.968*50=0.9984sec
;**********************************************************************
		ORG     0x000             ; processor reset vector
  		goto    main              ; go to beginning of program


		ORG     0x004             ; interrupt vector location
		movwf   w_temp            ; save off current W register contents
		movf	STATUS,w          ; move status register into W register
		movwf	status_temp       ; save off contents of STATUS register

		;---------------------------------	
		bcf	INTCON,T0IF
		movlw	tm0_setdata
		movwf	TMR0

		decfsz	count_data,1
		goto	next_int
time_up		movlw	cnt_setdata		
		movwf	count_data
		
		movlw	01h
		subwf	sec1_data,1
		btfsc	STATUS,0
		goto	next_int
		movlw	09h
		movwf	sec1_data

		
		movlw	01h
		subwf	sec10_data,1
		btfsc	STATUS,0
		goto	next_int
		movlw	05h
		movwf	sec10_data

		movlw	01h
		subwf	min1_data,1
		btfsc	STATUS,0
		goto	next_int
		movlw	09h
		movwf	min1_data

		movlw	01h
		subwf	min10_data,1
		btfsc	STATUS,0
		goto	next_int
		movlw	09h
		movwf	min10_data

next_int

		nop
		;----------------------------------

		movf    status_temp,w     ; retrieve copy of STATUS register
		movwf	STATUS            ; restore pre-isr STATUS register contents
		swapf   w_temp,f
		swapf   w_temp,w          ; restore pre-isr W register contents
		retfie                    ; return from interrupt

main
		call	port_set
		movlw	00h
		movwf	PORTA
		movlw	0f0h
		movwf	PORTB

		call	timer0_set
		movlw	cnt_setdata		
		movwf	count_data
		movlw	00h
		movwf	sec1_data
		movwf	sec10_data
		movlw	09h			;test data
		movwf	min1_data
		movwf	min10_data

main_loop
		;----------------------- led7_disp
		movf	sec1_data,0
		iorlw	0f0h
		movwf	PORTB
		bcf	PORTB,4
		call	wait_1
		bsf	PORTB,4

		movf	sec10_data,0
		iorlw	0f0h
		movwf	PORTB
		bcf	PORTB,5
		call	wait_1
		bsf	PORTB,5		

		movf	min1_data,0
		iorlw	0f0h
		movwf	PORTB
		bcf	PORTB,6
		call	wait_1
		bsf	PORTB,6

		movf	min10_data,0
		iorlw	0f0h
		movwf	PORTB
		bcf	PORTB,7
		call	wait_1
		bsf	PORTB,7
		;-----------------------
		goto	main_loop

wait_1		
		movlw	0ffh
		movwf	wait_data
wait_2
		decfsz	wait_data,1
		goto	wait_2
		return

port_set
			;RA0,RA1(OUT)
			;RA2,RA3,RA4(IN)
			;RB0,RB1,RB2,RB3,RB4,RB5,RB6,RB7(OUT)
		bsf	STATUS,RP0
		clrf	TRISA
		bsf	TRISA,3
		nop
		bsf	TRISA,4
		nop
		bsf	TRISA,2	
		clrf	TRISB
		bcf	STATUS,RP0
		return

timer0_set

		bsf	STATUS,RP0
		movlw	086h		;(1)PORTB NOT PULLUP
					;(0)INTEDG
					;(0)TOCS
					;(0)TOSE
					;(0)PSA
					;(110)1/128
		movwf	OPTION_REG
		bcf	STATUS,RP0
		
		movlw	tm0_setdata
		movwf	TMR0
		bsf	INTCON,T0IE
		bsf	INTCON,GIE
		return

		END                     ; directive 'end of program'
赤色で表示されている部分はテストボードのページと今までの説明で理解出来ると思います。青い部分について詳しく説明します。
99分タイマーの1秒減算ルーチン
movlw 01h
subwf sec1_data,1
btfsc STATUS,0
goto next_int
movlw 09h
movwf sec1_data
割り込みルーチンのtime_upのところを1秒ごとに通過します。
その後の部分ですので、1秒のデータの入っているRAMから1を引くことになります。
具体的にはW(ワーキングレジスタ)に1を入れて
sec1_dataから引いて、sec1_dataに戻します。
その後、C(キャリービット)を調べて、0以上のときはそのまま抜けます。
(goto next_int)
0より小さくなれば、
sec1_dataに9を入れて次の桁の計算に行きます。
同様に繰り下がりがあれば10秒、1分、10分の計算をします。
99分タイマーの1秒表示ルーチン
movf sec1_data,0
orlw 0f0h
movwf PORTB
bcf PORTB,4
call wait_1
bsf PORTB,4
1秒のデータをWレジスタに読み出します。
上位の4ビットはデータ的には無効なのでマスクします。(7セグのコモンを全てHにする役目もあります。)
WレジスタをポートBに出力します。1秒の桁の7セグのコモンをアクティブにします。
時間待ちをします。7セグのコモンをもとに戻します。
これが一桁ぶんです。あとは10秒、1分、10分と桁を変えながら順次表示して行きます。
99分タイマーの時間待ち
wait_1
movlw 0ffh
movwf wait_data
wait_2
decfsz wait_data,1
goto wait_2
return
Wレジスタに255(FFH)を入れます。このデータをwait_dataに入れます。
このデータをひとつずつ減算し0になるまで、ループします。
約770usecのウエイトだと思います。(計算間違ってます?)
99分タイマーのテストプログラムの動作の様子
ここまでで一度動かして確認してみましょう。
どうですか、1秒ごとに表示が変化したでしょう。
実測すれば、セラミック発振子のばらつきにもよりますが10分で約2秒程度のずれでした。いかがなものでしょうか。(これで充分ですね?)
(テストプログラムが走っております)
かなり量が多くなったので、この続きは次回としましょう。
これからもどんどん楽しくなる「PIC16F84電子遊戯」をよろしく。
この続きは(3ページ)へ

不明点などあればメールお願いいたします。nonchansoft@nifty.com

Copyright(c)2000-2001 nonchansoft