kuroの覚え書き

96の個人的覚え書き

PIC温度計プログラム続き 数値計算編



AD変換値から温度表示にするには・・・


温度 抵抗値(kΩ) 並列抵抗(kΩ) 合成抵抗(kΩ)
0 153 2.5 2.459807074
26 46.5 2.5 2.37244898
31 37.5 2.5 2.34375
39.5 27.2 2.5 2.28956229
48.5 19 2.5 2.209302326
60 12.7 2.5 2.088815789
70 9.1 2.5 1.961206897
79.5 6.5 2.5 1.805555556
89 4.8 2.5 1.643835616
101 3.7 2.5 1.491935484

抵抗(kΩ) 16F84A簡易AD変換値
0 2
0.3 27
0.47 43
0.5 45
0.75 68
1 91
1.5 139
1.8 164
2 181
2.27 214

これらから近似式を作ると

AD変換値が200以下の時(50℃以上)

y = -0.0108*66.752x + 199 = -0.72x + 199

AD変換値が200以上の時(50℃以下)

y = -0.0108*137.12x+ 352 = -1.48x + 256 + 96

で温度に変換できる(あくまで近似式だが)

なので、以上以下で区切るプログラムを作ればいいわけだ


MOVLW 0C8H ;200をロードして
SUBWF WIDTH,F ;元のデータから200を引く
BTFSC STATUS,C ;マイナスかどうか
GOTO OVER50
GOTO UNDER50

こんな感じか

後はかけ算をどうするか、小数点をどうするか

http://www1.bbiq.jp/shimitti/picmicon/program/mul/mul.htm

http://www.try-net.or.jp/~el_dream/pic/pic.html

100倍して小数をなくしておいてかけ算した後、もう一度100で割るようにすれば良いかな。


;水温測定(AD変換)
;RB2で充電、RB3でカウントする
;RB2は出力に設定
;AD変換値は変数WIDTHに格納
;数字表示用変数FIGCNT
BSF PORTB,2 ;充電しておく
CALL TIME50M
WATER_TEMP
MOVLW 0BDH ;LCD表示位置固定
CALL LCD_CMD ;
CALL ADCNV
CALL TEMP_CALC
CALL DISP_DIGIT
CALL TIME1S
GOTO WATER_TEMP
;************************************
;数字表示サブルーチン
;変数FIGCNT使用
;************************************
DISP_DIGIT ;3桁に分けて各桁をカウント
CLRF FIGCNT ;FIGCNTをリセット
FIGLOOP100
MOVLW 064H ;100をロードして
SUBWF WIDTH,F ;元のデータから100を引く
BTFSC STATUS,C ;マイナスになるまで繰り返す
GOTO CNTPLUS100
GOTO ENDFIG100
CNTPLUS100
INCF FIGCNT,F ;100の位の数を数える
GOTO FIGLOOP100
ENDFIG100
MOVF FIGCNT,W
CALL DISP_NUM ;100の位の表示
MOVLW 064H ;100をロード
ADDWF WIDTH,F ;マイナスになったWIDTHをプラスに戻す
CLRF FIGCNT ;FIGCNTをリセット
FIGLOOP10
MOVLW 0AH ;10をロードして
SUBWF WIDTH,F ;データから10を引く
BTFSC STATUS,C ;マイナスになるまで繰り返す
GOTO CNTPLUS10
GOTO ENDFIG10
CNTPLUS10
INCF FIGCNT,F ;10の位の数を数える
GOTO FIGLOOP10
ENDFIG10
MOVF FIGCNT,W
CALL DISP_NUM ;10の位の表示
MOVLW 0AH ;10をロード
ADDWF WIDTH,W ;マイナスになったWIDTHをプラスに戻し、Wレジスタにロード
CALL DISP_NUM ;1の位の表示
RETURN
DISP_NUM ADDLW '0' ;ASCIIコードに変換
CALL LCD_DATA ;数字の表示
RETURN
;************************************
;16F84A用簡易A/D変換サブルーチン
;変数WIDTHを使用
;************************************
ADCNV ;A/DCONVERT
CLRF WIDTH ;カウンタリセット
BSF STATUS,RP0 ;バンク1へ切替
MOVLW 08H ;PORTBRB3を入力モードにセット
MOVWF TRISB
BCF STATUS,RP0 ;BANK 0へ戻す
BCF PORTB,2 ;放電開始
LOOPT1 BTFSS PORTB,3 ;0か?
GOTO LOOPT2 ;0で変換終了
NOP
NOP
NOP ;時間カウント調整用ダミー
NOP
INCF WIDTH,F ;カウントアップ
GOTO LOOPT1 ;繰り返し
LOOPT2 BSF PORTB,2
CALL TIME50M ;充電待ち(必要ないかも)
RETURN
;************************************
;温度換算サブルーチン
;AD変換値200で2式に分けている
;************************************
TEMP_CALC
MOVLW 0C8H ;200をロードして
SUBWF WIDTH,F ;元のデータから200を引く
BTFSC STATUS,C ;マイナスかどうか
GOTO OVER50
GOTO UNDER50
OVER200
MOVLW 0C8H ;200をロード
ADDWF WIDTH,W ;WIDTHを戻してWに入れる
MOVWF A1 ;A1にW格納
MOVF 148,W ;乗算数値をWに入れる
MOVWF A2 ;A2にW格納
CALL MUL88 ;MUL88を呼び出し
MOVF A_HIGH,W ;計算結果(上位)をWに入れる
MOVWF DIV1B ;DIV1BにW格納
MOVF A_LOW,W ;計算結果(下位)をWに入れる
MOVWF DIV1A ;BDIV1AにW格納
MOVLW 00H ;割る数上位(0)
MOVWF DIV2B
MOVLW 064H ;割る数下位(100)
MOVWF DIV2A
CALL DIV16 ;答えはDIV3B,A、余りはDIV4B,Aに返る
MOVLW 0FFH ;255をロード
MOVWF WIDTH ;WIDTHにW格納
MOVF DIV3A,W ;割り算結果をWに格納
SUBWF WIDTH,F ;割り算結果を255から引いてWIDTHに戻す
MOVLW 061H ;97をロード
ADDWF WIDTH,F ;足し算結果をWIDTHに戻す
GOTO ENDCALC

UNDER200
MOVLW 0C8H ;200をロード
ADDWF WIDTH,W ;WIDTHを戻してWに入れる
MOVWF A1 ;A1にW格納
MOVF 72,W ;乗算数値をWに入れる
MOVWF A2 ;A2にW格納
CALL MUL88 ;MUL88を呼び出し
MOVF A_HIGH,W ;計算結果(上位)をWに入れる
MOVWF DIV1B ;DIV1BにW格納
MOVF A_LOW,W ;計算結果(下位)をWに入れる
MOVWF DIV1A ;BDIV1AにW格納
MOVLW 00H ;割る数上位(0)
MOVWF DIV2B
MOVLW 064H ;割る数下位(100)
MOVWF DIV2A
CALL DIV16 ;答えはDIV3B,A、余りはDIV4B,Aに返る
MOVLW 0C7H ;199をロード
MOVWF WIDTH ;WIDTHにWを格納
MOVF DIV3A,W ;割り算結果をWに格納
SUBWF WIDTH,F ;割り算結果を199から引いてWIDTHに戻す
GOTO ENDCALC
ENDCALC RETURN
;************************************
;1BITE乗算サブルーチン
;変数は A_HIGH
; A_LOW
; A1 かける数1
; A2 かける数2
;************************************
MUL88
CLRF A_HIGH ;A_HIGH=0
CLRF A_LOW ;A_LOW=0
MOVLW 0X8 ;Wに8を入れる
MOVWF LOOP ;LOOPにW格納
MOVF A1,W ;1ならWにA1を入れる
BCF STATUS,C ;STATUSのC=0
NEXT1
RRF A2,F ;A2を右へシフト
BTFSC STATUS,C ;STATUSのCは0か?
ADDWF A_HIGH,F ;A_HIGHとWを加算
RRF A_HIGH,F ;A_HIGHを右へシフト
RRF A_LOW,F ;A_LOWを右へシフト
DECFSZ LOOP,F ;LOOPは0か?
GOTO NEXT1 ;1の時NEXT1へ
RETURN ;0の時ルーチン修了
;************************************
;16ビットの割り算ルーチン
;使用変数
;DIV1B 割られる数上位(終了時には0になって戻る)
;DIV1A 割られる数下位
;DIV2B 割る数上位(変化せず戻る)
;DIV2A 割る数下位
;DIV3B 答え上位(答えが返る)
;DIV3A 答え下位
;DIV4B 余り上位(余りが返る、内部ワークにも使用)
;DIV4A 余り下位
;DIVL1 内部ループ用
;DIVL2 内部ループ用
;DIVERR 割る数が0であった場合に1をセットして戻る
;************************************
DIV16
MOVLW 10H ;10H=16
MOVWF DIVL1
MOVF DIV2A,0 ;割る数下位をワークにコピー
MOVWF DIV4A
MOVF DIV2B,0 ;割る数上位をワークにコピー
MOVWF DIV4B
DI1601
RLF DIV4A,1 ;左シフトする
RLF DIV4B,1
BTFSC 3H,0 ;キャリフラグを見る
GOTO DI1602 ;割る数の上位ビット位置検索
DECFSZ DIVL1,1
GOTO DI1601
MOVLW 1
MOVWF DIVERR ;割る数が0である。エラーコードをセット
RETURN ;戻る
DI1602
CLRF DIV3A ;答え用変数のクリア
CLRF DIV3B
CLRF DIV4A ;ワーク用変数のクリア
CLRF DIV4B
MOVLW 10H ;10H=16
MOVWF DIVL2
MOVF DIVL1,0
SUBWF DIVL2,1 ;残り、実ループの回数
DI1603
BCF 3H,0 ;キャリフラグを0に
RLF DIV1A,1
RLF DIV1B,1
RLF DIV4A,1
RLF DIV4B,1
DECFSZ DIVL1,1 ;割られる数を初期位置までシフト
GOTO DI1603
DI1604 ;現位置での減算が可能かチェック
MOVF DIV2B,0
SUBWF DIV4B,0
BTFSS 3H,0
GOTO DI1606
MOVF DIV4B,0
SUBWF DIV2B,0
BTFSS 3H,0
GOTO DI1605
MOVF DIV2A,0
SUBWF DIV4A,0
BTFSS 3H,0
GOTO DI1606
DI1605
MOVF DIV2A,0
SUBWF DIV4A,1 ;ワークから下位を引く
BTFSS 3H,0 ;キャリフラグが 1(正)なら次をスキップ
DECF DIV4B,1 ;上位 -1
MOVF DIV2B,0
SUBWF DIV4B,1 ;ワークから上位を引く
BSF 3H,0 ;キャリフラグを1に
GOTO DI1607
DI1606
BCF 3H,0 ;キャリフラグを0に
DI1607
RLF DIV3A,1 ;キャリフラグの内容を答えにシフト
RLF DIV3B,1
MOVF DIVL2,1 ;DIVL2 が 0 か検査
BTFSC 3H,2
GOTO DI1608 ;最下位まで処理したなら終了
DECF DIVL2,1 ;ビット位置を1つ下げる(右へ)
BCF 3H,0 ;キャリフラグを0に
RLF DIV1A,1 ;ワークへ1ビット左シフト
RLF DIV1B,1
RLF DIV4A,1
RLF DIV4B,1
GOTO DI1604
DI1608
CLRF DIVERR ;正常終了
RETURN

精度を上げるには複数回の計算結果を平均した方が良かろう


TEMP_AVE
CLRF AD1A
CLRF AD1B
CLRF AD2A
CLRF AD2B
MOVLW 064H ;100回
MOVWF CNTAV
AVELP CALL ADD_TEMP
DECFSZ CNTAV,F
GOTO AVELP
GOTO AVE_TEMP
ADD_TEMP
CALL ADCNV
CALL TEMP_CALC
MOVF WIDTH,W
MOVWF ad2a
CALL ADD16
RETURN
AVE_TEMP
MOVF AD1B,W
MOVWF DIV1B
MOVF AD1A,W
MOVWF DIV1A
MOVLW 00H
MOVWF DIV2B
MOVLW 064H
MOVWF DIV2A
CALL DIV16
MOVF DIV3A,W
MOVWF WIDTH
RETURN

;*******************************
;16+16=16ビットの加算
;ad1b(上位),ad1a(下位) と ad2b,ad2a に二つの引き数を
;セットして呼ぶ
;結果は ad1b,ad1a (左項)に加算された形で得られる。
;ad2b,ad2a は変化しない。
;ad1b 引き数1/答え(上位)
;ad1a 引き数1/答え(下位)
;ad2b 引き数2(上位)
;ad2a 引き数2(下位)
;*******************************
add16
movf ad2a,0
addwf ad1a,1
btfsc 3h,0
incf ad1b,1
movf ad2b,0
addwf ad1b,1
return


あとは変数を整理して、メモリを節約すれば多分完成!

http://www.geocities.jp/maxvxam/diy/PIC/temp3.txt

これでテストしてみよう。