We can take the previous tutorial a slight step forward and use interrupts. This method of using the USART has a huge advantage, we no longer have to keep calling rxbyte() to check for incoming data. Instead, when data is received, the processor gets interrupted, and the 'Interrupt Service Routine' or macro subroutine is run. This means we can do something entirely different in our main code, and not have to worry if the USART is being checked or not.
Code:
// Include library files
#include <avr/io.h>
#define F_CPU 8000000UL //Define crystal/RC osc frequency
#include <avr/interrupt.h>
// Prototypes
void init_usart(unsigned int baud);
void txbyte(unsigned char data);
unsigned char rxbyte(void);
// Let's go
int main(void)
{
init_usart(51); //Init the USART (Serial) for 8Mhz clock at 9600 Baud
sei(); //Enable interrupts
while(1) //Loop forever
{
//Do some entirely different thing
}
}
void init_usart(unsigned int baud)
{
// Setup serial I/O for communication
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
UCSRC = (1 << URSEL) | (3 << UCSZ0);
}
SIGNAL (SIG_UART_RECV)
{
//The UDR register contains the data received.
//We can still use rxbyte, but only inside the macro to receive another byte of data
if (UDR > rxbyte()) //If the first byte is greater than the second byte received
{
txbyte(1); //Send a 1 back
}
else
{
txbyte(0); //Send a 0 back
}
}
void txbyte(unsigned char data)
{
while ( !( UCSRA & (1 << UDRE)) ); //Wait for empty slot to send data
UDR = data; //Send it
}
unsigned char rxbyte (void)
{
while ( !(UCSRA & (1 << RXC)) ); //Wait until there is a byte to be read from RX buffer
return UDR; //Get it
}
|