;---- simple data transfer chip RX ;---- 簡易データ受信チップ・ファームウェア ;---- by K.I since 020322 LIST P=12C509A INCLUDE P12C509A.INC __CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC __IDLOCS H'0100' ;V1.00 ;-------------------------------------------------------- ;-------------------------------------------------------- NOOP MACRO ;debug用 GOTO $+2 ;skip dummy XORLW H'FF' ;dummy ENDM REPAIR MACRO jump_to ;NOOP置換え用 NOP GOTO jump_to ENDM ;-------------------------------- RXE EQU 0 ;GP0, O, 受信イネーブル OUT0 EQU 1 ;GP1, O, bit0 OUT1 EQU 2 ;GP2, O, bit1 RXD EQU 3 ;GP3, I, 受信データ OUT2 EQU 4 ;GP4, O, bit2 OUT3 EQU 5 ;GP5, O, bit3 ;-------------------------------- GPIODIR EQU B'00001000' ;GPIO入出力設定 GPIOINI EQU B'00000000' ;GPIO InitValue OPT_INI EQU B'00011100' ;OPTION Init TX_IDLE EQU B'00011111' ; 'idle' TX_START EQU B'00011000' ; 'start' TX_END EQU B'00001101' ; 'end' TX_ERR EQU B'00000100' ; 'error' RX_MIN EQU 40 RX_N_MIN EQU 80 ;通信速度の範囲(7サイクル単位) RX_N_MAX EQU 160 ;(計算値は119で約833US) ;-------------------------------- CBLOCK H'07' ;12C509は07〜1Fが汎用レジスタ RXDATA ;受信データ GPIOX ;前回のGPIO値 OUTDATA ;データ出力用バッファ OUTBUF RXCOUNT ;RX汎用カウンタ RX_N0 ;Rx count0 RX_N1 ;Rx count1 RX_N2 ;Rx count2 RX_N3 ;Rx count3 RX_N4 ;Rx count4 RX_N WAIT_CN ;WAIT counter WAIT_CN2 ;WAIT counter2 LINE ;汎用バッファ BL_CN ERR_NO ;Error Number ENDC ;-------------------------------------------------------- ;-------------------------------------------------------- ORG 0 ;リセット・ベクタ ;-------------------------------------------------------- POWERUP GOTO SETUPPORTS ;-------------------------------------------------------- ORG 4 ;-------------------------------------------------------- DT "RX021116E" ;<-- **** Version **** ;-------------------------------------------------------- MAIN NOOP MOVF GPIO,W MOVWF GPIOX ;現在のGPIOを保存 ;---- idle信号を利用して通信速度を求める CALL RXINVCHK MOVLW 255-RX_MIN ;RX_MIN幅より小さければ雑音として無視する ADDWF RXCOUNT,W BTFSS STATUS,C SLEEP MOVF RXCOUNT,W MOVWF RX_N0 ;RX_N0←B0-B1の時間 CALL RXINVCHK MOVLW 255-RX_MIN ;RX_MIN幅より小さければ雑音として無視する ADDWF RXCOUNT,W BTFSS STATUS,C SLEEP MOVF RXCOUNT,W MOVWF RX_N1 ;RX_N1←B1-B2の時間 CALL RXINVCHK MOVLW 255-RX_MIN ;RX_MIN幅より小さければ雑音として無視する ADDWF RXCOUNT,W BTFSS STATUS,C SLEEP MOVF RXCOUNT,W MOVWF RX_N2 ;RX_N2←B2-B3の時間 CALL RXINVCHK MOVLW 255-RX_MIN ;RX_MIN幅より小さければ雑音として無視する ADDWF RXCOUNT,W BTFSS STATUS,C SLEEP MOVF RXCOUNT,W MOVWF RX_N3 ;RX_N3←B3-B4の時間 CALL RXINVCHK MOVLW 255-RX_MIN ;RX_MIN幅より小さければ雑音として無視する ADDWF RXCOUNT,W BTFSS STATUS,C SLEEP MOVF RXCOUNT,W MOVWF RX_N4 ;RX_N4←B4-B5の時間 CALL RX_CALC ;(RX_N3+RX_N4)/4→RX_Nを求める CALL WAIT_HALF ;RX_N/2待ち(信号の中心位置を見るため) CALL READ_1B ;1ビット読み込み BTFSS STATUS,C GOTO CHK_START ;信号0ならばSTARTチェックへ CALL READ_1B ;1ビット読み込み BTFSS STATUS,C GOTO CHK_START ;信号0ならばSTARTチェックへ GOTO ERR_SLEEP CHK_START CALL READ_1B ;1ビット読み込み BTFSC STATUS,C ;2個目の0信号をチェック GOTO ERR_SLEEP CALL READ_1B ;1ビット読み込み BTFSC STATUS,C ;3個目の0信号をチェック GOTO ERR_SLEEP START ;3個0信号が続いたのでスタート NOOP ;(START=11000) DATA_LOOP NOOP CALL READ_5B ;READ_5B→データを5ビット分読む MOVF RXDATA,W XORLW TX_END BTFSC STATUS,Z GOTO DATA_END ;ENDなら終わり CALL OUT_5B ;データの表示出力 GOTO DATA_LOOP ;繰り返し DATA_END CALL WAIT_250MS ;約0.75秒待ってから CALL WAIT_250MS ;(Tx側は連続モードに入るのに約1秒 CALL WAIT_250MS ; なのでその前にSLEEPに入るように) NOP FADE_OUT CALL BLINK_OFF ;表示をOFFして SLEEP ;SLEEPに入る ;-------------------------------------------------------- ; 5bit-NRZI 信号の受信 READ_5B CALL READ_1B ;Read bit0 MOVWF RXDATA CALL READ_1B ;Read bit1 RLF RXDATA,F CALL READ_1B ;Read bit2 RLF RXDATA,F CALL READ_1B ;Read bit3 RLF RXDATA,F CALL READ_1B ;Read bit4 RLF RXDATA,F RETLW 0 ;-------------------------------------------------------- ; 5bitデータを5B/4Bテーブルで、4bitに変換して出力する OUT_5B NOOP CALL CNV_RXDATA NOOP MOVWF OUTDATA NOOP BTFSC OUTDATA,7 ;bit7 check GOTO ERR_DATA OUT_4B NOOP MOVF GPIO,W ANDLW B'00000001' ;RXE COPY MOVWF OUTBUF BTFSC OUTDATA,0 ;bit0 check BSF OUTBUF,OUT0 ;OUT0 set BTFSC OUTDATA,1 ;bit1 check BSF OUTBUF,OUT1 ;OUT1 set BTFSC OUTDATA,2 ;bit2 check BSF OUTBUF,OUT2 ;OUT2 set BTFSC OUTDATA,3 ;bit3 check BSF OUTBUF,OUT3 ;OUT3 set MOVF OUTBUF,W MOVWF GPIO RETLW 0 ;-------------------------------------------------------- ; RXが反転するまでカウントしてRXCOUNTを返す ; 前回のGPIO値をGPIOXにセットしてコール RXINVCHK CLRF RXCOUNT BTFSS GPIOX,RXD ;前回のGPIO値 GOTO WRISE ;Low GOTO WFALL ;High ;-------------------------------------------------------- ; READ 1bit ; RX_Nの間にデータが反転しなければ、信号0 ; 反転すれば同期をとって(カウンタリセット) ; RX_N/2の間反転しなければ、信号1とする。 ; 反転したら、エラー READ_1B MOVF RX_N,W MOVWF RXCOUNT ;RX_NをRXCOUNTにセット BTFSS GPIOX,RXD ;前回のGPIO値 GOTO R1B_WRISE ;Low GOTO R1B_WFALL ;High ;-------------------------------------------------------- ; RX_N/2待ちルーチン。途中で反転したらエラー WAIT_HALF NOOP BCF STATUS,C RRF RX_N,W MOVWF RXCOUNT ;RX_N/2をRXCOUNTにセット BTFSS GPIOX,RXD ;前回のGPIO値 GOTO WH_WRISE ;Low GOTO WH_WFALL ;High ;-------------------------------------------------------- ; RX速度計算と範囲チェック RX_CALC BCF STATUS,C MOVF RX_N3,W ;RXの速度計算 ADDWF RX_N4,W MOVWF RX_N RRF RX_N,F ;RX_N=(RX_N3+RX_N4)/2 MOVLW RX_N_MAX-RX_N_MIN+1 MOVWF LINE MOVLW 255-RX_N_MAX ;RX_N範囲はRX_N_MIN〜RX_N_MAX ADDWF RX_N,W ADDWF LINE,W BTFSS STATUS,C ;RX_Nが範囲外であれば、ERR_RANGE GOTO ERR_RANGE RETLW 0 ;-------------------------------------------------------- ;RXDATAの値を5B/4B変換してWに入れて返す CNV_RXDATA NOOP MOVF RXDATA,W ;WにRXDATA(5bit)を入れる TAB5B4B ;4B/5B変換用テーブル ADDWF PCL,F RETLW B'11111111' ; 00 RETLW B'11111111' ; 01 RETLW B'11111111' ; 02 RETLW B'11111111' ; 03 RETLW B'11111111' ; 04 RETLW B'11111111' ; 05 RETLW B'11111111' ; 06 RETLW B'11111111' ; 07 RETLW B'11111111' ; 08 RETLW B'00000001' ; 09-->'1' RETLW B'00000100' ; 0A-->'4' RETLW B'00000101' ; 0B-->'5' RETLW B'11111111' ; 0C RETLW B'11111111' ; 0D-->'end' RETLW B'00000110' ; 0E-->'6' RETLW B'00000111' ; 0F-->'7' RETLW B'11111111' ; 10 RETLW B'11111111' ; 11 RETLW B'00001000' ; 12-->'8' RETLW B'00001001' ; 13-->'9' RETLW B'00000010' ; 14-->'2' RETLW B'00000011' ; 15-->'3' RETLW B'00001010' ; 16-->'A' RETLW B'00001011' ; 17-->'B' RETLW B'11111111' ; 18-->'start' RETLW B'11111111' ; 19 RETLW B'00001100' ; 1A-->'C' RETLW B'00001101' ; 1B-->'D' RETLW B'00001110' ; 1C-->'E' RETLW B'00001111' ; 1D-->'F' RETLW B'00000000' ; 1E-->'0' RETLW B'11111111' ; 1F-->'idle' ;-------------------------------------------------------- ERR_SLEEP NOOP ERR_START ERR_RANGE ERR_HALF1 ERR_OVER ERR_DATA SLEEP NOOP MOVF ERR_NO,W CALL BLINK MOVF RX_N0,W CALL BLINK MOVF RX_N1,W CALL BLINK MOVF RX_N2,W CALL BLINK MOVF RX_N,W GOTO BLINK_SLEEP ;-------------------------------------------------------- BLINK_SLEEP NOOP CALL BLINK SLEEP ;-------------------------------------------------------- BLINK ; Wの値を表示、RxEをBN_N+1回点滅 NOOP MOVWF OUTDATA ; Wの値をOUTDATAに入れ INCF BL_CN,F MOVF BL_CN,W MOVWF LINE SWAPF OUTDATA,F ; OUTDATAのHighニブルを CALL OUT_4B ; 表示する BL_LOOP BSF GPIO,RXE ; LED ON(RxEを0.25秒で点滅) CALL WAIT_250MS ; wait 250ms BCF GPIO,RXE ; LED OFF CALL WAIT_250MS ; wait 250ms DECFSZ LINE,F ; BL_N+1回点滅させる GOTO BL_LOOP SWAPF OUTDATA,F ; OUTDATAのLowニブルを CALL OUT_4B ; 表示する BSF GPIO,RXE ; LED ON(RxEを0.5秒点灯) CALL WAIT_250MS ; wait 250ms CALL WAIT_250MS ; wait 250ms BLINK_OFF CLRF OUTDATA ; 全てのLEDをOFFする CALL OUT_4B ; BCF GPIO,RXE ; RxEもOFFする RETLW 0 ;-------------------------------- WAIT_250MS MOVLW 250 ;1001*250+5+1US=250.256MS WAIT_MS MOVWF WAIT_CN ;1001*CN+5 US WAIT_MS0 MOVLW 249 ;1;249 MOVWF WAIT_CN2 ;1; WAIT_MS1 NOP ;1; DECFSZ WAIT_CN2,1 ;1; GOTO WAIT_MS1 ;2;4usx249 DECFSZ WAIT_CN,1 ;1; GOTO WAIT_MS0 ;2;WAIT_CN*1001us RETLW 0 ;CALL(2)+(1)+(5+4*249)*CN+RET(2)=1001*CN+5US ;-------------------------------- WAIT_US MOVWF WAIT_CN ;1; WAIT_US0 GOTO $+1 ;2; DECFSZ WAIT_CN,1 ;1; GOTO WAIT_US0 ;2;WAIT_CN*5us WAIT_4US RET_POINT RETLW 0 ;2;CALL(2)+(1)+(5)*CN+RET(2)=5*CN+5US ;-------------------------------------------------------- ;-------------------------------------------------------- ORG 0x100 ;-------------------------------------------------------- SETUPPORTS NOOP MOVLW OPT_INI ;WAKE-UP,PULL-UP,1:16 WDT PRESCALER OPTION MOVLW GPIODIR ;Set I/O direction TRIS GPIO MOVLW GPIOINI ;Init I/O data MOVWF GPIO CLRF RX_N0 CLRF RX_N1 CLRF RX_N2 CLRF BL_CN CLRF ERR_NO CHK_WAKEUP BTFSC STATUS,GPWUF GOTO MAIN ;GP Wake-UpならばMAINへ CLRF BL_CN MOVLW H'A5' ;それ以外はTEST-SLEEP GOTO BLINK_SLEEP ;-------------------------------------------------------- WRISE INCFSZ RXCOUNT,F GOTO $+2 GOTO ERR_OVER BTFSS GPIO,RXD GOTO WRISE ; 立上がり BTFSS GPIO,RXD GOTO WRISE BTFSS GPIO,RXD GOTO WRISE BSF GPIOX,RXD BSF GPIO,RXE ; LED ON RETLW 0 WFALL INCFSZ RXCOUNT,F GOTO $+2 GOTO ERR_OVER BTFSC GPIO,RXD GOTO WFALL BTFSC GPIO,RXD GOTO WFALL BTFSC GPIO,RXD GOTO WFALL BCF GPIOX,RXD BCF GPIO,RXE ; LED OFF RETLW 0 ;-------------------------------------------------------- R1B_WRISE DECFSZ RXCOUNT,F GOTO $+3 BCF STATUS,C RETLW 0 ;終了(READ_1B用に0を返す) BTFSS GPIO,RXD GOTO R1B_WRISE BTFSS GPIO,RXD GOTO R1B_WRISE BTFSS GPIO,RXD GOTO R1B_WRISE BSF GPIOX,RXD BSF GPIO,RXE ; LED ON GOTO WAIT_HALF R1B_WFALL DECFSZ RXCOUNT,F GOTO $+3 BCF STATUS,C RETLW 0 ;終了(READ_1B用に0を返す) BTFSC GPIO,RXD GOTO R1B_WFALL BTFSC GPIO,RXD GOTO R1B_WFALL BTFSC GPIO,RXD GOTO R1B_WFALL BCF GPIOX,RXD BCF GPIO,RXE ; LED OFF GOTO WAIT_HALF ;-------------------------------------------------------- WH_WRISE DECFSZ RXCOUNT,F GOTO $+3 BSF STATUS,C RETLW 1 ;終了(READ_1B用に1を返す) BTFSS GPIO,RXD GOTO WH_WRISE BTFSS GPIO,RXD GOTO WH_WRISE BTFSS GPIO,RXD GOTO WH_WRISE BSF GPIOX,RXD BSF GPIO,RXE ; LED ON GOTO YAPPA_0 ;RXが反転したら0 WH_WFALL DECFSZ RXCOUNT,F GOTO $+3 BSF STATUS,C RETLW 1 ;終了(READ_1B用に1を返す) BTFSC GPIO,RXD GOTO WH_WFALL BTFSC GPIO,RXD GOTO WH_WFALL BTFSC GPIO,RXD GOTO WH_WFALL BCF GPIOX,RXD BCF GPIO,RXE ; LED OFF GOTO YAPPA_0 ;RXが反転したら0 YAPPA_0 DECFSZ RXCOUNT,F GOTO $+3 BCF STATUS,C RETLW 0 ;終了(READ_1B用に0を返す) GOTO YAPPA_0 ;-------------------------------------------------------- END ;-------------------------------------------------------- ORG 0x3FF ;-------------------------------------------------------- SLEEP