list p=16f877a ; PIC16F877A用のプログラムであることを宣言 #include p16f877a.inc ; PIC16F877A用のヘッダ・ファイルを読み込む __config _HS_OSC & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF PORTB_OLD equ 0x20 DARK_TH equ 0x21 ADRES_ equ 0x22 MYTIMER equ 0x23 PCLATH_TEMP equ 0x7d W_TEMP equ 0x7e STATUS_TEMP equ 0x7f org 0x0 goto start org 0x4 ;; レジスタの退避 movwf W_TEMP ; wレジスタを一時レジスタへ swapF STATUS,W ; STATUSレジスタをwへ clrf STATUS ; バンク0にする movwf STATUS_TEMP ; コピーしたSTATUSレジスタを一時レジスタへ movfw PCLATH ; PCLATHを保存する movwf PCLATH_TEMP clrf PCLATH ; PCLATHで指定するページも0にする ;; ここから割り込み処理 ;; 割り込み要因のチェック btfss INTCON, TMR0IF ; タイマ0割り込みかチェック goto INT_NEXT1 ; タイマ0割り込みの処理 bcf INTCON, TMR0IF ; 割り込みフラグを消す movlw D'61' addwf TMR0, f ; 次回のタイマ割り込みのタイミングを決める ;; 20[ms] タイマ decf MYTIMER, f ; ;; A-D変換する bsf ADCON0, GO ; A-D変換開始 btfsc ADCON0, GO ; A-D変換終了まで待つ goto $-1 movfw ADRESH ; 変換結果をADRES_へコピー movwf ADRES_ ;; スイッチのチェック movfw PORTB ; 時刻tのスイッチの状態をwへ andlw B'00000001' ; スイッチのついているビットだけ取り出す xorwf PORTB_OLD, f ; 排他的論理輪をとりスイッチの状態が ; 変わったかチェックする(wは変化しない) ; 変化がないなら0になる movwf PORTB_OLD ; w (時刻tのスイッチの状態)を代入(zは変化しない) btfsc STATUS, Z ; 0かチェック goto INT_TMR0_chk01 ; 0なので変化していない ;; スイッチ0か1のどちらが押されたかチェック btfsc PORTB_OLD, 0 ; スイッチ0が0かどうかをチェック goto INT_TMR0_chk01 ; 0なので変化していない ;; スイッチ0が押された movfw ADRESH movwf DARK_TH INT_TMR0_chk01 INT_NEXT1 ;; ほかの割り込み要因があればチェックする ;; レジスタの復帰 movfw PCLATH_TEMP ; PCLATHを戻す movwf PCLATH ; swapf STATUS_TEMP,W ; STATUSレジスタをwへ movwf STATUS ; STAUTSレジスタを戻す ; バンクも元に戻る SWAPF W_TEMP,F ; swapを2回行うことでwレジスタを戻す SWAPF W_TEMP,W ; これはSTATUSレジスタに影響させないため retfie ; 割り込みからの復帰 start: ; 初期設定をする bcf STATUS, RP0 ; この2行でバンク0にする bcf STATUS, RP1 clrf INTCON ; 割り込み禁止 clrf PORTC ; LEDが点灯しないように0に clrf PORTD ; 出力は0にしておく clrf PORTE ; 出力は0にしておく movlw B'01000001' ; A-Dコンバータの設定(ADCON0) movwf ADCON0 bsf STATUS, RP0 ; バンク1にする movlw 0xff movwf TRISB ; ポートBはディジタル入力 movlw B'00000111' ; PORTBのウィーク・プルアップを有効に ; プリスケーラはタイマに割り当て ; プリスケーラは1/256にする movwf OPTION_REG clrf TRISC ; 全ピン出力に clrf TRISD ; 全ピン出力に movlw B'01000000' ; A-Dコンバータの設定(ADCON1) movwf ADCON1 bcf STATUS, RP0 ; バンク0にする movlw B'00100000' ; LED0は消灯、LED1は点灯 movwf PORTC ; movfw PORTB andlw B'00000011' ; スイッチのついているビットだけ取り出す movwf PORTB_OLD ; 直前のPORTBの値として覚えておく movlw 0xff movwf DARK_TH ; 初期値は真っ暗でないと反応しない clrf ADRES_ ; 変換結果は点滅しないよう明るいことにしておく movlw D'61' movwf TMR0 ; 最初のタイマ割り込みは20[ms]後にかかる ; 初期設定は終了 ; 割り込みを有効にする movlw B'11100000' ; GIE、PEIE、TMR0IEを1に、TMR0IFを0にする movwf INTCON ; メイン・ルーチン loop movfw ADRES_ ; wに変換結果を代入 subwf DARK_TH, w ; 暗さの閾値と比較をする ; DARK_TH−wの結果が負(Cが0)なら暗い btfsc STATUS, C goto loop ; 明るいので点滅しない ; 点滅の部分 blink_LED movlw B'00100001' ; movwf PORTC ; 点灯 movlw D'25' call delayns ; 25×20[ms]待ち movlw B'00100000' ; movwf PORTC ; 消灯 movlw D'25' call delayns ; 25×20[ms]待ち goto loop ; メイン・ルーチンは、ここまで ;; 20[ms]×wだけ待つためのサブルーチン。wに指定できるのは1から255 delayns: movwf MYTIMER ; MYTIMERにwレジスタの値を代入 ; MYTIMERが0になるまで待つ delayns_lp movf MYTIMER, f ; チェックのための代入 btfss STATUS, Z ; 0になったかチェック goto delayns_lp ; まだ0でない return ; 0になった end リスト5-15 Copyright 2005 Noriaki Mitsunaga