目次>8章.機能が豊富なPICを使う(PIC16F88)>(5)温度計に仕上げる>ソース
温度計に仕上げる(ソース)
更新日2008.3.29
以下のソースを取り込んで、アセンブル→PIC書き込み→実行して下さい。
; ========================== ここから ============================== ; PIC16F88 ; clock:INTRC 8MHz ; ; AN4の温度センサ出力をA/D変換し、PORTBの7セグメントLEDに ; 結果を99.9で表示する ; ; RB0-6 :7セグメントLED(A〜G) ; RA7 :7セグメントLED(DP) ; RA0 :2SC1815(7セグ#1の選択) ; RA1 :2SC1815(7セグ#2の選択) ; RA2 :2SC1815(7セグ#3の選択) ; ; RA3(Vref+) :LM336-2.5(2.5V基準電圧) ; RA4(AN4) :LM35D(温度センサ) ; RA5 :Cds ; RA6 :上記3つの電源 ; ; RB7 :NaPiOn (ピン変化割込みでSLEEP時でも検出) ; ; 7セグの配置 888 ; 7セグの番号 321 右から順番 LIST P=16F88 #INCLUDE P16F88.INC __CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _MCLR_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_IO & _LVP_OFF & _CPD_OFF & _DEBUG_OFF CBLOCK 020h timer ;bit0:50μS ,1:0.5mS ,2:3mS ,3:5mS ,4:1S ,5:5S CNT05mS ;0.5mSカウンタ= 10 (50uS×10=0.5mS) CNT3mS ;3mSカウンタ= 60(50uS×60 =3mS) CNT5mS ;5mSカウンタ= 96(50uS×100=5mS) CNT1S ;1Sカウンタ =200(5mS×200=1S) CNT5S ;5Sカウンタ = 5 (1S×5=5S) ADsaveH ;ADRESH保存 ADsaveL ;ADRESL保存 ADsaveH1 ;ADRESH保存 ADsaveL1 ;ADRESL保存 ADsaveH2 ;ADRESH保存 ADsaveL2 ;ADRESL保存 ADsaveH3 ;ADRESH保存 ADsaveL3 ;ADRESL保存 ADsaveH4 ;ADRESH保存 ADsaveL4 ;ADRESL保存 ADsaveH5 ;ADRESH保存 ADsaveL5 ;ADRESL保存 sel7seg ;7セグメントLED選択 PORTA_wk ;7セグメントLED選択のワーク binH ;BCD変換の上位バイト binL ;BCD変換の下位バイト BCD3 ;BCD変換結果(百の位) BCD2 ;BCD変換結果(十の位) BCD1 ;BCD変換結果(一の位) BCDwk1 ;BCD変換用ワーク BCDwk2 ;BCD変換用ワーク ENDC CBLOCK 070h ;common register save_st ;STATUSのセーブ save_w ;W-regのセーブ ENDC f_t50u EQU 0 ;timer bit0:50μSフラグ f_t05mS EQU 1 ;timer bit1:0.5mSフラグ f_t3mS EQU 2 ;timer bit2:3mSフラグ f_t5mS EQU 3 ;timer bit3:5mSフラグ f_t1S EQU 4 ;timer bit4:1Sフラグ f_t5S EQU 5 ;timer bit5:5Sフラグ ORG 0 ;リセットの入口 GOTO init ; ----------------------------------------------------- ; TMR0割り込み処理 ; clock 8MHz ; TMR0 100 ; プリスケーラ なし ; 割込み周期 50uS ORG 4 ;割込みの入口 intr MOVWF save_w ;W-regセーブ SWAPF STATUS,W MOVWF save_st ;STATUSセーブ BCF STATUS,RP0 ;■バンク0に切替え BTFSS INTCON,TMR0IF ;TMR0割込み? GOTO RBint ; No BCF INTCON,TMR0IF ;割込みフラグクリア MOVLW d'255'-d'100'+d'10' MOVWF TMR0 ;TMR0セット(0.5μS*1*100=50μS) BSF timer,f_t50u ;50μS割込みフラグセット DECFSZ CNT05mS,F ;0.5mS経過? GOTO intr5 ; No MOVLW d'10' MOVWF CNT05mS BSF timer,f_t05mS ;0.5mS経過フラグセット intr5 DECFSZ CNT3mS,F ;3mS経過? GOTO intr6 ; No MOVLW d'60' MOVWF CNT3mS BSF timer,f_t3mS ;3mS経過フラグセット intr6 DECFSZ CNT5mS,F ;5mS経過? GOTO intr9 ; No MOVLW d'96' MOVWF CNT5mS BSF timer,f_t5mS ;5mS経過フラグセット DECFSZ CNT1S,F ;1S経過? GOTO intr9 ; No MOVLW d'200' MOVWF CNT1S BSF timer,f_t1S ;1S経過フラグセット DECFSZ CNT5S,F ;10S経過? GOTO intr9 ; No MOVLW d'5' MOVWF CNT5S BSF timer,f_t5S ;5S経過フラグセット GOTO intr9 ; ; PORTBピン変化割り込み処理 RBint BTFSS PORTB,7 GOTO RBint9 MOVLW d'5' MOVWF CNT5S RBint9 BCF INTCON,RBIF intr9 SWAPF save_st,W MOVWF STATUS ;STATUSロード SWAPF save_w,F SWAPF save_w,W ;W-regロード RETFIE ;割込み許可リターン ; ----------------------------------------------------- ; 初期処理 init CLRF timer ;タイマー関連初期化 MOVLW d'10' MOVWF CNT05mS MOVLW d'60' MOVWF CNT3mS MOVLW d'96' MOVWF CNT5mS MOVLW d'200' MOVWF CNT1S MOVLW d'5' MOVWF CNT5S MOVLW 04h ;7セグ選択ビット初期化 MOVWF sel7seg BSF STATUS,RP0 ;■バンク1に切替え MOVLW 070h MOVWF OSCCON ;CLOCK=8MHz MOVLW 038h MOVWF TRISA ;RA0-2,6-7は出力 MOVLW 080h MOVWF TRISB ;RB0-6は出力,RB7は入力 MOVLW 88h ;TMR0プリスケーラ未使用 MOVWF OPTION_REG ;プリセットカウンタへ出力 BCF STATUS,RP0 ;■バンク0に切替え CLRF PORTB MOVLW 040h MOVWF PORTA MOVLW d'255'-d'100'+d'10' MOVWF TMR0 ;TMR0セット(0.5μS*1*100=50μS) BSF INTCON,TMR0IE ;タイマ割込み許可 BSF INTCON,RBIE ;ピン変化割込み許可 BSF INTCON,GIE ;全体割込み許可 ; <A/D設定> MOVLW 061h MOVWF ADCON0 ;16Tosc,CH4,ADON BSF STATUS,RP0 ;■バンク1に切替え MOVLW 0E0h MOVWF ADCON1 ;右詰め , Vref+:RA3/Vref+ , Vref-:Vss MOVLW 10h MOVWF ANSEL ;AN4使用 BCF STATUS,RP0 ;■バンク0に切替え ; ----------------------------------------------------- ; メイン処理 main MOVLW d'255'-d'100'+d'10' ;カウント値ロード MOVWF TMR0 ;TMR0へ出力(0.5μS*1*100=50μS) BCF timer,f_t50u ;50μS割込みフラグOFF main1 BTFSS timer,f_t50u ;50μS経過?(アクイジション経過?) GOTO main4 ; NO BCF timer,f_t50u ;50μS経過フラグクリア BSF ADCON0,GO ;AD変換開始 main2 BTFSC ADCON0,GO ;AD変換完了? GOTO main2 ; NO MOVF ADRESH,W ;AD変換結果の退避 MOVWF ADsaveH1 BSF STATUS,RP0 ;■バンク1に切替え MOVF ADRESL,W BCF STATUS,RP0 ;■バンク0に切替え MOVWF ADsaveL1 CALL ADave ;AD変換結果の平均化 CALL bin2BCD ;ADsaveH・ADsaveLをBCD変換 main4 BTFSC timer,f_t3mS ;3mS経過?(7セグon時間経過?) GOTO main51 ; No main5 BTFSS PORTA,5 ;Cds(暗い?) GOTO main6 ; No BTFSS timer,f_t05mS ;0.5mS経過?(7セグon時間経過?) GOTO main6 ; No main51 MOVLW 0F8h ;RA0-2をoff(7セグ3個共off) ANDWF PORTA,F main6 BTFSS timer,f_t5mS ;5mS経過?(7セグ切り替え) GOTO main7 ; No CALL chg7seg ; Yes BCF timer,f_t5mS ;5mS経過フラグクリア(7セグ切り替え) MOVLW d'10' MOVWF CNT05mS ;0.5mSカウンタ初期化 MOVLW d'60' MOVWF CNT3mS ;3mSカウンタ初期化 BCF timer,f_t05mS ;0.5mS経過フラグクリア BCF timer,f_t3mS ;3mS経過フラグクリア main7 BTFSS timer,f_t5S ;5S経過? GOTO main1 ; No CALL goto_bed ; Yes (SLEEPモードへ) BCF timer,f_t5S ;5S経過フラグクリア GOTO main ; ----------------------------------------------------- ; 7セグメントLED表示切り替え chg7seg MOVLW 078h ANDWF PORTA,F ;全7セグ消灯 BCF STATUS,C RRF sel7seg,F ;次の7セグへ BTFSC sel7seg,0 ;7セグ#1? GOTO chg7seg1 ; Yes BTFSC sel7seg,1 ;7セグ#2? GOTO chg7seg2 ; Yes MOVLW 04h MOVWF sel7seg GOTO chg7seg3 ;7セグ#3 chg7seg1 ; BTFSC PORTB,7 ; BSF PORTA,7 ;NaPiOnの状態を小数点で表示 MOVF BCD1,W GOTO chg7seg9 chg7seg2 BSF PORTA,7 ;小数点を表示 MOVF BCD2,W GOTO chg7seg9 chg7seg3 MOVF BCD3,W BTFSC STATUS,Z ;0? GOTO chg7segX ; Yes chg7seg9 CALL bcd2led ;7セグ表示用10進数に変換 MOVWF PORTB MOVF sel7seg,W IORWF PORTA,F ;7セグ表示 chg7segX RETURN ; ----------------------------------------------------- ; BCD4ビットを7セグメントLED表示用10進数に変換 bcd2led ADDWF PCL,F RETLW 03Fh ;0 RETLW 006h ;1 RETLW 05Bh ;2 RETLW 04Fh ;3 RETLW 066h ;4 RETLW 06Dh ;5 RETLW 07Dh ;6 RETLW 007h ;7 RETLW 07Fh ;8 RETLW 06Fh ;9 RETLW 040h ;a RETLW 040h ;b RETLW 040h ;c RETLW 040h ;d RETLW 040h ;e RETLW 040h ;f ; ----------------------------------------------------- ; バイナリ10ビット(ADsaveH,ADsaveL)をBCDに変換 bin2BCD MOVF ADsaveH,W MOVWF binH MOVF ADsaveL,W MOVWF binL MOVLW 0FFh MOVWF BCD3 ; -1をセット MOVWF BCD2 ; -1をセット ; binLの下位2ビット → BCDwk2 MOVF binL,W ANDLW 03h MOVWF BCDwk2 ; binH・binL ÷ 4 → BCDwk1 ; 下位2ビットは一旦切り捨て(後で復活) BCF STATUS,C RRF binH,F RRF binL,F ; 1/2する BCF STATUS,C RRF binH,F RRF binL,W ; もう一度1/2する(合計1/4)。 MOVWF BCDwk1 ; 百の位(BCD3)を算出 MOVLW d'25' ; 1/4にしたので、25で割れば100の位が計算できる。 bin2BCD3 INCF BCD3,F SUBWF BCDwk1,F BTFSC STATUS,C ; BCDwk1 < 25 (C=0) GOTO bin2BCD3 ADDWF BCDwk1,F ; 十の位(BCD2)を算出 BCF STATUS,C RLF BCDwk1,F ; 2倍する RLF BCDwk1,F ; もう一度2倍する(合計4倍)。前で1/4したものを戻す。 MOVF BCDwk2,W ADDWF BCDwk1,F ; 前で切り捨てた下位2ビットを加算 MOVLW d'10' ; 10で割って10の位を計算。 bin2BCD2 INCF BCD2,F SUBWF BCDwk1,F BTFSC STATUS,C ; BCDwk1 < 10 (C=0) GOTO bin2BCD2 ADDWF BCDwk1,F ; 一の位(BCD1)を算出 MOVF BCDwk1,W MOVWF BCD1 RETURN ; ----------------------------------------------------- ; SLEEPモードに移行 goto_bed BCF INTCON,GIE ; 全割込み禁止 BCF ADCON0,ADON ; A/D off CLRF PORTA ; LM336,LM35D 電源OFF,7セグOFF MOVLW 080h ANDWF PORTB,F ; 7セグOFF BCF INTCON,RBIF ; RBピン変化割込みフラグクリア SLEEP BSF PORTA,6 ; LM336,LM35D 電源ON MOVLW d'5' MOVWF CNT5S ; 5秒カウンタ初期設定 MOVF PORTB,W BCF INTCON,RBIF ; RBピン変化割込みフラグクリア BSF INTCON,GIE ; 全割込み許可 BSF ADCON0,ADON ; A/D on RETURN ; ----------------------------------------------------- ; AD変換結果の平均化 ADave MOVF ADsaveH1,W ADDWF ADsaveH2,F MOVF ADsaveL1,W ADDWF ADsaveL2,F BTFSC STATUS,C INCF ADsaveH2,F BCF STATUS,C RRF ADsaveH2,F RRF ADsaveL2,F MOVF ADsaveH2,W ADDWF ADsaveH3,F MOVF ADsaveL2,W ADDWF ADsaveL3,F BTFSC STATUS,C INCF ADsaveH3,F BCF STATUS,C RRF ADsaveH3,F RRF ADsaveL3,F MOVF ADsaveH3,W ADDWF ADsaveH4,F MOVF ADsaveL3,W ADDWF ADsaveL4,F BTFSC STATUS,C INCF ADsaveH4,F BCF STATUS,C RRF ADsaveH4,F RRF ADsaveL4,F MOVF ADsaveH4,W ADDWF ADsaveH5,F MOVF ADsaveL4,W ADDWF ADsaveL5,F BTFSC STATUS,C INCF ADsaveH5,F BCF STATUS,C RRF ADsaveH5,F RRF ADsaveL5,F MOVF ADsaveH5,W ADDWF ADsaveH,F MOVF ADsaveL5,W ADDWF ADsaveL,F BTFSC STATUS,C INCF ADsaveH,F BCF STATUS,C RRF ADsaveH,F RRF ADsaveL,F RETURN END ; =========================== ここまで ===============================