;****************************************************************************** ; ; Filename: Relays.asm ; Date: 29.09.08 ; File Version: 1.0.0 ; ; Author: JP ROUBELAT ; ;****************************************************************************** ; NOTES: ; ; ;****************************************************************************** ; CHANGE LOG: ; ; ;****************************************************************************** list p=16f88 ; list directive to define processor #include ; processor specific variable definitions ; __CONFIG _CP_OFF & _WDT_ON & _BODEN_OFF & _PWRTE_ON & _INTOSC_OSC_CLKOUT & _MCLRE_OFF & _LVP_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ;Program Configuration Register 1 ; __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC ; __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_IO __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_OFF & _WDT_ON & _INTRC_IO ;Program Configuration Register 2 ; __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF #define MY_ADDR .3 ; Address of Relays card #define STX .2 #define DT_LEN .15 #define RX_LEN DT_LEN+.4 ; Serial RX buffer length #define TX_LEN 0x20 ; Serial TX buffer length #define TX_BIT .5 ; Bit for 32 positions #define B_4800 .51 ; Baud rate generator ;****************************************************************************** ; VARIABLE DEFINITIONS * ;****************************************************************************** cblock 0x20 ; 0x20-0x3f (32 bytes) banks 0 ; rx linear buffer (23 bytes) rx_ft ; from/to addresses rx_sl ; seq/len rx_cmd ; command rx_data:DT_LEN ; data rx_chck ; checksum rx_count ; nb of characters in buffer rx_temp ; temporary storage rx_length ; length of frame excluding STX rx_flags ; rx_flags ; eeprom variables (3 bytes) fl_relays ; Values of relays ; AC counters (2 bytes) ac_cnt1 ; Counter for AC1 ac_cnt2 ; Counter for AC2 ; Inputs status (2 bytes) dc_in ; DC Input status ac_in ; AC Input status endc rx_buffer equ rx_ft ; beginning of rx_buffer cblock 0x40 ; 0x40-0x6f (48 bytes) banks 0 ; tx circular buffer (39 bytes) ; MUST BE at address 0x40 and len 0x20 tx_buffer:TX_LEN; buffer tx_count ; nb of characters in buffer tx_bufin ; pointer for data IN tx_bufout ; pointer for data OUT tx_seq ; Sequence number tx_temp ; temporary storage tx_flags ; tx_flags tx_chck ; tx checksum computation endc cblock 0x70 ; 0x70-0x7F (16 bytes) common to all banks ide_temp ; Reserved for ICD w_temp ; variable used for context saving status_temp ; variable used for context saving index_temp ; variable used for context saving txtidx ; write text index pointer counter_h ; timer high 8 bits counter_l ; timer low 8 bits tmpval ; Temporary value fl_addr ; Address of Flash fl_temp ; Temporary value endc ;****************************************************************************** ; Flags ;****************************************************************************** RXFRM equ 0x00 ; Receive frame on-going RXMSG equ 0x01 ; Character received #define RX_FRM rx_flags,RXFRM #define RX_MSG rx_flags,RXMSG #define REL_ADDR .27 ;****************************************************************************** ; Port A ;****************************************************************************** #define REL_3 0 #define LED_R 1 #define LED_Y 2 #define DCIN_1 3 #define DCIN_2 4 #define REL_1 6 #define REL_2 7 #define LEDR PORTA,LED_R #define LEDY PORTA,LED_Y #define REL1 PORTA,REL_1 #define REL2 PORTA,REL_2 #define REL3 PORTA,REL_3 #define DCIN1 PORTA,DCIN_1 #define DCIN2 PORTA,DCIN_2 ;****************************************************************************** ; Port B ;****************************************************************************** #define ACIN_1 0 #define ACIN_2 3 #define ACIN1 PORTB,ACIN_1 #define ACIN2 PORTB,ACIN_2 ;****************************************************************************** ; Macros ;****************************************************************************** BANK0 MACRO bcf STATUS,RP0 bcf STATUS,RP1 bcf STATUS,IRP ENDM BANK1 MACRO bsf STATUS,RP0 bcf STATUS,RP1 bcf STATUS,IRP ENDM BANK2 MACRO bcf STATUS,RP0 bsf STATUS,RP1 bsf STATUS,IRP ENDM BANK3 MACRO bsf STATUS,RP0 bsf STATUS,RP1 bsf STATUS,IRP ENDM ;****************************************************************************** ; RESET VECTOR * ;****************************************************************************** ORG 0x000 ; processor reset vector nop ; Reserved for ICD clrf STATUS clrf PCLATH goto _startup ; go to beginning of program ;****************************************************************************** ; INTERRUPT ROUTINE ;****************************************************************************** ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register BANK0 btfsc INTCON,TMR0IF call _int_tmr0 btfsc PIR1,RCIF call _int_rx btfsc PIR1,TXIF call _int_tx movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ;==================================================================================== ; TIMER0 INTERRUPT _int_tmr0 bcf INTCON,TMR0IF ; Clear Timer0 interrupt request btfsc ACIN1 ; ac1 input goto _int_cnt1dec _int_cnt1inc ; 3x increment counter incf ac_cnt1,f ; increment counter btfsc STATUS,Z goto _int_cnt1max incf ac_cnt1,f ; increment counter btfsc STATUS,Z goto _int_cnt1max incf ac_cnt1,f ; increment counter btfss STATUS,Z goto _int_cnt2 ; next counter _int_cnt1max decf ac_cnt1,f ; set to 0xff goto _int_cnt2 _int_cnt1dec ; 1x decrement counter movfw ac_cnt1 btfss STATUS,Z decf ac_cnt1,f ; decrement counter if not 0 _int_cnt2 btfsc ACIN2 ; ac2 input goto _int_cnt2dec _int_cnt2inc ; 3x increment counter incf ac_cnt2,f ; increment counter btfsc STATUS,Z goto _int_cnt2max incf ac_cnt2,f ; increment counter btfsc STATUS,Z goto _int_cnt2max incf ac_cnt2,f ; increment counter btfss STATUS,Z goto _int_cnte ; next counter _int_cnt2max decf ac_cnt2,f ; set to 0xff goto _int_cnte _int_cnt2dec ; 1x decrement counter movfw ac_cnt2 btfss STATUS,Z decf ac_cnt2,f ; decrement counter if not 0 _int_cnte return ;==================================================================================== ; RX INTERRUPT _int_rx ; RX interrupt received btfss RCSTA,OERR goto _int_rx1 ; No overrun bcf RCSTA,CREN ; Overrun bsf RCSTA,CREN ; Restart receive _int_rx1 btfsc RCSTA,FERR goto _int_rxd ; Frame error btfsc RX_FRM goto _int_rx2 ; Wait for start of frame movfw RCREG sublw STX btfss STATUS,Z goto _int_rxe ; Not a STX... bsf RX_FRM ; Start of frame bcf LEDY clrf rx_count ; Character count = 0 movlw RX_LEN movwf rx_length ; length of frame goto _int_rxe _int_rx2 ; Put received character in buffer movfw FSR ; Save FSR movwf index_temp movfw rx_count ; Index in frame addlw rx_buffer movwf FSR movfw RCREG movwf INDF movwf rx_chck incf rx_count,f movfw rx_count ; Nb of received characters xorlw .2 ; Len received btfss STATUS,Z goto _int_rx3 ; Data length received movfw rx_sl andlw 0xf ; extract data length movwf rx_length movlw .4 addwf rx_length,f ; add header and checksum _int_rx3 movfw rx_length ; Test end of message xorwf rx_count,w btfss STATUS,Z goto _int_rxe bsf RX_MSG ; Message received bcf RX_FRM ; Wait for next frame bsf LEDY goto _int_rxe _int_rxd movfw RCREG ; Discard character _int_rxe return ;==================================================================================== ; TX INTERRUPT _int_tx ; TX interrupt received movfw tx_count btfsc STATUS,Z goto _int_txm ; buffer empty movfw tx_bufout movwf FSR ; buffer out pointer movfw INDF movwf TXREG ; move character to TX register decf tx_count,f ; Decrement character count incf tx_bufout,f ; Increment pointer bcf tx_bufout,TX_BIT; Circular buffer goto _int_txe _int_txm BANK1 bcf PIE1,TXIE ; stop TX interrupts BANK0 bsf LEDR ; stop LED R _int_txe return ;****************************************************************************** ; MAINLINE CODE ;****************************************************************************** _startup call _init call _blinkLeds bsf INTCON,GIE ; Allow global interrupts ; movlw 'F' ; call _serialTX ; movlw '6' ; call _serialTX ; movlw 'F' ; call _serialTX ; movlw 'B' ; call _serialTX ; movlw 'B' ; call _serialTX ;==================================================================================== ; Main loop ; _main_loop clrwdt ; Clear watchdog call _checkMsg ; Check for message call _checkDc ; Check DC inputs call _checkAc ; Check AC inputs goto _main_loop ; endless main loop ;****************************************************************************** ; SUB-ROUTINES ;****************************************************************************** ;==================================================================================== ; Check for DC inputs ; _checkDc clrf tmpval btfsc DCIN1 bsf tmpval,0 btfsc DCIN2 bsf tmpval,1 movfw dc_in xorwf tmpval,w btfsc STATUS,Z return movfw tmpval movwf dc_in goto _sendChg ; DC input have changed -> update ;==================================================================================== ; Check for AC Inputs ; _checkAc clrf tmpval btfsc ac_cnt1,7 bsf tmpval,0 btfsc ac_cnt2,7 bsf tmpval,1 movfw ac_in xorwf tmpval,w btfsc STATUS,Z return movfw tmpval movwf ac_in goto _sendChg ; AC input have changed -> update ;==================================================================================== ; Send a changed message ; _sendChg movlw STX ; STX call _serialTX clrf tx_chck ; clear checksum movlw MY_ADDR ; fmt movwf tmpval swapf tmpval,w addwf tx_chck,F call _serialTX swapf tx_seq,w ; snl addlw .3 ; add length addwf tx_chck,f call _serialTX call _incSeq ; Increment sequence number movlw .3 ; cmd addwf tx_chck,f call _serialTX clrf tmpval ; rel btfsc REL1 bsf tmpval,0 btfsc REL2 bsf tmpval,1 btfsc REL3 bsf tmpval,2 movfw tmpval addwf tx_chck,f call _serialTX movfw ac_in ; ac addwf tx_chck,f call _serialTX movfw dc_in ; dc addwf tx_chck,f call _serialTX negf tx_chck,w ; chck goto _serialTX ;==================================================================================== ; Check for message ; _checkMsg btfss RX_MSG return ; No message received ; Full message received bcf RX_MSG ; Clear flag ; Verify checksum movfw rx_chck movwf rx_temp ; add checksum to sum movfw rx_count movwf tmpval decf tmpval,f ; exclude checksum movlw rx_buffer movwf FSR _checkMsg_1 movfw INDF ; message excluding checksum addwf rx_temp,f ; add to sum incf FSR,f decfsz tmpval,f goto _checkMsg_1 ; rx_temp = 0 if checksum OK movfw rx_temp btfss STATUS,Z goto _checkMsg_e ; Checksum error, msg ignored movfw rx_ft andlw 0xf xorlw MY_ADDR btfss STATUS,Z goto _fwdMsg ; Message is for me. Process... movfw rx_cmd xorlw .1 btfsc STATUS,Z goto _ping movfw rx_cmd xorlw .2 btfsc STATUS,Z goto _ident goto _myMessages _checkMsg_e return ;****************************************************************** ; ; Answer to a ping request ; swap adresses, set seq number, copy the data and update checksum ; _ping clrf rx_chck swapf rx_ft,W ; swap addresses to answer movwf rx_ft addwf rx_chck,F ; sequence number movlw 0x0f andwf rx_sl,F ; clean seq number swapf tx_seq,W iorwf rx_sl,W ; add to length movwf rx_sl addwf rx_chck,F call _incSeq ; Increment sequence number movfw rx_cmd addwf rx_chck,F movfw rx_data addwf rx_chck,F negf rx_chck,F goto _fwdMsg ; Send frame ;****************************************************************** ; ; Answer to a ident request ; swap adresses, set seq number, copy the data and update checksum ; _ident clrf rx_chck swapf rx_ft,W ; swap addresses to answer movwf rx_ft addwf rx_chck,F ; Length movlw 0x06 movwf rx_sl ; sequence number swapf tx_seq,W iorwf rx_sl,W ; add to length addwf rx_chck,F movwf rx_sl call _incSeq movlw 0x02 addwf rx_chck,F movwf rx_cmd movlw 'R' addwf rx_chck,F movwf rx_data movlw 'E' addwf rx_chck,F movwf rx_data+.1 movlw 'L' addwf rx_chck,F movwf rx_data+.2 movlw ' ' addwf rx_chck,F movwf rx_data+.3 movlw 'V' addwf rx_chck,F movwf rx_data+.4 movlw '1' addwf rx_chck,F movwf rx_data+.5 negf rx_chck,F ; Ajust Checksum movlw .10 ; Set message length movwf rx_length movwf rx_count goto _fwdMsg ; Send frame ;==================================================================================== ; Initialisation code ; _init bcf STATUS,IRP ; clear indirect addressing IRP bit ; since we will only use banks 0 and 1 clrf PORTA ; clear PortA data latches clrf PORTB ; clear PortB data latches BANK1 ; Select register bank 1 movlw b'01101000' ; osc internal 4 Mhz movwf OSCCON BANK2 movlw b'00010110' ; Watchdog 2 seconds movwf WDTCON BANK1 movlw 0x04 ; Load mask for watchdog with no-prescaler movwf OPTION_REG ; Init option register - timer0 prescaler 32 movlw 0x07 movwf CMCON ; disable comparator movlw 0x00 ; Configure all pins movwf ANSEL ; as digital inputs movlw b'00111000' ; RA0,1,2,6,7 = out movwf TRISA ; Set PortA I/O for intput/output movlw b'11011111' ; RB2(RX),RB5(TX) used by USART movwf TRISB ; set PortB I/O bcf TXSTA,SYNC ; USART Async mode bsf TXSTA,BRGH ; USART BRGH low speed movlw B_4800 ; Value for timer = 4800 Bds movwf SPBRG ; set BRG for 4800bps bsf PIE1,RCIE ; RX interrupts bsf TXSTA,TXEN ; enable transmit BANK0 ; Select register bank 0 bsf INTCON,PEIE ; Allow perif interrupts bsf INTCON,TMR0IE ; Allow Timer0 interrupts bsf RCSTA,SPEN ; enable receive bsf RCSTA,CREN ; enable continous receive bsf LEDR ; LEDR eteinte bsf LEDY ; LEDY eteinte ; Init buffers variables clrf rx_flags clrf rx_count ; Index at beginning of rx_buffer clrf tx_count ; Count of characters in tx_buffer clrf tx_seq ; Sequence number movlw tx_buffer movwf tx_bufin ; Index at beginning of tx_buffer movwf tx_bufout ; Index at beginning of tx_buffer ; force update status for inputs movlw 0xff movwf ac_in movwf dc_in ; Write last relays values movlw REL_ADDR movwf fl_addr call _readFlash movwf fl_relays call _setRelays return ;==================================================================================== ; Blink red LED ; _blinkLeds movlw d'10' movwf tmpval _start_signal clrwdt ; watchdog movlw d'200' ; Wait 100ms call _tempo bcf LEDR ; LED allumée movlw d'200' ; Wait 100ms call _tempo bsf LEDR ; LED eteinte decfsz tmpval,f ; 10 blinks goto _start_signal return ;==================================================================================== ; ForwardMsg ; Forward message in rx_buffer to tx_buffer without change ; _fwdMsg movlw STX call _serialTX clrf rx_temp ; offset in buffer decf rx_count,f ; exclude checksum _fwdMsg_1 movlw rx_buffer addwf rx_temp,w movwf FSR movfw INDF call _serialTX incf rx_temp,f decfsz rx_count,f goto _fwdMsg_1 movfw rx_chck ; send checksum goto _serialTX ;==================================================================================== ; Tempo ; w contents the number of ms to wait ; _tempo movwf counter_h _tempo_1 movlw 0xFA ; wait 1ms movwf counter_l _tempo_2 nop ; loop = 4us decfsz counter_l,f goto _tempo_2 decfsz counter_h,f goto _tempo_1 return ;==================================================================================== ; ReadFlash ; w returns the value pointed by flash address fl_addr ; _readFlash movfw fl_addr BANK2 movwf EEADR BANK3 bcf EECON1,EEPGD bsf EECON1,RD BANK2 movfw EEDATA BANK0 return ;==================================================================================== ; WriteFlash ; write the content of W to flash address fl_addr ; _writeFlash movwf fl_temp ; Save character BANK3 btfsc EECON1,WR goto $-1 ; Wait for end of previous eeprom write BANK2 movfw fl_addr movwf EEADR movfw fl_temp movwf EEDATA BANK3 bcf EECON1,EEPGD bsf EECON1,WREN ; Enable EEPROM Write bcf INTCON,GIE ; Disable interrupts movlw 0x55 movwf EECON2 movlw 0xaa movwf EECON2 bsf EECON1,WR ; Start write bsf INTCON,GIE ; Allow interrupts bcf EECON1,WREN ; Disable EEPROM write BANK0 return ;==================================================================================== ; INCSEQ - increment the sequence number ; never goes to 0 (from 0x1 to 0xf) ; _incSeq incf tx_seq,f btfsc tx_seq,4 swapf tx_seq,f return ;==================================================================================== ; Send the character held in w ; _serialTX movwf tx_temp ; Save character _serialTX_wait movfw tx_count xorlw TX_LEN btfsc STATUS,Z goto _serialTX_wait ; Buffer full ... Wait movfw tx_bufin movwf FSR ; Buffer address movfw tx_temp movwf INDF ; Put character in buffer incf tx_bufin,f ; Increment pointer bcf tx_bufin,TX_BIT ; Circular buffer incf tx_count,f ; Increment character count BANK1 bsf PIE1,TXIE ; Allow TX interrupts BANK0 bcf LEDR ; start LED R return ; and return ;==================================================================================== ; Specific to the application ; ;==================================================================================== ; Decode and call routines for my messages ; _myMessages movfw rx_cmd xorlw .3 btfsc STATUS,Z goto _relays movfw rx_cmd xorlw .4 btfsc STATUS,Z goto _status ;==================================================================================== ; Do a Relays command and answers by a status ; _relays movlw REL_ADDR ; address of status in eeprom movwf fl_addr movlw 0x7 andwf rx_data,f ; Mask movlw 0x7 andwf rx_data+.1,f ; Values comf rx_data,w ; Complement of mask andlw 0x7 andwf fl_relays,f ; Clear bits in mask movfw rx_data+.1 ; values andwf rx_data,w ; only masked bits iorwf fl_relays,f ; Set relay bits from command movfw fl_relays ; Values call _writeFlash movfw fl_relays call _setRelays goto _status ;==================================================================================== ; Set Relays ; _setRelays movwf tmpval btfss tmpval,0 ; Relay 1 bcf REL1 btfsc tmpval,0 bsf REL1 btfss tmpval,1 ; Relay 2 bcf REL2 btfsc tmpval,1 bsf REL2 btfss tmpval,2 ; Relay 3 bcf REL3 btfsc tmpval,2 bsf REL3 return ;==================================================================================== ; Send Status answer ; _status clrf rx_chck swapf rx_ft,W ; swap addresses to answer movwf rx_ft addwf rx_chck,F ; Length movlw 0x03 movwf rx_sl ; sequence number swapf tx_seq,W iorwf rx_sl,W ; add to length addwf rx_chck,F movwf rx_sl call _incSeq ; Increment sequence number movfw rx_cmd ; Do not change cmd addwf rx_chck,F ; Get relays status clrf tmpval btfsc REL1 bsf tmpval,0 btfsc REL2 bsf tmpval,1 btfsc REL3 bsf tmpval,2 movfw tmpval movwf rx_data addwf rx_chck,F ; Get AC IN status clrf tmpval btfsc ac_cnt1,7 bsf tmpval,0 btfsc ac_cnt2,7 bsf tmpval,1 movfw tmpval movwf rx_data+.1 addwf rx_chck,F ; Get DC IN status clrf tmpval btfsc DCIN1 bsf tmpval,0 btfsc DCIN2 bsf tmpval,1 movfw tmpval movwf rx_data+.2 addwf rx_chck,F negf rx_chck,F ; Ajust Checksum movlw .7 ; Set message length movwf rx_length movwf rx_count goto _fwdMsg ; Send frame ;==================================================================================== END ; directive 'end of program'