;************************************************************
;LM35DZ for PIC16F88
;************************************************************
LIST P=16F88
INCLUDE P16F88.INC
__CONFIG _CONFIG1, _WDT_OFF & _BODEN_ON & _PWRTE_ON & _INTRC_IO & _LVP_OFF
__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
;------------タイマーループ用固定変数----------------
GPR1 EQU 20h ;400usを生成
GPR2 EQU 21h ;100msを生成
GPR3 EQU 22h ;500msを生成
GPR4 EQU 23h ;10msを生成
;------------LCD用固定変数----------------------
LCDINST EQU 2Bh ;LCDインストラクション格納
TMP1 EQU 2Ch ;ADRESL値の格納
TMP2 EQU 2Dh ;ADREDH値の格納
TMPWK EQU 2Eh ;計算変数
TMPWK2 EQU 2Fh ;計算変数
TMPWK3 EQU 30h ;計算変数
CNT EQU 31h ;計算回数カウンター
TMP163 EQU 32h ;16進表記用3桁目
TMP162 EQU 33h ;16進表記用2桁目
TMP161 EQU 34h ;16進表記用1桁目
TMP104 EQU 35h ;10進表記用4桁目
TMP103 EQU 36h ;10進表記用3桁目
TMP102 EQU 37h ;10進表記用2桁目
TMP101 EQU 38h ;10進表記用1桁目
TMP103W EQU 39h ;10進表記用3桁目ワーク
TMP102W EQU 3Ah ;10進表記用2桁目ワーク
TMP101W EQU 3Bh ;10進表記用1桁目ワーク
TMP210 EQU 3Ch ;2進アスキー表記用10桁目
TMP209 EQU 3Dh ;2進アスキー表記用9桁目
TMP208 EQU 3Eh ;2進アスキー表記用8桁目
TMP207 EQU 3Fh ;2進アスキー表記用7桁目
TMP206 EQU 40h ;2進アスキー表記用6桁目
TMP205 EQU 41h ;2進アスキー表記用5桁目
TMP204 EQU 42h ;2進アスキー表記用4桁目
TMP203 EQU 43h ;2進アスキー表記用3桁目
TMP202 EQU 44h ;2進アスキー表記用2桁目
TMP201 EQU 45h ;2進アスキー表記用1桁目
DMY EQU 50h ;汎用変数
KURIKOSHI EQU 51h ;繰越変数
ORG 0
CALL INI
MAIN
MOVLW 002h ;LCDインストラクション(カーソルホーム)
CALL LCDIni2 ;LCDへ書き込み
BSF PORTA,4 ;LED ON
BSF ADCON0,GO ;AD変換。取得開始
MAIN2
CALL Timer100 ;でも実際には取得が速すぎてLEDが光らないので0.1秒休憩
BTFSC ADCON0,GO ;AD変換。値セット完了?
GOTO MAIN2 ;まだなら完了待ち
BCF PORTA,4 ;LED OFF
MOVF ADRESH,W ;9-10bit目を
MOVWF TMP2 ;TMP2に代入する
BSF STATUS,RP0 ;
MOVF ADRESL,W ;1-8bit目を
BCF STATUS,RP0 ;
MOVWF TMP1 ;TMP1に代入する。BANK1内では処理無効!
; MOVLW B'00000011' ;デバッグ用
; MOVWF TMP2 ;デバッグ用
;--------ADRESHをアスキーコードに変換する------------------------------
MOVF TMP2,W ;変換元の数値を
MOVWF TMPWK ;TMPWORKに代入して加工準備をする
;--------2bit目ASCII化開始--------------
MOVLW 1h ;右シフトする回数を
MOVWF CNT ;指定する
MOVLW B'00000010' ;マスクする値をWへ代入する
CALL BtoASCII
MOVWF TMP210 ;10bit目として変数にセットする
;--------2bit目Decimal化開始-------------
SUBLW 31h ;Wにはすでに+30hしたTMP210が入っているので、31h-TMP210
BTFSS STATUS,Z ;Z=1 ⇒ ビットが立っていたら次スキップ
GOTO BtoD210END ;2bit目=0という事になるので無視して次ステップへ
MOVLW 5h ;2bit目=1という事になるので512(10)をそれぞれ格納する
MOVWF TMP103
MOVLW 1h
MOVWF TMP102
MOVLW 2h
MOVWF TMP101
BtoD210END
;--------1bit目ASCII化開始--------------
MOVLW B'00000001'
ANDWF TMPWK,W ;1bit目の場合はシフトさせないので
MOVWF TMPWK3
MOVLW 30h ;そのまま代入する。
IORWF TMPWK3,W
MOVWF TMP209 ;9bit目として変数にセットする
;--------1bit目Decimal化開始--------------
MOVF TMP209,W
SUBLW 31h
BTFSS STATUS,Z
GOTO BtoD209END
MOVLW 2h
MOVWF TMP103W ;1bit目=1という事になるので256(10)をワーク領域に格納する
MOVLW 5h
MOVWF TMP102W
MOVLW 6h
MOVWF TMP101W
;--------Decimalを合計する--------------
CALL TOTAL101
CALL TOTAL102
CALL TOTAL103
CALL TOTAL104
BtoD209END
; MOVLW B'11111111' ;デバッグ用
; MOVWF TMP1 ;デバッグ用
;--------ADRESLをアスキーコードに変換する------------------------------
MOVF TMP1,W ;変換元の数値を
MOVWF TMPWK ;TMPWORKに代入して加工準備をする
;--------8bit目--------------
MOVLW 7h
MOVWF CNT
MOVLW B'10000000'
CALL BtoASCII
MOVWF TMP208
;--------7bit目--------------
MOVLW 6h
MOVWF CNT
MOVLW B'01000000'
CALL BtoASCII
MOVWF TMP207
;--------6bit目--------------
MOVLW 5h
MOVWF CNT
MOVLW B'00100000'
CALL BtoASCII
MOVWF TMP206
;--------5bit目--------------
MOVLW 4h
MOVWF CNT
MOVLW B'00010000'
CALL BtoASCII
MOVWF TMP205
;--------4bit目--------------
MOVLW 3h
MOVWF CNT
MOVLW B'00001000'
CALL BtoASCII
MOVWF TMP204
;--------3bit目--------------
MOVLW 2h
MOVWF CNT
MOVLW B'00000100'
CALL BtoASCII
MOVWF TMP203
;--------2bit目--------------
MOVLW 1h
MOVWF CNT
MOVLW B'00000010'
CALL BtoASCII
MOVWF TMP202
;--------1bit目--------------
MOVLW B'00000001'
ANDWF TMPWK,W ;1bit目の場合はシフトさせないので
MOVWF TMPWK ;そのまま代入する。
MOVLW 30h
IORWF TMPWK,W
MOVWF TMP201
;--------ADRESHを16進数に変換する------------------------------
MOVF TMP2,W ;変換元の数値を
MOVWF TMPWK ;TMPWORKに代入して加工準備をする
MOVLW 0Ah ;10以下なら数字なのでその判定用
SUBWF TMPWK,W ;TMPWK-W < 10 ならSTATUSのC = 1 になる
BTFSS STATUS,C ;10か10以上だったら次スキップ(逆に9以下だったら次実行)
GOTO ADRESH0_9
MOVLW 41h
IORWF TMPWK,W
MOVWF TMP163
GOTO ADRESH_END
ADRESH0_9
MOVLW 30h
IORWF TMPWK,W
MOVWF TMP163 ;ADRESHの値決定
ADRESH_END
; MOVLW B'10011111' ;デバッグ用
; MOVWF TMP1 ;デバッグ用
;--------ADRESLの上位4bitを16進数に変換する------------------------------
MOVLW B'11110000' ;TMP1の上位4bitだけを
ANDWF TMP1,W ;抽出して
MOVWF TMPWK ;TMPWKに代入して
BCF STATUS,C
RRF TMPWK,F ;3回右シフトして
BCF STATUS,C
RRF TMPWK,F ;4bit分だけの値とする
BCF STATUS,C
RRF TMPWK,F
BCF STATUS,C
RRF TMPWK,F ;これで準備完了。
MOVLW 0Ah ;10以下なら数字なのでその判定用
SUBWF TMPWK,W ;TMPWK-W < 10 ならSTATUSのC = 1 になる
BTFSS STATUS,C ;10か10以上だったら次スキップ(逆に10未満だったら次実行)
GOTO ADRESL1_0_9
MOVLW 37h ;10以上だから 'A'=41h に合わせて
ADDWF TMPWK,W ;加算してやる
MOVWF TMP162 ;ADRESLの上位4bitの値決定
GOTO ADRESL1_END
ADRESL1_0_9
MOVLW 30h ;10未満だから単純に30hで
IORWF TMPWK,W ;論理和してやる
MOVWF TMP162 ;ADRESLの上位4bitの値決定
ADRESL1_END
;--------ADRESLの下位4bitを16進数に変換する------------------------------
MOVLW B'00001111' ;TMP1の下位4bitだけを
ANDWF TMP1,W ;抽出して
MOVWF TMPWK ;TMPWKに代入して準備完了。
MOVLW 0Ah ;以下同じ。
SUBWF TMPWK,W
BTFSS STATUS,C
GOTO ADRESL2_0_9
MOVLW 37h
ADDWF TMPWK,W
MOVWF TMP161 ;ADRESLの下位4bitの値決定
GOTO ADRESL2_END
ADRESL2_0_9
MOVLW 30h
IORWF TMPWK,W
MOVWF TMP161 ;ADRESLの下位4bitの値決定
ADRESL2_END
;--------ADRESLを10進数に変換する------------------------------
CLRF TMP103W
CLRF TMP102W
CLRF TMP101W
MOVF TMP1,W
MOVWF TMPWK
LD3ST
MOVLW 64h
SUBWF TMPWK,W
BTFSS STATUS,C
GOTO LD2ST
INCF TMP103W,F
MOVWF TMPWK
GOTO LD3ST
LD2ST
MOVLW 0Ah
SUBWF TMPWK,W
BTFSS STATUS,C
GOTO LD1ST
INCF TMP102W,F
MOVWF TMPWK
GOTO LD2ST
LD1ST
MOVF TMPWK,W
MOVWF TMP101W
;--------Decimalを合計する--------------
CALL TOTAL101
CALL TOTAL102
CALL TOTAL103
CALL TOTAL104
MOVLW 30h
ADDWF TMP104,F
ADDWF TMP103,F
ADDWF TMP102,F
ADDWF TMP101,F
;---------------bit算出終了。ここから表記-------------------------------
;--------2進表記--------------
MOVF TMP210,W
CALL LCDDTW
MOVF TMP209,W
CALL LCDDTW
MOVF TMP208,W
CALL LCDDTW
MOVF TMP207,W
CALL LCDDTW
MOVF TMP206,W
CALL LCDDTW
MOVF TMP205,W
CALL LCDDTW
MOVF TMP204,W
CALL LCDDTW
MOVF TMP203,W
CALL LCDDTW
MOVF TMP202,W
CALL LCDDTW
MOVF TMP201,W
CALL LCDDTW
MOVLW 0C0h ;LCD2行目へ
CALL LCDIni2
;--------16進表記--------------
MOVF TMP163,W
CALL LCDDTW
MOVF TMP162,W
CALL LCDDTW
MOVF TMP161,W
CALL LCDDTW
;--------10進表記--------------
MOVLW 20h ;SPACE
CALL LCDDTW
MOVLW 54h ;T
CALL LCDDTW
MOVLW 4Dh ;M
CALL LCDDTW
MOVLW 50h ;P
CALL LCDDTW
MOVLW 3Dh ;=
CALL LCDDTW
MOVF TMP104,W
CALL LCDDTW
MOVF TMP103,W
CALL LCDDTW
MOVF TMP102,W
CALL LCDDTW
MOVLW 2Eh ;.(小数点)
CALL LCDDTW
MOVF TMP101,W
CALL LCDDTW
MOVLW 20h ;SPACE
CALL LCDDTW
MOVLW 0DFh ;まる
CALL LCDDTW
MOVLW 43h ;C
CALL LCDDTW
CALL INI2
;--------LOOP-------------
GOTO MAIN
;-----------------------------以下サブルーチン----------------------------------
;--------10進数1桁目の加算--------------
TOTAL101
MOVF TMP101,W ;6 6
ADDWF TMP101W,W ;6+2=8 6+9=15
MOVWF TMPWK ;8 15
MOVLW 0Ah ;10
SUBWF TMPWK,W ;10-8=2 (C=1) 10-15=-5 (C=0)
BTFSS STATUS,C ;C=1だったら次スキップ
GOTO TOTAL101a ;>10だからジャンプ
MOVWF TMP101 ;=<10だから1桁目を代入して完成
BSF KURIKOSHI,0 ;繰越値=1
GOTO TOTAL101b
TOTAL101a
MOVF TMPWK,W ;合計値を代入して
MOVWF TMP101 ;1桁目完成
TOTAL101b
RETURN
;--------10進数2桁目の加算--------------
TOTAL102
MOVF TMP102,W ;6 6
ADDWF TMP102W,W ;6+2=8 6+9=15
ADDWF KURIKOSHI,W ;6+2+1=9 6+9+1=16
CLRF KURIKOSHI
MOVWF TMPWK ;9 16
MOVLW 0Ah ;10
SUBWF TMPWK,W ;10-9=1 (C=1) 10-16=-6 (C=0)
BTFSS STATUS,C ;C=1だったら次スキップ
GOTO TOTAL102a ;>10だからジャンプ
MOVWF TMP102 ;=<10だから1桁目を代入して完成
BSF KURIKOSHI,0 ;繰越値=1
GOTO TOTAL102b
TOTAL102a
MOVF TMPWK,W ;合計値を代入して
MOVWF TMP102 ;2桁目完成
TOTAL102b
RETURN
;--------10進数3桁目の加算--------------
TOTAL103
MOVF TMP103,W ;6 6
ADDWF TMP103W,W ;6+2=8 6+9=15
ADDWF KURIKOSHI,W ;6+2+1=9 6+9+1=16
CLRF KURIKOSHI
MOVWF TMPWK ;8 15
MOVLW 0Ah ;10
SUBWF TMPWK,W ;10-8=2 (C=1) 10-15=-5 (C=0)
BTFSS STATUS,C ;C=1だったら次スキップ
GOTO TOTAL103a ;>10だからジャンプ
MOVWF TMP103 ;=<10だから1桁目を代入して完成
BSF KURIKOSHI,0 ;繰越値=1
GOTO TOTAL103b
TOTAL103a
MOVF TMPWK,W ;合計値を代入して
MOVWF TMP103 ;3桁目完成
TOTAL103b
RETURN
;--------10進数4桁目の加算--------------
TOTAL104
MOVF TMP104,W
ADDWF KURIKOSHI,W
MOVWF TMP104
RETURN
;--------2進数→2進数文字にする--------------
BtoASCII
ANDWF TMPWK,W ;変換基数を
MOVWF TMPWK2 ;ワーク変数へ
BtoALoop
BCF STATUS,C
RRF TMPWK2,F ;1回右シフト
DECFSZ CNT,F ;CNT-1
GOTO BtoALoop ;CNT>0ならシフトの繰り返し
MOVLW 30h ;ASCIIコード基数と
IORWF TMPWK2,W ;変換値を論理和してASCIIコードにする
RETURN
;---------------変数初期化--------------------------
INI2
CLRF TMP1
CLRF TMP2
CLRF TMPWK
CLRF TMPWK2
CLRF TMPWK3
CLRF CNT
CLRF TMP163
CLRF TMP162
CLRF TMP161
CLRF TMP104
CLRF TMP103
CLRF TMP102
CLRF TMP101
CLRF TMP103W
CLRF TMP102W
CLRF TMP101W
CLRF TMP210
CLRF TMP209
CLRF TMP208
CLRF TMP207
CLRF TMP206
CLRF TMP205
CLRF TMP204
CLRF TMP203
CLRF TMP202
CLRF TMP201
CLRF DMY
CLRF KURIKOSHI
RETURN
;---------------初期化--------------------------
INI
CLRF GPR1
CLRF GPR2
CLRF GPR3
CLRF GPR4
CLRF LCDINST
CALL INI2
;----------内部クロックを使う----------
BSF STATUS,RP0 ;バンク1へ切替えて
MOVLW 070h ;CLOCK=8MHz
MOVWF OSCCON ;内部クロックを使う
MOVLW 1Fh ;最高値で
MOVWF OSCTUNE ;内部クロック微調整する。
BCF STATUS,RP0 ;バンク0に戻す
;----------アナログ&入力モードの設定----------
BSF STATUS,RP0 ;バンク1へ切替えて
MOVLW B'00001011' ;RA0、1,3を
MOVWF TRISA ;入力モードにする。
MOVLW B'00001011' ;RA0、1、3を
MOVWF ANSEL ;アナログにする。
CLRF TRISB ;ポートBは出力モードに設定
BCF STATUS,RP0 ;バンク0に戻す
;----------A/D設定----------
MOVLW B'01001001' ;ADCS10=01=16Tosc,ANA1=001,ADON=001
MOVWF ADCON0
BSF STATUS,RP0 ;バンク1へ切替えて
MOVLW B'11000000' ;ADFM=1=右詰め,ADCS2=1,VCFG=10=Vss+Vdd,以下未使用
; MOVLW B'01000000' ;ADFM=0=左詰め,ADCS2=1,VCFG=00=Vss+Vdd,以下未使用
MOVWF ADCON1
BCF STATUS,RP0 ;バンク0に戻す
;----------LCD初期化----------
CALL Timer100 ;「電源ONから20ms待機」との事なので面倒だから100msにする。
MOVLW 038H ;ファンクションセット値:8bit長,文字フォント5*7,1/8デューティ?
MOVWF PORTB ;でLCDのデータピンをセットする。
BCF PORTA,7 ;RA1=R/W選択信号(5PIN)を0=Wモードにする。
BCF PORTA,2 ;RA2=レジスタ選択信号(4PIN)を0=コマンドにする。
BSF PORTA,6 ;RA0=動作起動信号(6PIN)を1=ストローブにする。
CALL Timer100 ;「ストローブのパルス幅を220ns以上確保する」との事なので面倒だから100msにする。
BCF PORTA,6 ;ストローブをイネーブル(ストローブ終了)にする。
CALL Timer100 ;上記実行から4.1msec以上待機との事なので面倒だから100msにする。
MOVLW 01h ;表示クリア
CALL LCDIni2
CALL Timer100
MOVLW 06h ;エントリーモード(書き込み後カーソルを右へ)
CALL LCDIni2
CALL Timer100
MOVLW 0Ch ;表示ON
CALL LCDIni2
CALL Timer100
RETURN
;---------------タイマー管理--------------------------
;----------100ms*5=0.5sを作る------------
Timer500
MOVLW 05h ;W=5
MOVWF GPR3 ;Wの内容をデータ領域2バイト目に書き込む
TimeLoop3
NOP
CALL Timer100
DECFSZ GPR3,1
GOTO TimeLoop3
RETURN
;----------0.4ms*256=100msを作る------------
Timer100
MOVLW 0C8h ;W=200
MOVWF GPR2 ;Wの内容をデータ領域2バイト目に書き込む
TimeLoop2
NOP ;何もしない
CALL Timer1 ;999サイクルを249回呼ぶ
DECFSZ GPR2,1 ;W=W-1
GOTO TimeLoop2
RETURN ;もしW=0になら戻る
;----------0.4um*999サイクル=0.4msを作る------------
Timer1
MOVLW 0F9h ;W=249
MOVWF GPR1 ;Wの内容をデータ領域1バイト目に書き込む
TimeLoop1
NOP ;何もしない
DECFSZ GPR1,1 ;W=W-1
GOTO TimeLoop1
RETURN ;もしW=0になら戻る
;----------0.4ms*25=10msを作る------------
Timer10
MOVLW 19h ;W=200
MOVWF GPR4 ;Wの内容をデータ領域2バイト目に書き込む
TimeLoop4
NOP ;何もしない
CALL Timer1 ;999サイクルを249回呼ぶ
DECFSZ GPR4,1 ;W=W-1
GOTO TimeLoop4
RETURN ;もしW=0になら戻る
;----------------LCD初期化--------------------------------------
LCDIni2
MOVWF PORTB ;ワークWの内容をポートBへ
BCF PORTA,7 ;RA1を0=Wモードにする。
BCF PORTA,2 ;RA2を0=コマンドにする。
BSF PORTA,6 ;RA0を1=ストローブにする。
CALL Timer100
BCF PORTA,6 ;RA0を0=イネーブルにする。
CALL LCDIni3
RETURN
;----------LCD BUSYチェック------------
LCDIni3
BSF STATUS,RP0 ;バンク1へ
MOVLW 0FFh
MOVWF TRISB ;ポートBを入力モードへ
BCF STATUS,RP0 ;バンク0へ
BCF PORTA,2 ;RA2を0=コマンドにする。
BSF PORTA,7 ;RA1を1=Rモードにする。
BSF PORTA,6 ;RA0を1=ストローブにする。
CALL Timer10 ;ストローブ・ウェイト兼1文字表示間隔調整
BCF PORTA,6 ;RA0を0=イネーブルにする。
MOVF PORTB,W ;ポートBの内容をワークWへ
MOVWF LCDINST ;ワークWの内容を0Fhへ
BTFSC LCDINST,7 ;RB7=DB7=0ならループを抜ける
GOTO LCDIni3
BCF PORTA,7 ;RA1を0=Wモードにする。
BSF STATUS,RP0 ;バンク1へ切替えて
CLRF TRISB ;ポートBを出力モードに設定する。
BCF STATUS,RP0 ;バンク0に戻す
RETURN
;---------------LCDデータ書き込み---------------------------
LCDDTW
MOVWF PORTB
BCF PORTA,7 ;R/WをW
BSF PORTA,2 ;RSをデータに
BSF PORTA,6 ;書き込みストローブ。ストローブとはストロボの事で「その一瞬を切り取る」意味。リードでは「その一瞬の値」を読み取る、ライトでは「その瞬間にワークWの内容を書く」となる。
BCF PORTA,6 ;ストローブ終了。
CALL LCDIni3
RETURN
;---------------デバッグテスト用---------------------------
DEBUG1
MOVLW 01h ;表示クリア
CALL LCDIni2
MOVLW 002h ;カーソルホーム
CALL LCDIni2
CALL Timer500
MOVLW 0F3h ;∞表示
CALL LCDDTW
CALL Timer500
GOTO DEBUG1
DEBUG2
MOVLW 01h ;表示クリア
CALL LCDIni2
MOVLW 002h ;カーソルホーム
CALL LCDIni2
CALL Timer500
MOVLW 040h ;@表示
CALL LCDDTW
CALL Timer500
GOTO DEBUG2
;---------------------------------------
END