;************************************* ; Author : Mike Baird ; Program : Rx ; Date : September 7th,2009 ;************************************* List P=16F628a #include "P16F628a.INC" __config _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_ON & _LVP_OFF & _CP_OFF & _MCLRE_OFF ;*** Defines *** EXPIRE_TIMER EQU 0x12 LATCH_MASK EQU 0xFF VALID_BIT EQU 4 hdrcntmin EQU 0x0C ; minimum number of header bits to receive hdrcntmax EQU 0x10 ; maximum number of header bits to receive ; decoder time tolerances are set at : 0.5T, 1.5T, 2.5T ; measured in 9xinstr.time (9usec) counts T EQU .39 ; half frame 350 usec (= T * 9 usec) min_t EQU T/2 ; half frame (T) minimum time min_2t EQU 3*T/2 ; half frame (T) maximum time and full frame (2T) minimum time max_2t EQU 5*T/2 ; full frame (2T) maximum time packet_len EQU 5 ; packet length, check var. alloc! mrx_packet_len EQU 5 ; packet length, check var. alloc! #define RXBIT PORTB, 0 ; input port bit #define SKL BTFSC ; normal decoder logic input #define SKH BTFSS #define IF_SHORT flags, 0 ; Flags #define FIRST_HALF flags, 1 #define HEADER flags, 2 #define VALID flags, 7 if_short_val EQU 1 ; bit value of IF_SHORT flag first_half_val EQU 2 ; bit value of FIRST_HALF flag LCD_Port EQU PORTA RS EQU 0x04 RW EQU 0x06 E EQU 0x07 ;*** Cblock *** CBLOCK 0x20 Count1 ; For delay! CountA ; CountB ; TempHolder TempLCD Line bitcnt tmrval ; timer value bt ; receive byte buffer flags ; decode logic status btcnt ; byte counter mrx_buffer ; receive address buffer mrx_buffer1 ; receive packet buffer mtx_buffer2 mtx_buffer3 mtx_buffer4 mrx_bsum ; receive buffer, checksum ENDC ;*** Start of Ram *** Org 0x000 ; GOTO Start ; Org 0x004 ; ;*** Start CLRF PORTA ; PortA all low CLRF PORTB ; PortB all low MOVLW 0x07 ; Turn comparators off and enable pins for I/O MOVWF CMCON ; BSF STATUS,RP0 ; Bank 1 CLRF TRISA ; PortA all output MOVLW b'00000111' ; PortB Pin 1:2 must be input 0 for RX MOVWF TRISB ; ;*** UART Set Up *** MOVLW 0x19 ; 0x19 = 9600 BPS (0x0C = 19200 BPS) MOVWF SPBRG ; Baud Rate Generator Store Location BSF TXSTA,TXEN ; Transmit Enable bit BSF TXSTA,BRGH ; High Baud Rate Select bit BCF STATUS,RP0 ; Bank 0 BSF RCSTA,SPEN ; Serial Port Enable bit BSF RCSTA,CREN ; Continuous Receive Enable bit CALL Delay100 ; wait for LCD to settle CALL LCD_Init ; Initialize LCD ;*** Main *** CLRF Line MOVLW 'H' Call LCD_Char ; and display it MOVLW 'e' Call LCD_Char ; and display it MOVLW 'l' Call LCD_Char ; and display it MOVLW 'l' Call LCD_Char ; and display it MOVLW 'o' Call LCD_Char ; and display it Main: Call mrx_receive ; get packet ANDLW 0xFF BNZ Main ; reject if error code Call mrx_chk_buf ; test the checksum value ANDLW 0xFF BNZ Main ; reject packet if checksum fails MOVLW 0xAA ; check that packet address is correct (0xAA) SUBWF (mrx_buffer), W BNZ Main ; else reject packet MOVF mrx_buffer+1, W ; get data byte byte Call LCD_Char ; and display it MOVF mrx_buffer+2, W ; get data byte byte Call LCD_Char ; and display it MOVF mrx_buffer+3, W ; get data byte byte Call LCD_Char ; and display it MOVF mrx_buffer+4, W ; get data byte byte Call LCD_Char ; and display it GOTO Main ;*** Receive *** Receive: BTFSS PIR1,RCIF ; P1R1 is set when byte is recieved GOTO Receive ; MOVF RCREG,W ; Move received data into W RETURN ;*** Send *** Send: MOVWF TXREG ; Load W into TXREG BSF STATUS,RP0 ; RAM Page 1 Wait: btfss TXSTA,TRMT ; Transmission is complete when High GOTO Wait ; BCF STATUS,RP0 ; RAM Page 0 RETURN ;*** LCD routines *** LCD_Init MOVLW 0x20 ; Set to 4 bit mode CALL LCD_Cmd ; MOVLW 0x28 ; Set display shift to 1 CALL LCD_Cmd ; MOVLW 0x06 ; Set display move right after character sent CALL LCD_Cmd ; MOVLW 0x0C ; Set display on, don't underline cursor but flash it CALL LCD_Cmd ; CALL LCD_Clr ; Clear display RETURN LCD_Cmd MOVWF TempLCD SWAPF TempLCD,W ; Send upper nibble ANDLW 0x0F ; Clear upper 4 bits of W (Not to interfere with RS,RW and E) MOVWF LCD_Port BCF LCD_Port,RS ; RS line to 0 BSF LCD_Port,E ; Pulse the E line high NOP BCF LCD_Port,E MOVF TempLCD,W ; Send lower nibble ANDLW 0x0F ; Clear upper 4 bits of W MOVWF LCD_Port BCF LCD_Port,RS ; RS line to 0 BSF LCD_Port,E ; Pulse the E line high NOP BCF LCD_Port,E CALL Delay5 RETURN LCD_CharD ADDLW 0x30 ; Convert W to ASCII LCD_Char MOVWF TempLCD ; SWAPF TempLCD,W ; Send upper nibble ANDLW 0x0F ; Clear upper 4 bits of W MOVWF LCD_Port ; BSF LCD_Port,RS ; RS line to 1 BSF LCD_Port,E ; Pulse the E line high NOP BCF LCD_Port,E MOVF TempLCD,W ; Send lower nibble ANDLW 0x0F ; Clear upper 4 bits of W MOVWF LCD_Port BSF LCD_Port,RS ; RS line to 1 BSF LCD_Port,E ; Pulse the E line high NOP BCF LCD_Port,E CALL Delay5 RETURN LCD_Line1 MOVLW .128 ; Move to 1st row, first column CALL LCD_Cmd RETURN LCD_Line2 MOVLW .192 ; Move to 2nd row, first column CALL LCD_Cmd RETURN LCD_Line3 MOVLW 0x94 ; Move to 1st row, first column CALL LCD_Cmd RETURN LCD_Line4 MOVLW 0xD4 ; Move to 2nd row, first column CALL LCD_Cmd RETURN LCD_Line1W ADDLW 0x80 ; Move to 1st row, column W CALL LCD_Cmd RETURN LCD_Line2W ADDLW 0xC0 ; Move to 2nd row, column W CALL LCD_Cmd RETURN LCD_CurOn MOVLW 0x0D ; Set display on/off and cursor command CALL LCD_Cmd RETURN LCD_CurOff MOVLW 0x0C ; Set display on/off and cursor command CALL LCD_Cmd RETURN LCD_Clr MOVLW 0x01 ; Clear display CALL LCD_Cmd RETURN ;** Receive Routines *** ; Author: el@jap.hu ; http://jap.hu/electronic/ mrx_receive ; receive a full manchester-encoded packet s3 ; set flags: first_half=1, if_short=0 BSF FIRST_HALF s4 BCF IF_SHORT s5 ; init before the received packet MOVLW mrx_buffer ; set FSR to buffer start MOVWF FSR ; set byte counter MOVLW (packet_len+1) ; bytes / packet MOVWF btcnt BSF HEADER ; set header receive mode CLRF bitcnt ; counting bit1-s in this mode s2 ; wait for a pulse SKH RXBIT GOTO s2 s6 ; wait for end of (short) pulse up to min_2t CLRF tmrval s6_w SKH RXBIT GOTO s7 ; goto s7 at end of pulse INCF tmrval, F NOP MOVLW min_2t SUBWF tmrval, W BTFSS STATUS, C GOTO s6_w ; timeout, exit RETLW 1 ; illegal startbit s7 ; start timer CLRF tmrval s8 ; if (if_short & rxbit) goto s9 ; if (!if_short & !rxbit) goto s9 BTFSC IF_SHORT ; goto s10 GOTO s8_ss1 ; if_short = 1 s8_ss0 ; if_short = 0 SKL RXBIT GOTO s10 ; rxbit = 1, goto s10 s9_ss0 ; if (timer > max_2t) exit - else goto s8 MOVLW max_2t SUBWF tmrval, W BTFSC STATUS, C RETLW 2 ; signal too long INCF tmrval, F GOTO s8_ss0 s8_ss1 ; if_short = 1 SKH RXBIT GOTO s10 ; rxbit = 0, goto s10 s9_ss1 ; if (timer > max_2t) exit - else goto s8 MOVLW max_2t SUBWF tmrval, W BTFSC STATUS, C RETLW 2 ; signal too long INCF tmrval, F GOTO s8_ss1 s10 ; invert if_short MOVLW if_short_val XORWF flags, F s11 ; if (timer < min_t) exit MOVLW min_t SUBWF tmrval, W BTFSS STATUS, C RETLW 3 ; signal too short s12 ; if (timer < min_2t) goto s14 MOVLW min_2t SUBWF tmrval, W BTFSS STATUS, C GOTO s14 s13 ; if (first_half = 0) goto s16 - else exit BTFSS FIRST_HALF GOTO s16 RETLW 4 ; no mid-frame transition/out of sync s14 ; invert first_half MOVLW first_half_val XORWF flags, F s15 ; if (first_half = 1) goto 7 BTFSC FIRST_HALF GOTO s7 s16 ; if_short is a decoded bit. Handle here BTFSS HEADER GOTO s16_not_header ; header receiving mode BTFSS IF_SHORT GOTO s16_header_end ; header bit is 1 BTFSS bitcnt, 4 ; inc up to 16 INCF bitcnt, F ; 16 is enough... #ifdef NOMAXHDR MOVLW hdrcntmax ; test for max header length SUBWF bitcnt, W BTFSS STATUS, C #endif GOTO s7 ; loop back RETLW 9 ; header too long s16_header_end ; header ends indicated by a 0 BCF HEADER MOVLW hdrcntmin ; test for min header length SUBWF bitcnt, W BTFSS STATUS, C RETLW 0x0A ; header too short next_byte MOVLW 0x0A MOVWF bitcnt GOTO s7 ; loop back s16_not_header ; receiving bytes DECF bitcnt, F BZ s16_s4 ; if (bitcnt = 0) check for a byte-sep 1 MOVLW 1 ; if (bitcnt = 1) check for a byte-separator 0 XORWF bitcnt, W BNZ s16_s2 BTFSC IF_SHORT ; test for a byte separator 1 GOTO s7 RETLW 7 ; byte-ending 1 not present s16_s2 ; bit is data RRF flags, W RLF bt, F GOTO s7 s16_s4 ; check for a byte-separator 0 BTFSC IF_SHORT RETLW 8 ; byte-ending 0 not present MOVF bt, W ; OK, received byte is sane, store in buffer MOVWF INDF INCF FSR, F DECFSZ btcnt, F GOTO next_byte RETLW 0 ; OK, buffer received ; buffer checking is not done automatically! ; if returned value is 0, call mrx_chk_buf to check mrx_chk_buf ; check buffer sanity by chksum MOVLW mrx_buffer MOVWF FSR MOVLW (packet_len+1) ; number of bytes with the chksum byte MOVWF btcnt MOVLW 0xFF MOVWF bt ; used as sum register chk0 MOVF INDF, W ; fast CRC-8 algorithm with poly x^8+x^5+x^4+1 XORWF bt,f ; executes in 23 cycles per update CLRW BTFSC bt,7 XORLW 0x7A BTFSC bt,6 XORLW 0x3D BTFSC bt,5 XORLW 0x86 BTFSC bt,4 XORLW 0x43 BTFSC bt,3 XORLW 0xB9 BTFSC bt,2 XORLW 0xC4 BTFSC bt,1 XORLW 0x62 BTFSC bt,0 XORLW 0x31 MOVWF bt INCF FSR, F DECFSZ btcnt, F GOTO chk0 ; correct checksum must be zero MOVF bt, W BNZ chk_err RETLW 0 ; result is in Z chk_err RETLW 0x0C ; checksum error mrx_init RETURN ;*** Delay Routines *** Delay255 MOVLW d'255' ; Delay 255 mS GOTO d0 Delay100 MOVLW d'100' ; Delay 100mS GOTO d0 Delay50 MOVLW d'50' ; Delay 50mS GOTO d0 Delay20 MOVLW d'20' ; Delay 20mS GOTO d0 Delay5 MOVLW d'5' ; Delay 5.000 ms (4 MHz clock) d0 MOVWF Count1 d1 MOVLW 0xC7 ; Delay 1mS MOVWF CountA MOVLW 0x01 MOVWF CountB Delay_0 DECFSZ CountA,F GOTO $+2 DECFSZ CountB,F GOTO Delay_0 DECFSZ Count1,F GOTO d1 RETURN END