;****************************************************** ; ;    お気楽レヴロガーPlus ; ; 00/04/29 Masashi Kawanishi ; PIC16F84:20MHz用(1cycle=0.2us) ; ; 電源入れて20秒間の後計測開始 ; はじめの1秒の間にSW押すとセンサー調整モード ; 調整モード中にもう一回押すとRS232Cデータ送信モード ; データ送信モード: ;  9600bps, 8bit, 1stopbit ;  パリティーなし、フロー制御なし ;  テキストデータが0000番地から順に流れてくる ; ; 回転速度は10us単位でピニオンの一回転の周期を測定 ; 16ビットデータで表現(最大周期655.36ms) ; ; ピンアサイン ; RA2 -> IrLED (0でOFF 1でON) ; RA3 -> LED (1でOFF 0でON) ; RA4 <- センサー入力 (1で暗 0で明) ; RB1 <- プッシュSW (1でOFF 0でON) ; RB2 -> RS232C送信 ; RB3 <- RS232C受信 ; RB6 -> SCLK ; RB7 <-> SDA ; ;****************************************************** LIST P=PIC16F84 INCLUDE "P16F84.INC" ;****************************** ; 変数レジスタ定義 ;****************************** eeprom equ 0CH ; eeprom bit buffer bycnt equ 0DH ; eeprom byte counter addrl equ 0EH ; eeprom address(low) addrh equ 0FH ; eeprom address(high) datai equ 10H ; eeprom data input datao equ 11H ; eeprom data output 1st byte datao2 equ 12H ; eeprom data output 2nd byte datao3 equ 13H ; eeprom data output 2nd byte datao4 equ 14H ; eeprom data output 2nd byte slave equ 15H ; eeprom slave address txbuf equ 16H ; eeprom transmit buffer count equ 17H ; eeprom bit counter bcount equ 18H ; bcount CNTa equ 19H ; Time counter CNTb equ 1AH CNTc equ 1BH CNTd equ 1CH CNTe equ 1DH CNTf equ 1EH SENDT equ 1FH ; ウェイト時間調整用 BITW equ 20H ; ビット数 TXDATA equ 21H ; 送信データ(8ビット) DISBUF equ 22H ;RSキャラクタ送信用 PREDL equ 23H ;センサー用フラグ tmcnt1h equ 24H ;速度カウンター1上位 tmcnt1l equ 25H ;速度カウンター1下位 tmcnt2h equ 26H ;速度カウンター2上位 tmcnt2l equ 27H ;速度カウンター2下位 adcnth equ 28H ;書き込みアドレスカウンタ上位 adcntl equ 29H ;書きこみアドレスカウンタ下位 ;******************************* ; ビット定義他 ;******************************* di equ 7 ;eeprom input bit do equ 6 ;eeprom output bit sdata equ 7 ;serial EE data line (port_b ,pin13) sclk equ 6 ;serial EE clock line (port_b, pin12) ackf equ 3 ; acknowledge fail LED (port_a, pin2) BTIME equ D'170' ; 9600bps @20MHz org 0 ;******************** ; ポートセット、初期化 ;******************** bsf STATUS, RP0 movlw b'00010000' ;RA set : input for port 4 other output movwf TRISA movlw b'00001010' movwf TRISB bcf STATUS, RP0 movlw b'00001000' movwf PORTA ;LED消灯, IrLED消灯 movlw b'00000100' movwf PORTB ;RS232C初期化 ;******************************* ;  メインルーチン ;******************************* MENU1 ;1秒間SWが押されたか監視、おされたら調整モードへ MOVLW 0C8H ;set 200 MOVWF CNTe T_LP8 CALL TIME5M ;2+(25253+5)*200-1=5051601 BTFSS PORTB,1 ;SWが1(off)だったらスキップ GOTO SNSADJ ;onだったらセンサー調整モードへ DECFSZ CNTe,F GOTO T_LP8 ;********* 測定モード ******************** bsf PORTA, 2 ;IrLED ON MOVLW 13H ;set 19 MOVWF CNTf T_LP9 CALL TIM1S ;1秒待ち DECFSZ CNTf, F GOTO T_LP9 ;*******19秒待った後(計20秒)測定開始******* MEAMAIN0 CLRF PREDL movlw 80H movwf adcnth ;アドレス最上位bitはeeprom上で無視される ;32kbyte超えた時にオーバーフローするようにセット clrf adcntl MEAMAIN BTFSC PREDL,0 ;直前センサが0(明)だったら次をスキップ GOTO DARK ;直前センサが1(暗)だったらDARKへ ;***前回ループではマーカー内であった*** BTFSS PORTA, 4 ;現在センサが1(暗)だったら次をスキップ GOTO CNT5 ;現在センサが0(明)だったらカウントへ NOP NOP BTFSS PORTA, 4 ;再確認(ノイズ対策) GOTO CNT9 ;**回転マーカーが切れた** BSF PORTA, 3 ;LED消灯 MOVLW 01H MOVWF PREDL GOTO CNT13 ;***前回ループはマーカー外であった*** DARK BTFSC PORTA, 4 ;現在センサが0(明)だったら次をスキップ GOTO CNT6 ;現在センサが1(暗)だったらカウントへ NOP NOP BTFSC PORTA, 4 ;再確認(ノイズ対策) GOTO CNT10 ;**回転マーカーを検出** BCF PORTA, 3 ;LED点灯(10) MOVLW 00H MOVWF PREDL movf tmcnt2h, w ;タイムカウンタbuff.上位:0?(13) btfss STATUS, Z ;0だったら次をスキップ goto EEP1 movf tmcnt2l, w ;タイムカウンタbuff.下位:0? btfss STATUS, Z ;0だったら次をスキップ goto EEP2 movf tmcnt1h, w ;タイムカウンタの値をバッファに移す movwf tmcnt2h clrf tmcnt1h movf tmcnt1l, w movwf tmcnt2l clrf tmcnt1l ;(24) goto CNT26 CNT5 nop CNT6 nop nop nop CNT9 nop CNT10 nop nop nop CNT13 nop nop nop nop nop nop nop nop nop nop nop nop nop CNT26 incfsz tmcnt1l,f ;回転速度タイマー+1、オーバーフローしたら次をスキップ goto MEA1 incfsz tmcnt1h,f ;上位+1、オーバーフローでスキップ goto MEA2 ;******** オーバーフロー ******** movlw 0FFH movwf tmcnt1h movwf tmcnt1l MEA1 nop ;オーバーフローなし nop ;(31) MEA2 MOVLW 05H MOVWF CNTb ;33 MEA3 DECFSZ CNTb,F ;33+3*5-1=47 GOTO MEA3 nop goto MEAMAIN ;(50) ;********* EEPROM書きこみ操作 ************** EEP1 nop ;0でない(17) nop ;if文の時間合わせ nop EEP2 movf adcnth, w ;(20) movwf addrh movf adcntl, w movwf addrl movf tmcnt2h, w movwf datao movf tmcnt2l, w movwf datao2 movf tmcnt1h, w movwf datao3 movf tmcnt1l, w movwf datao4 ;(31) call EEPWT ; subroutine EEPWT=1253steps : (1286) clrf tmcnt2h ;1287 clrf tmcnt2l clrf tmcnt1h clrf tmcnt1l incf adcntl, f incf adcntl, f incf adcntl, f incfsz adcntl, f ;アドレスカウンター下位がオーバーフローしたら次をスキップ goto EEP3 ;下位オーバーフローせず(6) incfsz adcnth, f ;下位がオーバーフローしたので上位+1、さらにオーバーフローしたら次をスキップ goto EEP4 ;上位オーバーフローせず(8) ENDLOOP ;上位もオーバーフロー bcf PORTA, 2 ;IrLED消灯 bcf PORTA,3 ;LED点灯 call TIM1S ; bsf PORTA,3 ;LED消灯 call TIM1S goto ENDLOOP ;無限ループ EEP3 nop nop ;(1298) EEP4 movlw 1BH addwf tmcnt1l,f ;カウンタ下位に+27(1350step=270us) btfsc STATUS, C ;キャリーが発生しなかったら次をスキップ incfsz tmcnt1h,f ;キャリーが発生したので上位+1、その結果 ;もし0なら次をスキップ goto EEP5 movlw 0FFH ;上位までオーバーフロー movwf tmcnt1h movwf tmcnt1l EEP5 MOVLW 0EH ;(1305) MOVWF CNTb ;1306 EEP6 DECFSZ CNTb,F ;1306+3*14-1=1347 GOTO EEP6 nop goto MEAMAIN ;(1350) ;********* センサー感度調整モード ************ SNSADJ call TIME5M ;5ms待ち btfss PORTB, 1 ;SWがおされていたら(0)戻る goto SNSADJ call TIME5M call TIME5M btfss PORTB, 1 goto SNSADJ bsf PORTA, 2 ;IrLED ON SENSOR2 btfss PORTB, 1 ;スイッチが押されていなかったら(1)スキップ goto DATTMT ;おされたらデータ送信モードへ BTFSS PORTA,4 ;現在センサが1(暗)だったら次をスキップ GOTO SENSOR3 BSF PORTA,3 ;LED消灯 GOTO SENSOR2 SENSOR3 BCF PORTA,3 ;LED点灯 GOTO SENSOR2 ;********* データ送信モード ********** DATTMT bcf PORTA,2 ;IrLED OFF nop bsf PORTB, 2 ;232C初期化 call TIM1S TMT0 btfsc PORTB, 3 goto TMT0 clrf addrl movlw 80H movwf addrh TMT1 call EEPRD ; datai に読み出し movlw 0F0H andwf datai ,w ;datai上位をWに抽出 movwf DISBUF swapf DISBUF, f movlw 0AH subwf DISBUF,w ;DISBUF - 0AH ...DISBUF<=09HのときC=0 btfsc STATUS, C ;DISBUF<09Hのとき次をスキップ goto DISB1 movlw 30H ;DISBUF <= 09H addwf DISBUF, f goto DISB2 DISB1 movlw 37H ;DISBUF => 0AH addwf DISBUF, f DISB2 movf DISBUF, w movwf TXDATA call RSTRANS ;RS232C出力 movlw 0FH andwf datai ,w ;datai下位をWに抽出 movwf DISBUF movlw 0AH subwf DISBUF,w ;DISBUF - 0AH ...DISBUF<=09HのときC=0 btfsc STATUS, C ;DISBUF<09Hのとき次をスキップ goto DISB3 movlw 30H ;DISBUF <= 09H addwf DISBUF, f goto DISB4 DISB3 movlw 37H ;DISBUF => 0AH addwf DISBUF, f DISB4 movf DISBUF, w movwf TXDATA call RSTRANS ;RS232C出力 btfss addrl, 0 ;アドレス下位の0ビット目が1の場合(奇数アドレス)次をスキップ goto TMT2 ;偶数アドレスの場合CRを出力せずに次のアドレスへ movlw 0DH ; CR movwf TXDATA call RSTRANS ;RS232C出力 TMT2 incfsz addrl, f ;アドレス下位+1、オーバーフローで次をスキップ goto TMT1 ;オーバーフローなしでループ incfsz addrh, f ;アドレス上位+1、オーバーフローで次をスキップ goto TMT1 ;オーバーフローなしでループ TMT3 ;addrがオーバーフロー bcf PORTA,3 ;LED点灯 call TIM1S ; bsf PORTA,3 ;LED消灯 call TIM1S goto TMT3 ;無限ループ ;**************************************** ; write サブルーチン(4byte) ; アドレス : addrh, addrl ; データ : datao, datao2, datao3, datao4 ;**************************************** EEPWT movlw b'10100000' ;スレーブアドレス=0, write mode(1) movwf slave call BSTART ;generate start bit ;****** data transmit ********** movf slave,w ; move slave address(26) movwf txbuf ; into transmit buffer call TX ; and send it movf addrh,w ; move word address(h) movwf txbuf ; into transmit buffer call TX ; and send it movf addrl,w ; move word address(l) movwf txbuf ; into transmit buffer call TX ; and send it movf datao,w ; move data byte(1st) movwf txbuf ; to tranmit buffer call TX ; and transmit it movf datao2,w ; move data byte(2nd) movwf txbuf ; to tranmit buffer call TX ; and transmit it movf datao3,w ; move data byte(3rd) movwf txbuf ; to tranmit buffer call TX ; and transmit it movf datao4,w ; move data byte(4th) movwf txbuf ; to tranmit buffer call TX ; and transmit it ;****** stop bit 発生 ******* bcf PORTB, sdata ; make sure data line is low nop nop nop bsf PORTB, sclk ; set clock high nop nop nop bsf PORTB, sdata ; data goes high while clock high ; for stop bit nop nop bcf PORTB, sclk ; set clock low again nop nop nop ; **** End of stop bit **** retlw 0 ;******************************* ; read サブルーチン ; アドレス : addrh, addrl ; データ : datai ;******************************* EEPRD call BSTART ;generate start bit ;****** data transmit & recieve ********** movlw b'10100000' ; get slave address (write mode) movwf txbuf ; into transmit buffer call TX ; and send it movf addrh,w ; move word address(h) movwf txbuf ; into transmit buffer call TX ; and send it movf addrl,w ; move word address(l) movwf txbuf ; into transmit buffer call TX ; and send it call BSTART ;generate start bit movlw b'10100001' ; get slave address (read mode) movwf txbuf ; into transmit buffer call TX ; and send it call RX ;****** stop bit 発生 ******* bcf PORTB, sdata ; make sure data line is low nop nop nop bsf PORTB, sclk ; set clock high nop nop nop bsf PORTB, sdata ; data goes high while clock high ; for stop bit nop nop bcf PORTB, sclk ; set clock low again nop nop nop ; **** End of stop bit **** retlw 0 ; ********************************** ; ****** Transmit data subroutine ******* ; ********************************** ; TX movlw .8 ;(1) movwf count ; set the #bits to 8 ; TXLP bcf eeprom,do ; assume bit out is low btfsc txbuf, 7 ; is bit out really low? bsf eeprom,do ; otherwise data bit =1 ;** bit out *** btfss eeprom,do ; check for state of data bit to xmit goto bitlow ; bsf PORTB, sdata ; set data line high goto clkout ; go toggle the clock bitlow bcf PORTB, sdata ; output a low bit nop ;Time adjustment clkout bsf PORTB, sclk ; set clock line high nop nop nop nop bcf PORTB, sclk ; return clock line low ;** End of bit out *** rlf txbuf, F ; rotate txbuf left decfsz count, F ; 8 bits done? goto TXLP ; no - go again ;** bit in *** bsf eeprom,di ; assume input bit is high bsf STATUS, RP0 movlw b'10001010' ; make sdata an input line movwf TRISB bcf STATUS, RP0 bsf PORTB, sclk ; set clock line high nop ; just sit here a sec nop nop nop nop ; btfss PORTB, sdata ; read the data bit bcf eeprom, di ; input bit was low bcf PORTB, sclk ; set clock line low nop bsf STATUS, RP0 movlw b'00001010' ; make sdata an input line movwf TRISB bcf STATUS, RP0 ;** End of bit in *** nop btfsc eeprom,di ; check ack bit bsf PORTA, ackf ; set acknowledge fail LED if no ack retlw 0 ;******************************* ;**** Receive data routine ********* ;******************************* RX clrf datai ; clear input buffer movlw .8 ; set # bits to 8 movwf count bcf STATUS,0 ; make sure carry bit is low RXLP rlf datai, F ; rotate datai 1 bit left ;** bit in *** bsf eeprom,di ; assume input bit is high bsf STATUS, RP0 movlw b'10001010' ; make sdata an input line movwf TRISB bcf STATUS, RP0 bsf PORTB, sclk ; set clock line high nop ; just sit here a sec nop nop nop nop ; btfss PORTB, sdata ; read the data bit bcf eeprom, di ; input bit was low bcf PORTB, sclk ; set clock line low nop bsf STATUS, RP0 movlw b'00001010' ; make sdata an input line movwf TRISB bcf STATUS, RP0 ;** End of bit in *** btfsc eeprom,di bsf datai,0 ; set bit 0 if necessary decfsz count, F ; 8 bits done? goto RXLP ; no, do another bsf eeprom,do ; set ack bit = 1 ;** bit out *** btfss eeprom,do ; check for state of data bit to xmit goto bitlow2 ; bsf PORTB, sdata ; set data line high goto clkout2 ; go toggle the clock bitlow2 bcf PORTB, sdata ; output a low bit nop ;Time adjustment clkout2 bsf PORTB, sclk ; set clock line high nop nop nop nop bcf PORTB, sclk ; return clock line low ;** End of bit out *** retlw 0 ;****** start bit Subroutine ******* BSTART bsf PORTB, sdata ; make sure data is high nop bcf PORTB, sclk ; make sure clock is low nop bsf PORTB, sclk ; set clock high nop nop nop nop nop bcf PORTB, sdata ; data line goes low during ; high clock for start bit nop nop nop nop nop ; timing adjustment bcf PORTB, sclk ; start clock train nop nop retlw 0 ;****** End of start bit ******** ;************************************************ ;* RS232C transmit routine * ;* input TXDATA * ;************************************************ RSTRANS BCF PORTB, 2 MOVLW BTIME MOVWF SENDT TRANS10 DECFSZ SENDT,F GOTO TRANS10 MOVLW 08H MOVWF BITW NOP TRANS0 RRF TXDATA,F NOP BTFSS STATUS,C ; データ出力(LSBから) BCF PORTB, 2 BTFSC STATUS,C BSF PORTB, 2 MOVLW BTIME MOVWF SENDT TRANS11 DECFSZ SENDT,F GOTO TRANS11 DECFSZ BITW,F GOTO TRANS0 NOP NOP NOP NOP NOP NOP BSF PORTB, 2 MOVLW BTIME MOVWF SENDT TRANS12 DECFSZ SENDT,F ; STOPビット分ウェイト GOTO TRANS12 RETLW 00H ;********************************* ; タイマーサブルーチン ; TIME10 :10usec ; TIME100 :100usec ; TIME1M :1msec ; TIME5M :5msec ; TIM1S :1sec ;********************************* TIME100 ;100usec MOVLW 9H MOVWF CNTa T_LP1 CALL TIME10 ;2+(2+50+3)*9-1=496 DECFSZ CNTa,F GOTO T_LP1 NOP NOP RETURN ;500*0.2=100usec TIME10 ;10usec MOVLW 0FH MOVWF CNTb T_LP2 DECFSZ CNTb,F ;2+3*15-1=46 GOTO T_LP2 NOP NOP RETURN ;46+4=50, 50*0.2=10usec TIME1M ;1msec (approx.) MOVLW 0AH MOVWF CNTc T_LP3 CALL TIME100 ;2+(500+5)*10-1=5051 DECFSZ CNTc,F GOTO T_LP3 RETURN ;5053 (=1.0106msec) TIME5M ;5msec(about) MOVLW 32H MOVWF CNTd T_LP4 CALL TIME100 ;2+(500+5)*50-1=25251 DECFSZ CNTd,F GOTO T_LP4 RETURN ;25253 (=5050.6usec) TIM1S MOVLW 0C8H ;set 200 MOVWF CNTe T_LP5 CALL TIME5M ;2+(25253+5)*200-1=5051601 DECFSZ CNTe,F GOTO T_LP5 RETURN ;5051603 (=1,010,320.6usec) END