; ; Interrupt based USART1 routines ; ; John E. Andrews ; Feb 24th, 1998 ; ;********************************************************************** InitU1 ; initialize USART1 ;********************************************************************** ; ; This sets up the peripheral USART1 to provide buffered, line based, ; interrupt driven, transmit and receive. The functions UART1Rx and ; UART1Tx are called from the peripheral interrupt vector. ; These functions are terminated by a return to the peripheral isr ; which restores context and performs the retfie. ; This function, InitU1, and the routine to start interrupt based ; buffer transission, StartTx are called by inline code. ; ; ***** Variable and symbol declarations for UART1 ***** ; cblock ; declare bank 0 variables u1Flags ; UART1 semaphore flags endc ; ; bit flag definitions for u1Flags RxRdy equ 0 ; new data from UART1 for inline code RstRxPtr equ 1 ; isr should reset its buffer pointer TxRdy equ 2 ; new data for UART1 from inline code ; ; select gpr bank containing Rx buffer, pointers and flags movlr 0 ; select gpr bank 0 movlw rxBuffer-1 ; load prestart of Rx buffer movwf rxPtr ; into Rx buffer pointer clrf u1Flags ; clear all semaphors bsf u1Flags, RstRxPtr ; tell isr to reset Rx pointer bcf u1Flags, RxRdy ; clear data ready flag ; ; init peripheral movlb 0 ; select SFR bank for USART1 movlw 0x20 ; select TxEN, 8 bit, asynch movwf TXSTA1 ; for USART1 Tx movlw 0x90 ; select SPEN, RxEN, continuous Rx movwf RCSTA1 ; for USART1 Rx movlw (Dev_Freq/(64*9600))-1 ; select 9600 movwf SPBRG1 ; for USART1 baud rate ; ; init interupts for USART1 movlb 1 ; select sfr bank 1 bsf PIE1, RC1IE ; enable Rx int return ; ;********************************************************************** UART1Rx ; UART1 receiver interrupt service routine ;********************************************************************** ; ; Receive characters into buffer until CR is received. Then set ; RxRdy bit in u1Flags register to inform inline code that a line ; is ready. Once the inline code has finished with the buffer it sets ; RstRxPtr to cause the isr buffer pointer, intRxPtr, to be set equal ; to the inline code buffer pointer, rxPtr, it then clears RxRdy ; allowing the isr to reset and begin accumulating a new buffer. ; ; This function ; must be terminated by a return to the peripheral isr which restores ; context and performs the retfie. ; ; The following macro causes this function to be called by the ; peripheral interrupt routine when the RC1IF flag is set. This macro ; must be placed immediately following the label at the beginning of ; the isr function and prior to any executable code. ; ; include bit testing at the peripheral int vector at assembly time InstallISR 1, PIR1, RC1IF ; install isr for uart1 rx ; ; ***** Variable and symbol declarations for UART1 Rx isr ***** ; rxBufferSize equ 40 ; size of buffer for UART1 Rx data ; cblock ; declare bank 0 variables ; UART1 Rx buffer, allow extra char for 0 fil by command parser rxBuffer: rxBufferSize+1 rxPtr ; pointer into Rx buffer used by inline code intRxPtr ; pointer into Rx buffer used by isr endc ; ; ***** Executable code for USRT1 Rx isr ***** ; ; select gpr bank containing Rx buffer, pointers and flags movlr 0 ; select gpr bank 0 ; select sfr bank containing UART1 registers movlb 0 ; select sfr bank 0 ; ; if buffer has data ready then read Rx data into bit bucket btfss u1Flags, RxRdy ; skip if buffer has whole line ready goto RstRx ; otherwise test for buffer reset movfp RCREG1, WREG ; read Rx data into bit bucket return ; return to restore context and exit isr ; RstRx ; reset isr uart Rx buffer pointer to equal inline code pointer btfss u1Flags, RstRxPtr ; skip if reset requested goto ReadRx ; otherwise continue to buffer Rx data movfp rxPtr, WREG ; fetch inline buffer ptr movwf intRxPtr ; reset isr Rx pointer bcf u1Flags, RstRxPtr ; clear pointer rst flag ; ReadRx ; point to next buffer entry and copy in Rx character incf intRxPtr ; inc isr Rx pointer movfp intRxPtr, FSR0 ; load FSR0 movfp RCREG1, INDF0 ; read Rx data into buffer ; ; process special characters ; ; if a LF was received echo it then throw it away movlw 0x0A ; test for LF cpfseq INDF0 ; if equal then skip goto RxNotLF ; otherwise jump to not LF movpf INDF0, TXREG1 ; echo it back to the term decf intRxPtr ; backup isr pointer deleting LF return ; return to restore context and exit isr RxNotLF ; if here then character was not LF ; ; if a backspace was received then backup movlw 0x08 ; test for backspace cpfseq INDF0 ; if equal skip goto RxNotBS ; otherwise jump to not BS decf intRxPtr ; backup over backspace char ; this prevents backing up past the beginning of the buffer movlw rxBuffer-1 ; load prestart of Rx buffer cpfsgt intRxPtr ; skip if current pointer greater return ; return to restore context and exit isr decf intRxPtr ; otherwise backup over prior char movpf INDF0, TXREG1 ; and echo it back to the term return ; return to restore context and exit isr RxNotBS ; if here then character was not backspace ; ; if a CR was received then pass buffer to inline code movlw 0x0D ; test for CR cpfseq INDF0 ; if equal then skip goto RxNotCR ; otherwise jump to not CR movpf INDF0, TXREG1 ; echo it back to the term bsf u1Flags, RxRdy ; set flag indicating data ready return ; return to restore context and exit isr RxNotCR ; if here then character was not CR ; ; character was not LF or backspace or CR, test for last buffer addr movlw rxBuffer+rxBufferSize-1 ; load last buffer addr cpfseq intRxPtr ; skip if interrupt pointer is equal movpf INDF0, TXREG1 ; otherwise echo it back to the term cpfslt intRxPtr ; skip if interrupt pointer is less than ; otherwise data was placed in last buffer location and is not a CR decf intRxPtr ; so backup isr pointer return ; return to restore context and exit isr ; ;********************************************************************** StartTx ; Kick start UART1 transmitter interrupt service routine ;********************************************************************** ; ; Initialize flags and pointers for interrupt based UART1 transmit ; and load first byte of buffer into TXREG1 to start transmit. ; This function is called by inline code to setup and start UART1 Tx. ; Exit is accomplished by a return. ; ; ***** Variables for UART1 Tx ***** ; cblock ; declare bank 0 variables txPtr ; pointer into Tx buffer used by inline code intTxPtr ; pointer into Tx buffer used by isr endc ; ; ***** Executable code for UART1 Tx kick start ***** ; movwf txPtr ; load output buffer addr into txPtr ; select sfr bank containing UART1 registers movlb 0 ; select sfr bank 0 ; wait for any ongoing buffered Tx activity to complete btfsc u1Flags, TxRdy ; skip when Tx buffer empty goto $-1 ; until then wait ; reset isr uart Tx buffer pointer to equal inline code pointer movfp txPtr, WREG ; fetch inline buffer ptr movwf intTxPtr ; reset isr Tx pointer movwf FSR0 ; load FSR0 tstfsz INDF0 ; test for null char goto $+2 ; if not null keep going return ; otherwise return w/o starting Tx bsf u1Flags, TxRdy ; set flag indicating buffer is ready movpf INDF0, TXREG1 ; put first byte into Tx reg movlb 1 ; select sfr bank 1 for PIE register bsf PIE1, TX1IE ; enable Tx int return ; Tx started, return ; ;********************************************************************** UART1Tx ; UART1 transmitter interrupt service routine ;********************************************************************** ; ; Transmit characters from buffer until 0 or \ is detected. If 0 is ; detected then the end of the buffer has been reached, the TxRdy ; flag is cleared informing inline code that the buffer is available. ; If the \ character is detected then an escape sequence is indicated ; and the next char is interpreted and the control char sent. If the ; next char is not a known escape character then the \ and the char ; are output as text. ; ; This function ; must be terminated by a return to the peripheral isr which restores ; context and performs the retfie. ; ; The following macro causes this function to be called by the ; peripheral interrupt routine when the TX1IF flag is set. This macro ; must be placed immediately following the label at the beginning of ; the isr function and prior to any executable code. ; ; include bit testing at the peripheral int vector at assembly time InstallISR 1, PIR1, TX1IF ; install isr for uart1 tx ; ; ***** Executable code for UART1 Tx isr ***** ; ; select gpr bank containing Rx buffer, pointers and flags movlr 0 ; select gpr bank 0 ; select sfr bank containing UART1 registers movlb 0 ; select sfr bank 0 ; ; if buffer has no data ready then exit btfss u1Flags, TxRdy ; skip if buffer holds data return ; return to restore context and exit isr ; TestTx ; point to next buffer entry incf intTxPtr ; inc isr Tx pointer movfp intTxPtr, FSR0 ; load FSR0 ; ; process special characters ; ; test for 0 indicating end of tx buffer data tstfsz INDF0 ; is next char 0? goto TxNot0 ; if not keep checking bcf u1Flags, TxRdy ; otherwise clear Tx data ready flag movlb 1 ; select sfr bank 1 for PIE register bcf PIE1, TX1IE ; disable Tx int return ; return to restore context and exit isr TxNot0 ; if here then buffer character is not 0 ; ; test for escape sequence character movlw '\\' ; load escape sequence character cpfseq INDF0 ; is next char \? goto WriteTx ; if not write it incf intTxPtr ; otherwise inc isr Tx pointer movfp intTxPtr, FSR0 ; load FSR0 ; determine which special character is requested cpfseq INDF0 ; is next char also \? goto $+3 ; if not keep checking movwf TXREG1 ; otherwise output it return ; return to restore context and exit isr movlw 'a' ; load bell escape character cpfseq INDF0 ; is next char a? goto $+4 ; if not keep checking movlw 0x07 ; otherwise load bell character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 'b' ; load backspace escape character cpfseq INDF0 ; is next char b? goto $+4 ; if not keep checking movlw 0x08 ; otherwise load backspace character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 'f' ; load form feed escape character cpfseq INDF0 ; is next char f? goto $+4 ; if not keep checking movlw 0x0C ; otherwise load form feed character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 'n' ; load new line escape character cpfseq INDF0 ; is next char n? goto $+4 ; if not keep checking movlw 0x0A ; otherwise load new line character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 'r' ; load carriage return escape character cpfseq INDF0 ; is next char r? goto $+4 ; if not keep checking movlw 0x0D ; otherwise load carriage return character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 't' ; load tab escape character cpfseq INDF0 ; is next char t? goto $+4 ; if not keep checking movlw 0x09 ; otherwise load tab character movwf TXREG1 ; and output it return ; return to restore context and exit isr movlw 'v' ; load vertical tab escape character cpfseq INDF0 ; is next char v? goto $+4 ; if not keep checking movlw 0x0B ; otherwise load vertical tab character movwf TXREG1 ; and output it return ; return to restore context and exit isr ; otherwise output \ char and exit movlw '\\' ; load \ movwf TXREG1 ; and output it decf intTxPtr ; dec isr Tx pointer to prep for next int ; on next Tx int non-escape char after \ will be output return ; return to restore context and exit isr ; WriteTx ; not end of buffer or escape so output next char from buffer movpf INDF0, TXREG1 ; write Tx data into buffer return ; return to restore context and exit isr ;
Interested:
Questions:
I am using a PIC16F628 and due to constrants I have to use this chip due to cost. My problem is I need two TX and two RX on this chip. It only comes with one USART and I need another. Would this program allow to be interupt driven so the processor can distinguish between the different tx and rx registers. This is my first experience with PIC programming any help would be great.