//* INTERRUPT HANDLER ROUTINE
void interrupt EUSART_TIMER1(void) {
char usart_data,tmphead,tmptail;
The temporary transmit and receive buffer pointer
bytes in the interrupt handler char declaration. The
usart_data byte is used to hold the incoming bytes that
are removed from the EUSART's hardware buffer. The
TIMER1 portion of the PIC18LF2620 interrupt handler is
represented by code that "ticks" every millisecond:
if((TMR1IF && TMR1IE)) {
TMR1IF = 0;
TMR1H = 0xF8;
TMR1L = 0x31;
++tmsecs1;
if(++imsecs1 == 1000) {
imsecs1 = 0;
++isecs1;
++tsecs1;
LED1 ^= 1;
}
}
Every time that TIMER1 overflows, it is reloaded with
an integer that causes the timer to overflow again in one
millisecond. The milliseconds are collected into seconds
and are used to provide timing for the millisecond and
second timer functions. As you can see in the TIMER1
interrupt handler code, LED1 is toggled every 1,000 ms
or every second.
Every time the EUSART signals that a character is
captured in its hardware receive buffer, the interrupt
handler code fetches the received byte from the EUSART's
hardware buffer and stores it in the next available byte slot
of the receive buffer. The idea behind the circular buffer
scheme is to never let the head pointer value of the buffer
catch up to the tail pointer value of the buffer. I've never
had to execute the error statements in this receive
interrupt handler code:
if(RCIF) {
usart_data = RCREG; //read received data
// calculate new buffer index
tmphead = ( EUSART_RxHead + 1 ) &
EUSART_RX_BUFFER_MASK;
EUSART_RxHead = tmphead;// store new index
if ( tmphead == EUSART_RxTail ) {
//ERROR! Receive buffer overflow
status.buf_ovrf = 1;
}
// store received usart_data in buffer
EUSART_RxBuf[tmphead] = usart_data;
}
THE DESIGN CYCLE
The transmit interrupt handler code is only used by
the sendchar() function. When the sendchar() function is
called, the outgoing byte is placed in the PIC18LF2620's
transmit buffer and the transmit interrupt enable bit is
activated. The interrupt handler code keys on the transmit
interrupt bit, retrieves the byte from the transmit buffer,
and stuffs it into the EUSART's hardware transmit
buffer. The EUSART — seeing a byte in its TXREG register
— sends that byte along its way. Like the EUSART receive
interrupt handler code, the transmit interrupt handler
code declares the associated buffer empty when the
buffer head pointer is equal to the tail buffer pointer. If
more than one character is waiting in the PIC’s transmit
buffer, the transmit interrupt handler code will attempt
to transmit until the transmit buffer is found to be
empty. Here's what the transmit interrupt handler
code looks like:
if(TRMT) {
//check if all usart_data is transmitted
if ( EUSART_TxHead != EUSART_TxTail ) {
//calculate new buffer index
tmptail = ( EUSART_TxTail + 1 ) &
EUSART_TX_BUFFER_MASK;
EUSART_TxTail = tmptail; //save new idx
TXREG = EUSART_TxBuf[tmptail]; //send it
}
else {
TXIE = 0; // disable TX interrupt
}
}
The CharInQueue(), recvchar(), and sendchar()
functions interact with the interrupt handler routines
we've just discussed. We examined the inner workings
of the CharInQueue(), recvchar(), and sendchar() functions
in the previous installment of Design Cycle.
After powering up the PIC18LF2620's EUSART, we
turn our attention to TIMER1:
//*CONFIGURE AND START TIMER1,
//* SET TO OVERFLOW EVERY 1mS
//F831 = 8MHz
//E0C1 = 32MHz
TIMER1OFF;
T1CON = 0b00000000;
TMR1H = 0xF8;
TMR1L = 0x31;
TIMER1ON;
Basically, we let TIMER1 do its thing with the
processor clock unhindered by prescalers. Just in case
you want to put the pedal to the silicon, I've included the
TIMER1 32 MHz clock value in a comment of the TIMER1
initialization code.
At this point, we can open the gate and let the
horses run:
January 2009 75