Developer Home Contents Search Contact Us Support Intel(r)



Interrupt Driven 'C' Routine for using the Serial Port on the 196KC/KD


Asynchronous serial communications is a common peripheral used on microcontrollers. The 80C196 can generate a seperate interrupt for a reception or a transmission. The iC-96 compiler is shipped with a library which polls the serial port to transmitt and receive. This polling can waste a lot of CPU bandwith at slow baud rates. The following is a sample interrupt driven putchar and getchar that can be used in place of the library putchar and getchar.

The size of the receive and transmitt buffers can be set with the symbol definitions at the beginning of the program. The desired baud rate and frequency of operation can also be set.

#pragma model(KD)
#include "80C196.h"
#pragma interrupt(receive=25,transmit=24)
#define TRANSMIT_BUF_SIZE 20
#define RECEIVE_BUF_SIZE 20
#define FREQUENCY 20000000L /* 20 MHz */
#define BAUD_RATE_VALUE 9600
#define BAUD_REG ((unsigned int)(FREQUENCY/((long)BAUD_RATE_VALUE*16)-1)+0x8000)
#define RI_BIT 0x40
#define TI_BIT 0x20
#ifdef EVAL_BOARD
/* Reserve the 9 bytes required by eval board */
char reserve[9];
#pragma locate(reserve=0x30)
#else
/* Initialize the chip configuration bytes */
const unsigned int ccr = {0x20FF};
#pragma locate(ccr=0x2018)
#endif
unsigned char status_temp; /* image of sp_stat to preserve the RI and TI bits on a read. */
/* receive and transmit buffers and their indexes */
unsigned char trans_buff[TRANSMIT_BUF_SIZE];
unsigned char receive_buff[RECEIVE_BUF_SIZE];
char begin_trans_buff,end_trans_buff;
char end_rec_buff,begin_rec_buff;
/* declares and locates the special function registers */
void transmit(void) /* serial interrupt routine */
{
wsr = 0;
status_temp |= sp_stat; /* image sp_stat into status_temp */
/* transmitt a character if there is a character in the buffer */
if(begin_trans_buff!=end_trans_buff)
 {
 sbuf=trans_buff[begin_trans_buff]; /* transmit character */
/* The next statement makes the buffer circular by starting over when the index reaches the end of the buffer. */
 if(++begin_trans_buff>TRANSMIT_BUF_SIZE - 1)begin_trans_buff=0;
 status_temp &= (~TI_BIT); /* clear TI bit in status_temp. */
 }
}
void receive(void) /* serial interrupt routine */
{
wsr = 0;
status_temp |= sp_stat; /* image sp_stat into status_temp */
/* If the input buffer is full, the last character will be ignored, and the BEL character is output to the terminal. */
 if(end_rec_buff+1==begin_rec_buff || (end_rec_buff==RECEIVE_BUF_SIZE-1 &&
 !begin_rec_buff))
 {
 ; /* input overrun code */
 }
else
 {
/* The next statement makes the buffer circular by starting over when the
 index reaches the end of the buffer. */
 if(++end_rec_buff > RECEIVE_BUF_SIZE - 1) end_rec_buff=0;
 receive_buff[end_rec_buff]=sbuf; /* place character in buffer */
 }
 status_temp &= (~RI_BIT); /* clear RI bit in status_temp. */
}
int putchar(int c)
{
/* remain in loop while the buffer is full. This is done by checking the end of buffer index to make sure it does not overrun the beginning of buffer index. The while instruction checks the case when the end index is one less then the beginning index and at the end of the buffer when the beginning index may be equal to 0 and the end buffer index may be at the buffer end. */
while((end_trans_buff+1==begin_trans_buff)||
 (end_trans_buff==TRANSMIT_BUF_SIZE -1 && !begin_trans_buff));
trans_buff[end_trans_buff]=c; /* put character in buffer */
if(++end_trans_buff>TRANSMIT_BUF_SIZE - 1) /* make buffer appear */
 end_trans_buff=0; /* circular. */
if(status_temp & TI_BIT) ipend1 |= 0x01; /* If transmitt buffer was empty, then cause
 an interrupt to start transmitting. */
}
unsigned char getchar()
{
while(begin_rec_buff==end_rec_buff); /* remain in loop while there is not a character avaliable. */
if(++begin_rec_buff>RECEIVE_BUF_SIZE - 1) /* make buffer appear */
 begin_rec_buff=0; /* circular. */
return(receive_buff[begin_rec_buff]); /* return the character in buffer. */
}
void init_serial_port()
{
 unsigned char wsr_image = wsr;
 wsr=0;
 baud_rate = ((unsigned char) BAUD_REG);
 baud_rate = ((unsigned char) (BAUD_REG >> 8));
 sp_con = 0x09; /* mode 1, no parity, receive enabled, no 9th bit */
 status_temp = sp_stat | TI_BIT;
 end_rec_buff=0; /* initialize buffer pointers */
 begin_rec_buff=0;
 end_trans_buff=0;
 begin_trans_buff=0;
 
 imask1=0x03; /* enable the serial port interrupts */
 enable(); /* global enable of interrupts */
 wsr = wsr_image;
}
main()
{
 char c;
 init_serial_port();
 while((c=getchar()) != 0x1b) /* stay in loop till escape key pressed */
 printf("key pressed = %02X\n\r",c);
}



* Legal Information © 1999 Intel Corporation