|
Simple USART routines arenot always practical because waiting transmitting buffer to be ready in a simple loop occupies processor. Especially if we don't know when data will be received. Another issue when multiple data bytes has to be sent/received. As microcontroller speciality is interrupts so it is better to use them and this way improve overall performance and energy saving. In previous article we discussed simple USART implementation. Where microcontroller constantly has to check if there is data received in UDR register. Also for sending it has to check if send buffer is free. Such coding is ineffective as MCU have always to run at 100% performance checking the buffer. In such mode batteries are going down really fast. Why not to set up guardian which would wake the MCU if it have received a byte via USART. In other hand Interrupt mode allows to perform other tasks at full capacity while waiting for USART interrupt. Lets modify our program to Interrupt driven USART mode
For this wee will need to include another one library: #include <avr/interrupt.h> Then wee will have to enable USART Receive Complete Interrupt (USART_RXC_vect) and enable global interrupts. And at last ti write interrupt service routine ISR(USART_RXC_vect). Lets write simple bounce program – USART sends back incremented by one what he received: #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> #ifndef F_CPU //define cpu clock speed if not defined #define F_CPU 3686400 #endif //set desired baud rate #define BAUDRATE 19200 //calculate UBRR value #define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1) void USART_Init() { //Set baud rate UBRRL=UBRRVAL; //low byte UBRRH=(UBRRVAL>>8); //high byte //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)| (0<<USBS)|(0<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0); //Enable Transmitter and Receiver and Interrupt on receive complete UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); //enable global interrupts set_sleep_mode(SLEEP_MODE_IDLE); sei(); } ISR(USART_RXC_vect) { //defien temp value for storing received byte uint8_t Temp; //Store data to temp Temp=UDR; Temp++;//increment //send received data back // no need to wait for empty send buffer UDR=Temp; } int main(void) { USART_Init(); while(1) sleep_mode(); //nothing here interrupts are working return 0; } Transmitter interrupt mode works same way. There are two flags indicating and generating interrupts: USART Data Register Empty(UDRE), which generates interrupt when UDR register is empty and ready to receive new data; and Transmit Complete (TXC) – generates interrupt when transmit is complete and no new data is in UDR. These interrupts are useful in half duplex mode, where transmitting operation mus enter receive mode. Also receive and transmit interrupt modes are often used in buffered mode when for example after all multi-byte data buffer is sent interrupt may request to load new data or set USART for receive mode. But as I mentioned Interrupt mode frees MCU resources and allows to run other background tasks like sending information to LCD, Reading button states, flashing LED and so on. In other hand Interrupts has to be short enough so they wouldn't block other interrupts. More interrupts – more care should be taken while setting them.
Related Items:
|