第18週 
;16F877でA/D変換
;A/D入力値をLCD表示器に表示
;*********************************************
        LIST        P=PIC16F877   ;
        INCLUDE     "P16f877.inc" ;標準ヘッダ定義ファイル
        __CONFIG    _HS_OSC & _PWRTE_ON & _WDT_OFF & _LVP_OFF 
 
;*********************************************

TIMCNT  EQU     024H            ;タイマ用カウンタ
TIM2CNT EQU     025H
TIM5CNT EQU     026H
TIM1CNT EQU     027H
LCDDT   EQU     028H            ;LCD表示データ格納
LCDINST EQU     029H            ;LCDインストラクション格納
ADDATA  EQU     02AH            ;AD変換データ格納
BINDATA EQU     02BH            ;ADデータの表示
L100    EQU     02CH            ;100桁表示
L10     EQU     02DH            ;10桁
L1      EQU     02EH            ;1桁
TEMP1   EQU     02FH            ;テンポラリレジスタ(計算用他に使用)
TEMP2   EQU     030H

SBDL    EQU     044H    ;被減算数
SBDH    EQU     045H
SBSL    EQU     046H    ;減算数
SBSH    EQU     047H
SB2BRF  EQU     048H    ;Borrowフラグ
BDBINL  EQU     049H    ;被BCD変換
BDBINH  EQU     04AH
FIG     EQU     04BH    ;桁カウンタ
DGT     EQU     04CH    ;桁数値取得
SBDLR   EQU     04DH    ;減算ルーチン中データ保存
SBDHR   EQU     04EH

D10000  EQU     060H
D1000   EQU     061H
D100    EQU     062H
D10     EQU     063H
D1      EQU     064H
;***********************
;  メインルーチン
;***********************
        ORG     0               ;Reset Start

;*********************************************************
;初期処理
INIT
        BSF     STATUS,RP0      ;バンク1へ切替
        BCF     INTCON,GIE      ;割り込み禁止
        MOVLW   0EH
        MOVWF   ADCON1          ;RA0のみアナログ、ADFM=0(結果左詰)
        MOVLW   07H             ;
        MOVWF   OPTION_REG      ;内部クロック、プリスケーラ1:256
        MOVLW   01H
        MOVWF   TRISA           ;ポートAをRA0入力、他は出力モード設定
        CLRF    TRISB           ;ポートBを出力モードに設定
        MOVLW   80H
        MOVWF   TRISC           ;ポートCをRC7入力、他は出力モードに設定
        CLRF    TRISD           ;ポートDを出力モードに設定
        CLRF    TRISE           ;ポートEを出力モードに設定
        BCF     STATUS,RP0      ;バンク0に戻す
        
        MOVLW   080H            ;A/D OFF
        MOVWF   ADCON0
        

;LCD初期化
        CALL    TIM5            ;まず15msec以上待ち
        CALL    TIM5
        CALL    TIM5
        CALL    TIM5 
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM5            ;4.1msec以上待ち
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM02           ;100μsec以上待ち
        CALL    TIM02
        MOVLW   030H
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをWに
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0

        CALL    TIM02
        CALL    TIM02
        MOVLW   038H            ;Function Set 8ビット 2行 5×7ドット
        CALL    LCDCMD
        MOVLW   01H             ;表示クリア
        CALL    LCDCMD        
        MOVLW   06H             ;エントリーモード                
        CALL    LCDCMD
        MOVLW   0CH             ;表示ON
        CALL    LCDCMD

        CALL    LCDCLR          ;表示クリア
        MOVLW   0C3H            ;テ
        CALL    LCDDTW
        MOVLW   0DEH            ;゛
        CALL    LCDDTW
        MOVLW   0DDH            ;ン
        CALL    LCDDTW
        MOVLW   0B1H            ;ア
        CALL    LCDDTW
        MOVLW   0C2H            ;ツ
        CALL    LCDDTW

MAIN        
;A/D変換
ADSTART 


        MOVLW   081H            ;Fosc/32,ch0,A/D on
        MOVWF   ADCON0          ;
        CALL    TIM20           ;20μsec待ち
        BSF     ADCON0,GO       ;A/Dスタート
WAITE
        BTFSC   ADCON0,GO
        GOTO    WAITE
        MOVF    ADRESH,W        ;A/Dデータ上位(ADFM=0でデータは左詰め)
        MOVWF   TEMP1
        BSF     STATUS,RP0      ;バンク1へ切替
        MOVF    ADRESL,W
        BCF     STATUS,RP0      ;バンク0に戻す
        MOVWF   TEMP2
        BCF     STATUS,C        ;Cフラグクリア
        RLF     TEMP2,W         ;下位データ最上位桁をCフラグへ
                                ;下位(表示は9ビットのみ使用)
        RLF     TEMP1,W         ;Cフラグを上位桁最下位ビット
        MOVWF   BDBINL
        CLRF    BDBINH
        RLF     BDBINH,F        ;Cフラグを上位へ
        
        BCF     ADCON0,ADON     ;A/D off

        CALL    BD2B

        MOVF    D100,W
        IORLW   030H
        MOVWF   L100
        MOVF    D10,W
        IORLW   030H
        MOVWF   L10
        MOVF    D1,W
        IORLW   030H
        MOVWF   L1
        
DPLY    
        CALL    LCD2L           ;2行目先頭へ
        MOVLW   ' '
        CALL    LCDDTW
        MOVF    L100,W
        CALL    LCDDTW
        MOVLW   '.'
        CALL    LCDDTW
        MOVF    L10,W
        CALL    LCDDTW
        MOVF    L1,W
        CALL    LCDDTW
        MOVLW   'V'
        CALL    LCDDTW

        GOTO    MAIN
        

;***********************
;サブルーチン
;***********************
;***************************************************
;2バイトBCD変換
;被変換数をBDBINH BDBINLに置く
;結果はD10000〜D1に1桁毎に
BD2B
        CLRF    D10000
        CLRF    D1000
        CLRF    D100
        CLRF    D10
        CLRF    D1
        MOVF    BDBINL,W
        MOVWF   SBDL
        MOVF    BDBINH,W
        MOVWF   SBDH
        MOVLW   060H    ;initialize pointer(D10000)
        MOVWF   FSR
        CLRF    FIG     ;桁カウンタ
BD2BL0  CLRF    DGT     ;各桁数値
        
BD2BL1  MOVF    FIG,W
        CALL    TABLEL  ;減算数
        MOVWF   SBSL
        MOVF    FIG,W
        CALL    TABLEH
        MOVWF   SBSH
        
        MOVF    SBDL,W  ;被減算数保存
        MOVWF   SBDLR
        MOVF    SBDH,W
        MOVWF   SBDHR
        
        CALL    SB2B
        
        BTFSC   SB2BRF,0
        GOTO    BD2BL2
        
        INCF    DGT,F
        GOTO    BD2BL1

BD2BL2  MOVF    SBDLR,W  ;保存被減算数復帰
        MOVWF   SBDL
        MOVF    SBDHR,W
        MOVWF   SBDH

        MOVF    DGT,W
        MOVWF   INDF
        INCF    FSR,F
        INCF    FIG,F
        MOVF    FIG,W
        SUBLW   04H     ;最小桁(1)   
        BTFSS   STATUS,Z
        GOTO    BD2BL0
        MOVF    SBDL,W
        MOVWF   D1
        
        RETURN

;***************
;減算数テーブル
;10000、1000、100、10をBINで下位桁、上位桁に分けて置く        
TABLEL  ADDWF   PCL,F
        RETLW   010H    ;10000
        RETLW   0E8H    ;1000
        RETLW   064H    ;100
        RETLW   0AH     ;10
TABLEH  ADDWF   PCL,F
        RETLW   027H    ;10000
        RETLW   03H     ;1000
        RETLW   0H      ;100
        RETLW   0H      ;10


;************************************************************
;2バイト-2バイト
;SBDH_SBDL-SBSH_SBSL=SBDH_SBDL
;条件:結果は正かゼロ 
;負になったらフラグを立てる
SB2B                            
        CLRF    SB2BRF          ;Borrow FLAG クリア
        MOVF    SBSL,W          ;!!!!!!!!!!!!!!!!!!!!!!!!!
        SUBWF   SBDL,F          ;SBDL-SBSL
        BTFSC   STATUS,C        ;Borrowなら(C=0)スキップ
        GOTO    SB2BLP
        MOVLW   01H
        SUBWF   SBDH,F
        BTFSS   STATUS,C        ;Borrowなければ(C=1)スキップ
        GOTO    SB2BBR          ;Borrow
SB2BLP  MOVF    SBSH,W
        SUBWF   SBDH,F
        BTFSS   STATUS,C        ;Borrow****(C=1)スキップ
        GOTO    SB2BBR                         
        RETURN          
SB2BBR  BSF     SB2BRF,0        ;Borrowフラグ
        RETURN

;************************************************************
;LCDデータ書き込み
LCDDTW                          ;Wに書き込まれたデータ(1文字)を表示
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをW
        BSF     PORTE,2         ;RSをデータに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        CALL    LCDBUSY         ;BUSYチェック
        RETURN

LCDCMD                          ;LCDインストラクション書き込み
                                ;Wレジスタに書き込まれたコマンドをLCDへ
        MOVWF   PORTB
        BCF     PORTE,1         ;R/WをW
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        CALL    LCDBUSY         ;BUSYチェック
        RETURN

LCDCLR                          ;LCD表示クリア
        MOVLW   01H
        CALL    LCDCMD
        RETURN
LCD2L                           ;2行目へ
;◎データシートによると1行目と2行目はアドレスが連続していないで
;2行目の第1文字目は40(H)番地らしい
;(b'1*******'が表示アドレス書き込み  *******を1000000として2行目先頭指令)
        MOVLW   0C0H
        CALL    LCDCMD
        RETURN

LCDBUSY                         ;LCD BUSYチェック
                                ;やっかいなことにいちいちPORTBを入力に変えて
                                ;さらにOPTIONレジスタで弱プルアップに設定
        BSF     STATUS,RP0      ;バンク1へ切替
        MOVLW   0FFH            ;ポートBを入力モードに設定
        MOVWF   TRISB
        BCF     STATUS,RP0      ;バンク0に戻す
        BCF     PORTE,2         ;RSをインストラクションに
        BSF     PORTE,1         ;R/WをR
        BSF     PORTE,0         ;E
        NOP
        BCF     PORTE,0
        MOVF    PORTB,W
        MOVWF   LCDINST
        BTFSC   LCDINST,7       ;BUSYフラグチェック
        GOTO    LCDBUSY

        BCF     PORTE,1         ;R/WをWに戻しておく
        BSF     STATUS,RP0      ;バンク1へ切替
        CLRF    TRISB           ;ポートBを出力モードに設定
        BCF     STATUS,RP0      ;バンク0に戻す
        RETURN

;************************************************************
;タイマ
TIM20                           ;約20μSECタイマ
        MOVLW   012H
        MOVWF   TIMCNT
TIMLP   
        DECFSZ  TIMCNT,F
        GOTO    TIMLP
        RETURN
TIM02                           ;約0.2mSECタイマ
        MOVLW   0FFH
        MOVWF   TIM2CNT
TIM2LP  NOP
        DECFSZ  TIM2CNT,F
        GOTO    TIM2LP
        RETURN
TIM5                            ;約5msecタイマ
        MOVLW   01AH
        MOVWF   TIM5CNT
TIM5LP  CALL    TIM02
        DECFSZ  TIM5CNT,F
        GOTO    TIM5LP
        RETURN

;*********************************************************

        END