;****************************************************************** ;* * ;* Filename: teleinfo.asm * ;* * ;* J-Paul ROUBELAT - F6FBB - 29 March 2009 * ;* * ;****************************************************************** list p=12f675 ; list directive to define processor #include __CONFIG _BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT #define SENSOR_T 0xc #define SENSOR_A 0x7 #define STX 0x02 #define ETX 0x03 #define LF 0x0a #define CR 0x0d #define SP 0x20 #define LABEL_LEN .8 #define VALUE_LEN .12 ;****************************************************************************** ; file register variables ; cblock 0x20 ;0x20-0x5f banks 0 baud_delay ; delay counter for baudrate rx_wait rx_count rx_data rx_chck rx_ctrl rx_par ; parity nb_fram ; nb de trames led_ct ; LED timer lab:LABEL_LEN val:VALUE_LEN control dt_count v_int:2 ; intensity value v_wtt:4 ; base value 32bits v_rate ; current rate p_rate ; rate of alternate power temp:4 ; temporary storage tabtmp ; table address computation sn_type ; sensor message sn_addr sn_watt:4 sn_int:3 sn_rate sn_xor sn_chck num_opt char_pos table_pos flags ; 8 flags endc #define RS_IN GPIO,2 #define LED GPIO,1 #define TX GPIO,0 #define BAUDRATE (.208 - .4) ; 1200 Bauds TABLE_JUMP MACRO MOVWF tabtmp ; save wanted offset MOVLW LOW($+8) ; get low adress ( of first instr. after macro ) ADDWF tabtmp,F ; add offset MOVLW HIGH($+6) ; get highest 5 bits ( of first instr. after macro ) BTFSC STATUS,C ; page crossed ? ( 256 byte ) ADDLW 0x01 ; Yes add one to high adress MOVWF PCLATH ; load high adress in latch MOVF tabtmp,W ; get computed adress MOVWF PCL ; And jump ENDM ;****************************************************************************** ; RESET VECTOR * ;****************************************************************************** org 0 goto _init ;****************************************************************************** ; INTERRUPT ROUTINE (unused) ;****************************************************************************** org 4 retfie ;****************************************************************************** ; MAINLINE CODE ;****************************************************************************** _init clrf GPIO movlw b'00000111' ; comp off |B0 movwf CMCON ; |B0 bsf STATUS,RP0 ; bank 1 |B1 ; timer 0 configuration, prescaler to WDT (#1sec), no pull-ups movlw b'10001110' ; timer0 on internal clock, |B1 movwf OPTION_REG ; and pull-ups -> option register clrf VRCON ; disable Voltage Reference |B1 movlw B'00000000' ; Configure analog |B1 movwf ANSEL ; inputs |B1 movlw b'11000100' ; GP2=IN GP0,1,3,4,5=OUT |B1 movwf TRISIO ; Set GPIO for intput/output |B1 call 3FFh movwf OSCCAL ; calibrate oscillator clrf INTCON ; clear irq flags |B1 clrf PIE1 ; clear peripheral irq flags |B1 bcf STATUS,RP0 ; select bank 0 |B0 bcf LED ; led OFF clrf v_rate clrf p_rate clrf flags ;****************************************************************************** ; MAIN LOOP ;****************************************************************************** _main_loop movlw .32 movwf nb_fram ; Frames number before sending data clrf v_int clrf v_int+1 _loop movfw v_rate ; current rate movwf sn_rate call _frame decfsz nb_fram,F goto _loop call _delay1s ; Send the HF frame call _send_data call _delay1s incf p_rate,W ; Second frame holds alternate info andlw 0x0f movwf p_rate movwf sn_rate ; search this power value xorwf v_rate,W ; if sn_rate is v_rate send the same frame btfsc STATUS,Z goto _resend bcf flags,0 call _frame call _delay1s btfss flags,0 goto _resend movfw p_rate movwf v_int+1 ; lsb = sent rate rlf v_int+1,f ; mult by 2 movlw 0x1e movwf v_int ; msb = 0xf (alternate) mult by 2 call _send_data ; if the power is found send alternate goto _end_loop _resend movfw v_rate ; current rate movwf sn_rate call _send_frame ; not found... send same frame _end_loop call _delay1s goto _main_loop ;****************************************************************************** ; Read an information frame ;****************************************************************************** _frame ; wait for STX = begin of frame call _rx_char iorlw 0 btfsc STATUS,Z goto _frame ; rxchar error movfw rx_data xorlw STX btfss STATUS,Z goto _frame bsf LED ; LED on movlw .2 ; 20ms movwf led_ct _next_msg call _get_msg iorlw 0 btfsc STATUS,Z goto _frame movfw rx_data xorlw ETX btfsc STATUS,Z return ; End of frame ; process intensity message movlw 'I' xorwf lab,W btfss STATUS,Z goto _p_msg1 movlw 'I' xorwf lab+1,W btfss STATUS,Z goto _p_msg1 movlw 'N' xorwf lab+2,W btfss STATUS,Z goto _p_msg1 movlw 'S' xorwf lab+3,W btfss STATUS,Z goto _p_msg1 call _p_int goto _next_msg _p_msg1 ; process option message movlw 'P' xorwf lab,W btfss STATUS,Z goto _p_msg2 movlw 'T' xorwf lab+1,W btfss STATUS,Z goto _p_msg2 movlw 'E' xorwf lab+2,W btfss STATUS,Z goto _p_msg2 movlw 'C' xorwf lab+3,W btfss STATUS,Z goto _p_msg2 call _p_ptec goto _next_msg _p_msg2 ; find message depending of option clrw call _conv_popt xorwf lab+0,W btfss STATUS,Z goto _next_msg movfw lab+1 btfsc STATUS,Z goto _p_msg_ok movlw .1 call _conv_popt xorwf lab+1,W btfss STATUS,Z goto _next_msg movfw lab+2 btfsc STATUS,Z goto _p_msg_ok movlw .2 call _conv_popt xorwf lab+2,W btfss STATUS,Z goto _next_msg movfw lab+3 btfsc STATUS,Z goto _p_msg_ok movlw .3 call _conv_popt xorwf lab+3,W btfss STATUS,Z goto _next_msg movfw lab+4 btfsc STATUS,Z goto _p_msg_ok movlw .4 call _conv_popt xorwf lab+4,W btfss STATUS,Z goto _next_msg movfw lab+5 btfsc STATUS,Z goto _p_msg_ok movlw .5 call _conv_popt xorwf lab+5,W btfss STATUS,Z goto _next_msg movfw lab+6 btfsc STATUS,Z goto _p_msg_ok movlw .6 call _conv_popt xorwf lab+6,W btfss STATUS,Z goto _next_msg _p_msg_ok bsf flags,0 call _p_base ; base get value goto _next_msg _p_msg3 goto _next_msg ;****************************************************************************** ; Gestion de l'intensité ;****************************************************************************** _p_int ; get 3 digits 0->255 goto _conv_int ;****************************************************************************** ; Gestion de l'option ;****************************************************************************** _p_ptec goto _conv_ptec ;****************************************************************************** ; Gestion de l'intensité ;****************************************************************************** _p_base ; get MSB 0->65535 goto _conv_base ;****************************************************************************** ; Gestion de l'intensité ;****************************************************************************** _conv_int movlw 0x0f ; Bit pattern to strip off ASCII offset andwf val+2,W ; convert ASCII value to a number (units) movwf temp ; start the running total (units) rlf val+1,W ; read 2*DIGIT2 doing (tens) andlw 0x1e ; clear ASCII offset + odd bits addwf temp,F ; add to running total total 2T + U addwf temp,F ; add to running total total 4T + U addwf temp,F ; add to running total total 6T + U addwf temp,F ; add to running total total 8T + U addwf temp,F ; add to running total total 10T + U movlw '1' ; (Hundred) digit can only usefully be 1 or 2 subwf val,W ; test value of DIGIT1 (sets flags) movlw 0x00 ; clear value to add to total btfsc STATUS,C ; test if result negative ie DIGIT1 was <='0' movlw .200 ; DIGIT1 was >'0', total needs inc by 100 or 200 btfsc STATUS,Z ; test if result = '1' movlw .100 ; DIGIT1 was = '1' inc total by 100 addwf temp,f ; add 0, 100 or 200 to total as req movfw temp ; add to mesures addwf v_int+1,f btfsc STATUS,C incf v_int,f return ;****************************************************************************** ; Get an information message ;****************************************************************************** _get_msg ; wait for LF call _rx_char iorlw 0 btfsc STATUS,Z retlw 0 ; rxchar error movfw rx_data xorlw ETX ; end message ? btfsc STATUS,Z retlw 1 movfw rx_data xorlw LF ; end message ? btfss STATUS,Z goto _get_msg ; clear checksum, lab and value clrf rx_chck movlw LABEL_LEN movwf dt_count movlw lab ; set index movwf FSR _clr1 clrf INDF incf FSR,F decfsz dt_count,F goto _clr1 movlw VALUE_LEN movwf dt_count movlw val ; set index movwf FSR _clr2 clrf INDF incf FSR,F decfsz dt_count,F goto _clr2 _get_label ; get lab movlw lab ; set index movwf FSR _gl movlw LABEL_LEN movwf dt_count call _rx_char iorlw 0 btfsc STATUS,Z retlw 0 ; rxchar error movfw rx_data xorlw SP btfsc STATUS,Z goto _get_value movfw rx_data movwf INDF incf FSR,f decfsz dt_count,F goto _gl retlw 0 ; error... _get_value ; get value movlw val ; set index movwf FSR _gv movlw VALUE_LEN movwf dt_count call _rx_char iorlw 0 btfsc STATUS,Z retlw 0 ; rxchar error movfw rx_data xorlw SP btfsc STATUS,Z goto _get_control movfw rx_data movwf INDF incf FSR,f decfsz dt_count,F goto _gv retlw 0 ; error... _get_control ; get control movlw 0xe0 ; substract 0x20 addwf rx_chck,F movlw 0x3f andwf rx_chck,F movlw 0x20 addwf rx_chck,W ; check control movwf rx_ctrl call _rx_char iorlw 0 btfsc STATUS,Z retlw 0 ; rxchar error movfw rx_data movwf control _get_return ; get return call _rx_char iorlw 0 btfsc STATUS,Z retlw 0 ; rxchar error movfw rx_data xorlw CR btfss STATUS,Z retlw 0 ; error retlw 1 ; message received ;****************************************************************************** ; Send a HF data frame ;****************************************************************************** _send_data ; prepare the frame movlw SENSOR_T movwf sn_type movlw SENSOR_A movwf sn_addr ; get power LSB 16 bits swapf v_wtt+2,w andlw 0xf movwf sn_watt+0 movfw v_wtt+2 andlw 0xf movwf sn_watt+1 swapf v_wtt+3,w andlw 0xf movwf sn_watt+2 movfw v_wtt+3 andlw 0xf movwf sn_watt+3 ; divide intensity by 2 -> send intensity * 16 bcf STATUS,C rrf v_int+0,f rrf v_int+1,f movfw v_int+0 andlw 0xf movwf sn_int+0 swapf v_int+1,w andlw 0xf movwf sn_int+1 movfw v_int+1 andlw 0xf movwf sn_int+2 clrw xorwf sn_type,w xorwf sn_addr,w xorwf sn_watt+0,w xorwf sn_watt+1,w xorwf sn_watt+2,w xorwf sn_watt+3,w xorwf sn_int+0,w xorwf sn_int+1,w xorwf sn_int+2,w xorwf sn_rate,w movwf sn_xor ; check xor movlw .5 addwf sn_type,w addwf sn_addr,w addwf sn_watt+0,w addwf sn_watt+1,w addwf sn_watt+2,w addwf sn_watt+3,w addwf sn_int+0,w addwf sn_int+1,w addwf sn_int+2,w addwf sn_rate,w addwf sn_xor,w andlw 0xf ; get LSB movwf sn_chck ; check sum _send_frame ; send the frame clrw ; 10 bits 0 header call _send_nib clrw call _send_nib call _send_0 call _send_0 call _send_1 movfw sn_type call _send_nib call _send_1 movfw sn_addr call _send_nib call _send_1 movfw sn_watt+3 call _send_nib call _send_1 movfw sn_watt+2 call _send_nib call _send_1 movfw sn_watt+1 call _send_nib call _send_1 movfw sn_watt+0 call _send_nib call _send_1 movfw sn_int+2 call _send_nib call _send_1 movfw sn_int+1 call _send_nib call _send_1 movfw sn_int+0 call _send_nib call _send_1 movfw sn_rate call _send_nib call _send_1 movfw sn_xor call _send_nib call _send_1 movfw sn_chck call _send_nib call _send_1 return ;****************************************************************************** ; send_nibble : send the LSB nibble of W ;****************************************************************************** _send_nib movwf temp call _send_bit call _send_bit call _send_bit goto _send_bit _send_bit rrf temp,f btfsc STATUS,C goto _send_1 goto _send_0 _send_0 bsf TX call _d_400 call _d_400 bcf TX goto _d_400 _send_1 bsf TX call _d_400 bcf TX call _d_400 goto _d_400 _d_400 movlw .98 movwf baud_delay goto _rx_delay ;****************************************************************************** ; RX RECEIVE ;****************************************************************************** _rx_char clrwdt ; clear watchdog btfss RS_IN ; check for stop bit goto _rx_char _rx_char1 clrwdt ; clear watchdog btfsc RS_IN ; wait for start bit goto _rx_char1 movlw .8 ; get 8 bits (stop is not checked) movwf rx_count clrf rx_par ; clear parity movlw BAUDRATE/2 movwf baud_delay ; 1/2 bit delay call _rx_delay ; wait btfsc RS_IN ; check start bit goto _rx_char _rx_next movlw BAUDRATE movwf baud_delay ; 1 bit delay call _rx_delay ; wait bcf STATUS,C btfsc RS_IN bsf STATUS,C rrf rx_data,F movfw rx_data xorwf rx_par,F decfsz rx_count,F goto _rx_next btfsc rx_par,7 ; check parity retlw 0 ; parity error movlw 0x7f ; strip parity andwf rx_data,W movwf rx_data addwf rx_chck,F ; checksum ; decrement LED timing decf led_ct,f btfsc STATUS,Z bcf LED ; clear LED retlw 1 ; OK _rx_delay nop decfsz baud_delay,F goto _rx_delay return ;****************************************************************************** ; 9xAscii to 4xBin ;****************************************************************************** _add32 andlw 0x0f addwf v_wtt+3, F bcf STATUS,Z btfsc STATUS,C incf v_wtt+2, F btfsc STATUS,Z incf v_wtt+1, F btfsc STATUS,Z incf v_wtt+0, F return ; (v_wtt0..v_wtt3) += W _mul10 bcf STATUS,C ; multiply by 2 and save (2*N) rlf v_wtt+3, F movfw v_wtt+3 movwf temp+3 rlf v_wtt+2, F movfw v_wtt+2 movwf temp+2 rlf v_wtt+1, F movfw v_wtt+1 movwf temp+1 rlf v_wtt+0, F movfw v_wtt+0 movwf temp+0 bcf STATUS,C ; multiply by 2 (4*N) rlf v_wtt+3, F rlf v_wtt+2, F rlf v_wtt+1, F rlf v_wtt+0, F bcf STATUS,C ; multiply by 2 (8*N) rlf v_wtt+3, F rlf v_wtt+2, F rlf v_wtt+1, F rlf v_wtt+0, F movfw temp+3 ; Add (2*N) = (10*N) addwf v_wtt+3, F btfsc STATUS,C incf v_wtt+2,F movfw temp+2 addwf v_wtt+2, F btfsc STATUS,C incf v_wtt+1,F movfw temp+1 addwf v_wtt+1, F btfsc STATUS,C incf v_wtt+0,F movfw temp+0 addwf v_wtt+0, F return ; (v_wtt0..v_wtt3) *= 10 _conv_base clrf v_wtt+0 clrf v_wtt+1 clrf v_wtt+2 clrf v_wtt+3 movfw val+0 call _add32 call _mul10 movfw val+1 call _add32 call _mul10 movfw val+2 call _add32 call _mul10 movfw val+3 call _add32 call _mul10 movfw val+4 call _add32 call _mul10 movfw val+5 call _add32 call _mul10 movfw val+6 call _add32 call _mul10 movfw val+7 call _add32 call _mul10 movfw val+8 call _add32 return ; Ascii/BCD to binary conversion done ;****************************************************************************** ; delay # 1.5 seconde using the watchdog timer ;****************************************************************************** _delay1s sleep return ;****************************************************************************** ; Returns the number of the string matching val (0..15) ;****************************************************************************** _conv_ptec clrf v_rate _co_0 movfw v_rate call _get_tper xorlw .0 btfsc STATUS,Z retlw 0 ; string not found -> return xorwf val+0,W btfsc STATUS,Z goto _co_1 ; 1st char OK incf v_rate,F ; not match incf v_rate,F incf v_rate,F incf v_rate,F goto _co_0 _co_1 incf v_rate,F movfw v_rate call _get_tper xorwf val+1,W btfsc STATUS,Z goto _co_2 ; 2nd char OK incf v_rate,F ; not match incf v_rate,F incf v_rate,F goto _co_0 _co_2 incf v_rate,F movfw v_rate call _get_tper xorwf val+2,W btfsc STATUS,Z goto _co_3 ; 3rd char OK incf v_rate,F ; not match incf v_rate,F goto _co_0 _co_3 incf v_rate,F movfw v_rate call _get_tper xorwf val+3,W btfsc STATUS,Z goto _co_ok incf v_rate,F goto _co_0 ; not match _co_ok ; 4th char OK bcf STATUS,C ; divide v_rate by 4 rrf v_rate,F bcf STATUS,C rrf v_rate,F retlw 1 ;****************************************************************************** ; Returns the character at the offset given by W ;****************************************************************************** _get_tper TABLE_JUMP DT " " DT "TH.." DT "HC.." DT "HP.." DT "HN.." DT "PM.." DT " " DT " " DT "HCJB" DT "HPJB" DT "HCJW" DT "HPJW" DT "HCJR" DT "HPJR" DT 0x0 ;****************************************************************************** ; Returns the number of the string matching lab (0..15) ;****************************************************************************** org 0x300 _conv_popt movwf char_pos clrf table_pos movfw sn_rate movwf num_opt rlf num_opt,F ; Multiply by 8 rlf num_opt,F rlf num_opt,F movfw char_pos addwf num_opt,W call _get_topt return _get_topt TABLE_JUMP DT 0,0,0,0,0,0,0,0 DT "BASE",0,0,0,0 DT "HCHC",0,0,0,0 DT "HCHP",0,0,0,0 DT "EJPHN",0,0,0 DT "EJPHPM",0,0 DT 0,0,0,0,0,0,0,0 DT 0,0,0,0,0,0,0,0 DT "BBRHCJB",0 DT "BBRHPJB",0 DT "BBRHCJW",0 DT "BBRHPJW",0 DT "BBRHCJR",0 DT "BBRHPJR",0 DT 0,0,0,0,0,0,0,0 DT 0,0,0,0,0,0,0,0 ;==================================================================================== ; ; End of program ; end