;16F877でA/D変換
;値によってステッピングモータの周波数を変えて変速
;*********************************************
LIST P=PIC16F877 ;
INCLUDE "P16f877.inc" ;標準ヘッダ定義ファイル
__CONFIG _HS_OSC & _PWRTE_ON & _WDT_OFF & _LVP_OFF
;*********************************************
CNT EQU 020H ;出力パターン用カウンタ
WTEMP EQU 021H ;Wレジスタ待避
STTEMP EQU 022H ;STATUSレジスタ待避
INTTMCT EQU 023H ;割り込みタイマ設定値
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
PCLTEMP EQU 031H
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
GOTO INIT
ORG 04H ;Int
GOTO INTR
;*********************************************************
;初期処理
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 B'10010000' ;初期出力
MOVWF PORTD
MOVLW 0H ;COUNTER初期出力
MOVWF CNT
MOVLW 080H ;A/D OFF
MOVWF ADCON0
MOVLW 01H ;タイマ初期値ロード
MOVWF TMR0 ;
MOVWF INTTMCT ;タイマ値記憶
;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 ;表示クリア
BSF INTCON,T0IE ;TMR0オーバーフロー割り込み発生許可
BSF INTCON,GIE ;割り込み許可
;*********************************
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 INTTMCT ;A/D変換値をTM0値に
MOVWF TEMP1 ;LCD表示値
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 LCD1L ;1行目へ
MOVLW 0C3H ;テ
CALL LCDDTW
MOVLW 0DEH ;゛
CALL LCDDTW
MOVLW 0DDH ;ン
CALL LCDDTW
MOVLW 0B1H ;ア
CALL LCDDTW
MOVLW 0C2H ;ツ
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
MOVLW 020H ;
CALL LCDDTW
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
;*********************************************************
;割り込み処理
;
INTR
BCF INTCON,T0IF ;割り込みフラグクリア
MOVWF WTEMP ;レジスタ待避
SWAPF STATUS,W
MOVWF STTEMP
BCF STATUS,RP0 ;バンク0に戻す
;◎メインプログラム中でバンク切り替えをし、かつ割り込みの中で
; STATUSをチェックするので互いに影響を及ぼさないようにここで
; バンク0にしておく
;(復帰についてはレジスタ復帰するので考慮不要)
MOVF INTTMCT,W ;タイマ値ロード
SUBLW 0FAH ;◎タイマ値はFA(5KHz)まで
BTFSC STATUS,C ; タイマ値と比較して小さいならスキップ
GOTO INTDT
MOVLW 0FAH ; 大きいならFAに固定
MOVWF INTTMCT
INTDT MOVF INTTMCT,W
MOVWF TMR0 ;
FWD ;正転カウント処理
MOVF CNT,W
SUBLW 07H
BTFSC STATUS,2
GOTO SET0 ;カウンタ値 7 なら 0 に
INCF CNT,F
GOTO INCED
SET0 MOVLW 0H
MOVWF CNT
INCED
PATTERN
MOVF CNT,W
CALL TABLE
MOVWF PORTD
SWAPF STTEMP,W ;レジスタ復帰
MOVWF STATUS
SWAPF WTEMP,F
SWAPF WTEMP,W
RETFIE
TABLE
ADDWF PCL,F
RETLW B'10010000'
RETLW B'00010000'
RETLW B'00110000'
RETLW B'00100000'
RETLW B'01100000'
RETLW B'01000000'
RETLW B'11000000'
RETLW B'10000000'
;***********************
;サブルーチン
;***********************
;***************************************************
;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
LCD1L ;1行目へ
MOVLW 080H
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