Vol.550 21.Aug.2008
P
PICを使おう(3)−LEDの点滅−
by fjk
LEDを点滅させるために、タイマー0を使ってインターバルタイマーを作製した。ただ点滅させるだけでは面白くないので、前述の回路にスイッチをもう一つ追加(GP2)して、GP4スイッチを押すと点滅が速くなり、GP2スイッチを押すと点滅が遅くなるようにした。なお、今回使用したPICは12Fシリーズで最高の機能を持つPIC12F683(PIC12F675にCCPやPWMがついたもの)を使用した(赤字、特にイタリック体の所の名称が異なっていることに注意)。
スイッチを使う場合チャタリングが発生し、そのままキー状態を読み取ると沢山のキー入力があったように見える。そこで、簡易チャタリング対策として、キーボードが押されたらキーフラグをセットし、点滅用タイマー割り込みでキーフラグを消去するまで、キー入力を無視する方法を用いた。タイマーとキー入力のタイミングが取れていないので完全なチャタリング対策でなないが、一つのカウンタで2つの機能を果たすことが出来る。このように作成したプログラムは以下とおり、
Address Value Source
------ ------ ------------------------------------------------------------
;***************************************************
; PIC12F683 テストプログラム(TM0割り込み、LED点滅)
;***************************************************
list p=12f683 ; 翻訳時にリストファイルを作る
include "p12f683.inc" ; 12F683用定義ファイルを読み込みます
errorlevel -302 ; 翻訳時に302エラーが出ないようにする
002007 3cc4 __CONFIG _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT
radix dec ; 省略時の数値表現を10進数にします。
;---------- CONST ----------
STRCNT equ 0x14 ; ソフトカウンタ初期値
STRTM0 equ 0x1b ; タイマー0の初期値
;---------- RAM AREA ----------
group1 udata_shr ; ここらユーザーメモリの割り当て
w_temp res 1 ; 変数名 res 使用アドレス数
s_temp res 1 ; 順次割り当てていく
tmcnt res 1 ; タイマー用ソフトカウンタ
stime res 1 ; タイマーセット用データ
gpdat res 1 ; キー入力データフラグ
;---------- PROGARAM ----------
vreset code 0 ; code は、「ここからプログラム」の意味
000000 281b goto start
;---------- INTALUPT OPERATION ----------
intope code 4 ; 割り込み処理の開始番地です
000004 00f0 push: movwf w_temp ; Wレジスタを待避
000005 0803 movf STATUS,w ; STATUSレジスタを待避
000006 00f1 movwf s_temp
000007 1d0b btfss INTCON,T0IF ; タイマー0割り込みか?
000008 2816 goto pop ; タイマー0割り込み以外なら何もしない
000009 110b bcf INTCON,T0IF ; タイマー0割り込みフラグをクリア
00000a 300b movlw STRTM0 ; タイマー0の初期値セット
00000b 0081 movwf TMR0 ; TMR0 ← w
00000c 0bf2 decfsz tmcnt,F ; tmcntカウンタを1つ減らす
00000d 2816 goto pop ; ゼロでないなら割り込みから戻る
00000e 01f4 clrf gpdat ; キーフラグをクリア(チャタリング用)
00000f 0873 movf stime,w ; w ← stime
000010 00f2 movwf tmcnt ; tmcnt ← w tmcntに初期値セット
000011 1e85 btfss GPIO,GP5 ; GP5=1?、消灯中なら次命令をskip
000012 2815 goto ledoff ; GP5=0 ならLED消灯へ
ledon:
000013 1285 bcf GPIO,GP5 ; GPIOレジスタの GP5=0(LED点灯)
000014 2816 goto pop
ledoff:
000015 1685 bsf GPIO,GP5 ; GPIOレジスタの GP5=1(LED消灯)
000016 0871 pop: movf s_temp,w ; コピーしておいたSTATUSレジスタを戻す。
000017 0083 movwf STATUS ;
000018 0ef0 swapf w_temp,f ; wレジスタを元に戻す
000019 0e70 swapf w_temp,w ; フラグの変化がないswap命令を使う
00001a 0009 retfie ; メイン処理に戻る
;---------- MAIN OPERATION ----------
start: ; 電源投入直後の「準備の処理」
00001b 1283 bcf STATUS,RP0 ; バンク0 に切り換える
00001c 0185 clrf GPIO ; 一旦 GPIO を クリア(00000000)
00001d 3007 movlw B'00000111' ; コンパレータ使用しないに設定
00001e 0099 movwf CMCON0 ; CMCON0 ← w
00001f 1683 bsf STATUS,RP0 ; バンク1 に切り換えます
000020 301c movlw B'00011100' ; GP2,3,4 = 入力, GP0,1,5 = 出力 に設定
000021 0085 movwf TRISIO ; TRISO ← w
000022 019f clrf ANSEL ; アナログ入力を使用しない に設定します
000023 3014 movlw B'00010100' ; GP2,4をウィークプルアップ
000024 0095 movwf WPU ; WPU ← w
000025 3007 movlw B'00000111' ; WPU有り、プリスケーラ 1:256
000026 0081 movwf OPTION_REG ; OPTION ← w
000027 1283 bcf STATUS,RP0 ; バンク0 に戻します
000028 3014 movlw STRCNT ; ソフトカウンタの初期値
000029 00f3 movwf stime ; stime ← w
00002a 00f2 movwf tmcnt ; tmcnt ← w
00002b 300b movlw STRTM0 ; タイマー0の初期値
00002c 0081 movwf TMR0 ; TMR0 ← w
00002d 01f4 clrf gpdat ; キーフラグのクリア(チャタリング用)
00002e 168b bsf INTCON,T0IE ; タイマー0割り込み許可
00002f 178b bsf INTCON,GIE ; グローバル割り込み許可
main:
000030 1a05 ckgp4: btfsc GPIO,GP4 ; GP4キーが押されたか?
000031 2839 goto ckgp2 ; 押されていないならckgp2へ
000032 1a74 btfsc gpdat,GP4 ; GP4キーフラグonか?
000033 2830 goto main ; チャタリング待ち中なら何もしない
000034 1674 bsf gpdat,GP4 ; GP4フラグをセット
000035 0bf3 decfsz stime,F ; カウントセット値を1つ減らす
000036 2830 goto main ; 0でなければmainへ
000037 3001 movlw 1 ; 最低値は1
000038 00f3 movwf stime ; stime ← w
ckgp2:
000039 1905 btfsc GPIO,GP2 ; GP2キーが押されたか?
00003a 2830 goto main ; 押されてないならmainへ
00003b 1974 btfsc gpdat,GP2 ; GP2キーフラグがonか?
00003c 2830 goto main ; チャタリング待ち中なら何もしない
00003d 1574 bsf gpdat,GP2 ; GP2フラグをセット
00003e 0ff3 incfsz stime,F ; カウントセット値を1つ増やす
00003f 2830 goto main ; オーバフローでなければmainへ
000040 30ff movlw 0FFH ; 最大値は256 (0xFF)
000041 00f3 movwf stime ; stime ← w
000042 2830 goto main ; 割り込みを待つループ
END ; プログラムの終了