kuroの覚え書き

96の個人的覚え書き

シリアル通信に成功



PICで作成したタコメータの回転数をrs232c通信によりPC(もしくはPalm)に送ることに挑戦していたのだが

なかなか成功しなかった。

昨日もやはりだめだったんだけど、今日ソース中にいらないコメントが入っていることに気がついた。

その点を修正してアセンブルし直してみたところ見事にデータの送信に成功した。

これで回転数ログを取ることができる。現状では250msec計測→計算→転送→計測・・・・と時間制御なしでやっている。

あとは

EEPROMにいったん記憶させて後で転送、もしくは逐次転送のどちらがいいかの検討。

タイマーにより一定間隔で回転数を計測し転送(もしくはEEPROMに書き込み)する方法の模索。

この2点をクリアーすれば念願のパワー計測ツールが完成する。


LIST P=PIC16F648A
INCLUDE "P16F648A.INC"
__CONFIG _BODEN_OFF & _WDT_OFF & _PWRTE_ON & _LVP_OFF & _INTOSC_OSC_NOCLKOUT & _MCLRE_ON

;************************
;変数定義とレジスタ割付
;************************
CBLOCK 020H ;先頭の番地を指定
BYTE0 ;周波数カウンタ0
BYTE1 ;周波数カウンタ1
BYTE2 ;周波数カウンタ2
DPDT ;液晶表示データ
CALC1A
CALC1B
CALC2A
CALC2B
CALC3A
CALC3B
CALC4A
CALC4B
CALCLP1
CALCLP2
CALCERR
FIGCNT ;
CNT1 ;タイマ用カウンタ
CNT2
CNT3
CNT4
LOOP
LPCNT1 ;LOOP COUNTER
LPCNT2 ;LOOP COUNTER
OVRFLW ;OVER FLOW FLAG
TEMP ;TEMPOLARY WORK
ENDC ;定義終わり

;************************
;JUMPING VECTOR
;************************
ORG 0
GOTO MAIN

ORG 4
GOTO INTPROC
INTPROC
RETURN

ORG 08H

;************************
; MAIN ROUTINE
;************************

MAIN
BCF INTCON,GIE ;割込禁止
BTFSC INTCON,GIE
GOTO $-2 ;(2行戻る)
CALL PORT_INI ;PORT A,B INI
CALL LCD_INI ;RESET LCD

MAINLP
MOVLW 0C7H
CALL LCD_CMD ;表示位置指定
CALL MEASURE
CALL CALC
CALL SEND
CALL DISP_DIGIT ;回転数表示
CALL DISP_OTHER ;00と単位_RPM表示
; CALL TIME50M ;1秒間そのまま表示
GOTO MAINLP ;表示更新

;************************
;計測実行サブルーチン
;VMAXのタコメーターパルスに
;あわせるとゲートタイムは0.6秒
;だがゲートタイム0.25秒にして
;2.4をかけて表示させる。
;PORTAのRA4がゲート制御ピン
;4MHZ内蔵オシレータ使用ver.
;************************
MEASURE
BSF STATUS,RP0 ;SET PAGE 1
MOVLW 068H ;SET TO NO PRESCALE
MOVWF OPTION_REG ;
BCF STATUS,RP0 ;SET PAGE 0
CLRF TMR0 ;カウンタリセット
BCF PORTA,4 ;ゲートを閉める

;****ゲートタイム250msec****
BSF PORTA,4 ;ゲートを開ける
CLRF OVRFLW ;OverFlowフラグをクリア
CALL MEALOOP ;249998STEP
BCF PORTA,4 ;ゲートを閉める (250000)
RETURN

;****計測実行ループ(249,996STEPS)****
MEALOOP
MOVLW 08DH ;ループ繰り返しカウンタ=141
MOVWF LPCNT1
;++++++++++
MEALP1
MOVLW 088H ;第二カウンタ=136
MOVWF LPCNT2 ;
;***********
MEALP2
BTFSS INTCON,T0IF ;13 STEPS LOOP
GOTO DUMY1
BCF INTCON,T0IF ;T0IFフラグをリセット
MOVLW 1 ;カウント更新用定数
GOTO NEXT
DUMY1
NOP ;時間調整
NOP
MOVLW 0 ;カウンタ更新用定数
NEXT
ADDWF BYTE1,F ;BYTE1+T0IF
RLF BYTE1,W ;CARRY TO D<0>
ANDLW 1 ;キャリーだけ取り出し
ADDWF BYTE2,F ;BYTE2+CARRY
DECFSZ LPCNT2,F ;ループ終了か?
GOTO MEALP2 ;
;**********
NOP
MEALP3
DECFSZ LPCNT1,F ;(13*LPCNT2+5)*LPCNT1
GOTO MEALP1 ;(13*136+5)*141=249993-1
;+++++++++++++++
RETURN ;+2+2=249996

;************************
;0.6秒のカウント数にあわせるため2.4倍する
;************************
CALC
MOVF TMR0,W ;TMR0をWに取出し
MOVWF CALC1A ;W格納
MOVLW 018H ;乗算数値24をWに入れる
MOVWF CALC1B ;W格納
CALL MUL88 ;MUL88を呼び出し
MOVLW 0AH ;10で割る
MOVWF CALC1A
CLRF CALC1B
CALL DIV16
MOVF CALC3A,W ;計算結果(下位)をWに入れる
MOVWF TEMP ;TEMPにW格納
RETURN

SEND
BSF STATUS,RP0 ; Bank 1 へ切替
LPTX
BTFSS TXSTA,TRMT ; 送信可能であるかチェック(1:可能, 0:禁止)
GOTO LPTX ; 禁止であれば LPTX のラベル間を繰り返す
BCF STATUS,RP0 ; Bank 0 へ戻す
MOVF TEMP,W
MOVWF TXREG
RETURN

;************************
;バイナリから10進数へ変換後LCDに数字を表示するサブルーチン
;120カウントが最大値なので3桁しか表示しない
;************************
DISP_DIGIT ;3桁に分けて各桁をカウント
CLRF FIGCNT ;FIGCNTをリセット
FIGLOOP100
MOVLW 064H ;100をロードして
SUBWF TEMP,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 TEMP,F ;マイナスになったTEMPをプラスに戻す
CLRF FIGCNT ;FIGCNTをリセット
FIGLOOP10
MOVLW 0AH ;10をロードして
SUBWF TEMP,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 TEMP,W ;マイナスになったTEMPをプラスに戻し、Wレジスタにロード
CALL DISP_NUM ;1の位の表示
RETURN

DISP_NUM ADDLW '0' ;ASCIIコードに変換
CALL LCD_DATA ;数字の表示
RETURN


;************************************
;四則演算サブルーチン
;参照http://www1.bbiq.jp/shimitti/picmicon/program/mul/mul.htm
;およびhttp://www.try-net.or.jp/~el_dream/pic/pic.html
;これらを一部改編し作成
;************************************
;使用するレジスタは以下
;CALC1A
;CALC1B
;CALC2A
;CALC2B
;CALC3A
;CALC3B
;CALC4A
;CALC4B
;CALCLP1
;CALCLP2
;CALCERR
;***8ビット乗算サブルーチン***
MUL88
CLRF CALC2B
CLRF CALC2A
MOVLW 0X8 ;Wに8を入れる
MOVWF CALCLP1 ;LOOPにW格納
MOVF CALC1B,W ;1ならWにCALC1Bを入れる
BCF STATUS,C ;STATUSのC=0
MUL88LP
RRF CALC1A,F ;CALC2Aを右へシフト
BTFSC STATUS,C ;STATUSのCは0か?
ADDWF CALC2B,F ;CALC1BとWを加算
RRF CALC2B,F ;CALC1Bを右へシフト
RRF CALC2A,F ;CALC1Aを右へシフト
DECFSZ CALCLP1,F ;LOOPは0か?
GOTO MUL88LP ;1の時NEXT1へ
RETURN ;0の時ルーチン修了
;***16ビットの割り算サブルーチン***

DIV16
MOVLW 10H ;10H=16
MOVWF CALCLP1
MOVF CALC1A,0 ;割る数下位をワークにコピー
MOVWF CALC4A
MOVF CALC1B,0 ;割る数上位をワークにコピー
MOVWF CALC4B
DI1601
RLF CALC4A,1 ;左シフトする
RLF CALC4B,1
BTFSC 3H,0 ;キャリフラグを見る
GOTO DI1602 ;割る数の上位ビット位置検索
DECFSZ CALCLP1,1
GOTO DI1601
MOVLW 1
MOVWF CALCERR ;割る数が0である。エラーコードをセット
RETURN ;戻る
DI1602
CLRF CALC3A ;答え用変数のクリア
CLRF CALC3B
CLRF CALC4A ;ワーク用変数のクリア
CLRF CALC4B
MOVLW 10H ;10H=16
MOVWF CALCLP2
MOVF CALCLP1,0
SUBWF CALCLP2,1 ;残り、実ループの回数
DI1603
BCF 3H,0 ;キャリフラグを0に
RLF CALC2A,1
RLF CALC2B,1
RLF CALC4A,1
RLF CALC4B,1
DECFSZ CALCLP1,1 ;割られる数を初期位置までシフト
GOTO DI1603
DI1604 ;現位置での減算が可能かチェック
MOVF CALC1B,0
SUBWF CALC4B,0
BTFSS 3H,0
GOTO DI1606
MOVF CALC4B,0
SUBWF CALC1B,0
BTFSS 3H,0
GOTO DI1605
MOVF CALC1A,0
SUBWF CALC4A,0
BTFSS 3H,0
GOTO DI1606
DI1605
MOVF CALC1A,0
SUBWF CALC4A,1 ;ワークから下位を引く
BTFSS 3H,0 ;キャリフラグが 1(正)なら次をスキップ
DECF CALC4B,1 ;上位 -1
MOVF CALC1B,0
SUBWF CALC4B,1 ;ワークから上位を引く
BSF 3H,0 ;キャリフラグを1に
GOTO DI1607
DI1606
BCF 3H,0 ;キャリフラグを0に
DI1607
RLF CALC3A,1 ;キャリフラグの内容を答えにシフト
RLF CALC3B,1
MOVF CALCLP2,1 ;CALCLP2 が 0 か検査
BTFSC 3H,2
GOTO DI1608 ;最下位まで処理したなら終了
DECF CALCLP2,1 ;ビット位置を1つ下げる(右へ)
BCF 3H,0 ;キャリフラグを0に
RLF CALC2A,1 ;ワークへ1ビット左シフト
RLF CALC2B,1
RLF CALC4A,1
RLF CALC4B,1
GOTO DI1604
DI1608
CLRF CALCERR ;正常終了
RETURN

;************************
;LCDに単位などの表示を加える
;************************
DISP_OTHER
MOVLW 0CAH ;位置を指定
CALL LCD_CMD
MOVLW '0'
CALL LCD_DATA
MOVLW '0'
CALL LCD_DATA
MOVLW 0CDH ;位置を指定
CALL LCD_CMD
MOVLW 072H ;R
CALL LCD_DATA
MOVLW 070H ;P
CALL LCD_DATA
MOVLW 06DH ;M
CALL LCD_DATA
RETURN

;************************
;PORT A & B INITIALIZE ROUTINE
;************************
PORT_INI
CLRF PORTA
MOVLW 07H
MOVWF CMCON ;コンパレータをすべてオフ
BSF STATUS,RP0 ;SET PAGE 1
MOVLW 02H ;00000010 ONLY RB1 INPUT (RXD)
MOVWF TRISB ;PORTB SET
MOVLW 018H ;00011000 ONLY RA3,4 INPUT
MOVWF TRISA ;PORTA SET
MOVLW 057H ;1010111 OPTION SET TMR0=1:256
MOVWF OPTION_REG ;FOR TMR0

;USART INI
MOVLW 024H ;00100100 非同期モード
MOVWF TXSTA ;set TX mode
MOVLW 019H ;4MHz, 9600bps
MOVWF SPBRG ;ボーレート
BCF STATUS,RP0 ;set PAGE 0
MOVLW 090H ;10010000 非同期モード
MOVWF RCSTA ;set RX mode
CLRF PORTB ;ALL CLEAR
RETURN

;************************
;LCD制御サブルーチン
;************************

;****LCD COMMAND OUT****
LCD_CMD
MOVWF DPDT ;COMMANDデータの一時保存
ANDLW 0F0H ;上位4ビットをまず出力
MOVWF PORTB ;RB4-7のデータバスへ出力
BCF PORTA,1 ;R/Wを0にセット COMMAND条件セット
BCF PORTA,2 ;RSを0にセット
BSF PORTA,0 ;E HIGH ストローブ信号出力
BCF PORTA,0 ;E LOW
SWAPF DPDT,W ;一時保存データの上位下位を入れ替え
ANDLW 0F0H ;下位4ビットを出力
MOVWF PORTB ;RB4-7へ出力
BSF PORTA,0 ;ストローブ信号出力
BCF PORTA,0
CALL LCD_BUSY ;BUSY信号が無くなるまで待つ
RETURN
;**** LCD DATA WRITE ****
LCD_DATA
MOVWF DPDT ;表示データ(ASCII)の一時保存
ANDLW 0F0H ;上位4ビット転送
MOVWF PORTB
BCF PORTA,1 ;R/Wを0にセット、データ送信モードセット
BSF PORTA,2 ;RSを1にセット
BSF PORTA,0 ;E HIGH ストローブ信号出力
BCF PORTA,0 ;E LOW
SWAPF DPDT,W ;GET DATA LOWER
ANDLW 0F0H ;下位4ビットの転送
MOVWF PORTB
BSF PORTA,0 ;ストローブ信号出力
BCF PORTA,0
CALL LCD_BUSY ;BUSY信号が無くなるまで待つ
RETURN
;**** LCD BUSY CHECK ****
LCD_BUSY
CLRF DPDT ;データバッファクリア
BSF STATUS,RP0 ;PICモード変更のためBANK1へ切替え
BSF OPTION_REG,7 ;ポートBのプルアップをOFF指定
MOVLW 0FEH ;PORTBRB0以外を入力モードにセット
MOVWF TRISB
BCF STATUS,RP0 ;BANK 0へ戻す
BCF PORTA,2 ;RSを0にセット
BSF PORTA,1 ;R/Wを1にセット BUSY入力モードをセット
BSF PORTA,0 ;E HIGH ストローブ信号出力
MOVF PORTB,W ;データを2回に分けて入力
BCF PORTA,0 ;E LOW
ANDLW 0F0H ;まず上位4ビットを入力
MOVWF DPDT ;一時保存
BSF PORTA,0 ;E HIGH 次のストローブ信号出力
MOVF PORTB,W ;下位4ビットを入力
BCF PORTA,0 ;E LOW
ANDLW 0FH ;MASK OUT UPPER
IORWF DPDT,F ;上位と下位をORで合併
BTFSC DPDT,7 ;BUSY FLAGビットをチェック
GOTO LCD_BUSY ;BUSY状態だったら再度入力繰り返し
;
BCF PORTA,1 ;R/Wを0に戻す(出力モードに戻す)
BSF STATUS,RP0 ;PICのモード変更のためBANK 1へ切替え
MOVLW 0EH ;RB1,2,3 以外は出力へ戻す
MOVWF TRISB ;PORTBモードセット
BCF STATUS,RP0 ;BANK 0へ戻す
RETURN
;**** LCD INITIALIZE ****
LCD_INI
CALL TIME5M ;15MSEC以上待つ(5MSEC3回待ちにしている)
CALL TIME5M
CALL TIME5M
MOVLW 030H ;8ビットモード設定制御
MOVWF PORTB
BCF PORTA,1 ;R/W 0セット
BCF PORTA,2 ;RS 0セット
BSF PORTA,0 ;E HIGH ストローブ
BCF PORTA,0 ;E LOW
CALL TIME5M ;4.1MSEC以上待つ(5MSEC待ち)
MOVLW 030H ;再度8ビットモード設定制御
MOVWF PORTB
BCF PORTA,1 ;R/W 0セット
BCF PORTA,2 ;RS 0セット
BSF PORTA,0 ;E HIGH ストローブ
BCF PORTA,0 ;E LOW
CALL TIME02M ;100USEC以上待つ(200USEC待ち)
MOVLW 030H ;再々度8ビットモード設定制御
MOVWF PORTB
BCF PORTA,1 ;R/W 0セット
BCF PORTA,2 ;RS 0セット
BSF PORTA,0 ;ストローブ
BCF PORTA,0
CALL TIME02M ;念のため200USEC待ち
MOVLW 020H ;4ビットモード設定制御
MOVWF PORTB ;(この時はまだ8ビットモード)
BCF PORTA,1 ;R/W 0セット
BCF PORTA,2 ;RS 0セット
BSF PORTA,0 ;ストローブ
BCF PORTA,0
CALL TIME02M ;念のため200USEC待ち
;以降4ビットモードで動作かつBUSYFLAG有効
MOVLW 02CH ;FUNCTION SET(101100 4ビット、2行、5X10DOT表示指定)
CALL LCD_CMD
MOVLW 08H ;DISPLAY OFF (1000 表示オフ、CURSOR,BLINKなし)
CALL LCD_CMD
MOVLW 0CH ;DISPLAY ON (1100 表示オン、CURSOR,BLINKなし)
CALL LCD_CMD
MOVLW 06H ;ENTRY MODE SET(INCREMENTオン,表示シフト指定なし)
CALL LCD_CMD
RETURN
;*****表示クリア*****
LCD_CLR MOVLW 01H ;表示クリア(1)
CALL LCD_CMD
; CALL TIME1S
RETURN

;タイマーサブルーチン4MHz
;周期0.25usec、実行サイクル1usec

;0.2msec 200サイクル*1usec
TIME02M
MOVLW 031H ;1 49回まわす
MOVWF CNT1 ;1 2
TIMLP1
NOP ;1
DECFSZ CNT1,F ;1
GOTO TIMLP1 ;2 2+4*49-1=197
NOP ;1 198
RETURN ;2 200 200*1usec=0.2msec
;5msec 5000サイクル
TIME5M
MOVLW 019H ;1 25回まわす
MOVWF CNT2 ;
TIMLP2
CALL TIME02M ;
DECFSZ CNT2,F ;
GOTO TIMLP2 ;
RETURN ;
;50msec 50000
TIME50M
MOVLW 0F7H ;247回
MOVWF CNT3 ;ここまでで2サイクル
TIMLP3
CALL TIME02M ;
DECFSZ CNT3,F ;
GOTO TIMLP3 ;
RETURN ;

;1sec
TIME1S
MOVLW 014H ;20回
MOVWF CNT4 ;50msec*20
TIMLP4
CALL TIME50M
DECFSZ CNT4,F ;このループは50msec
GOTO TIMLP4
RETURN


END