# I can't get out from interrupt driven serial communication

program works correctly but after receiving '#' it has to come out from while loop and print "Exit" on lcd but it doesn't.program still in while loop.

#define F_CPU 14745600
#include<avr/io.h>
#include<avr/interrupt.h>
#include<util/delay.h>
char data;
int ser=1;
void uart2_init(void)
{
UCSR2B = 0x00; //disable while setting baud rate
UCSR2A = 0x00;
UCSR2C = 0x06;
UBRR2L = 0x5F; //set baud rate lo
UBRR2H = 0x00; //set baud rate hi
UCSR2B = 0x98;
}

ISR(USART2_RX_vect)         // ISR for receive complete interrupt
{
data = UDR2;
lcd_wr_char(data);

if(data=='#')
{
ser=0;
}
}

void init_devices()
{
cli(); //Clears the global interrupts

lcd_port_config();
uart2_init();

sei();   //Enables the global interrupts
}

//Main Function
int main(void)
{
init_devices();
lcd_set_4bit();
lcd_init();
while(ser);
lcd_string("Exit");
}

• Where is ser declared? Have you marked it as volatile? – Roger Rowland Feb 11 '16 at 12:27
• ... also, where is it initialized? – Dave Tweed Feb 11 '16 at 12:58
• Remove the line "if (data=='#'). Now on the first character you receive you should send it to the LCD and then print "Exit" on the LCD. If that works as expected, then my guess is that data is being corrupted somehow. – Steve G Feb 11 '16 at 13:14
• I have missed the qualifier "volatile". After adding it ,code works correctly. Thank You – Pravein Feb 11 '16 at 13:22
• Avoid unecessary computing in ISR, you can put a flag and execute in main. – Marko Buršič Feb 11 '16 at 13:51

You have ser not declared as volatile. What this means is the compiler doesn't know it can be changed in an ISR.

Essentially ser is initialised to 1. In the main() function, the compiler will examine the code and see that it gets to the while(ser) loop. Now as far as it can see, ser is never changed from the moment it is initialised to the moment the while() loop is reached (because it can see that the main() function doesn't call anything that changes the value). It can also see that ser doesn't change within the while() loop.

What this means is as far as the compiler can see, the while() loop will always be entered because ser is 1, but never exited because ser is not changed anywhere that it knows the execution can reach.

It then says, well if the while() loop will never exit, then there is no point checking the value of ser, nor is there any point including any of the code after the loop (as it will never be reached). The whole loop will optimise to simply:

rjmp .-2


Which represents an infinite loop (it will jump back to itself and repeat forever).

But wait I hear you cry. ser can be changed. It's modified in the ISR. Well, ok, it is, you know that, but the compiler doesn't. It is unaware that the processor can suddenly jump to another bit of code all on its own (well, when an interrupt is triggered actually). You need to tell it that this can happen.

By declaring something as volatile, it instructs the compiler to always load from memory the value of that memory whenever it is used. This means that the compiler can't assume that it will never change, because it has been told that it specifically must check. It is no longer able to say with certainty that the value in the memory is the value it put there at the beginning.