AVR code problems with USART

Status
Not open for further replies.

tyassin

Advanced Member level 1
Joined
Jul 22, 2004
Messages
467
Helped
86
Reputation
170
Reaction score
41
Trophy points
1,308
Activity points
3,804
Hello,

I have this code shown below.
When I press the corresponding button, the program enter the second IF-sentence as it should and displays the data on the LEDS. When I then press another button which should enter the first IF-sentence nothing happens, nothing is transmittet.
I can make it work if a press the button which enters the second IF-sentence and then quickly press the button which enters the first IF-sentence. Then it starts transmitting as long as I hold the button down.

Can anybody see what is wrong?
Thank you

Code:
#include <avr/io.h>
#include <util/delay.h>		//Max delay: 262.14 ms / F_CPU in MHz

//#define F_CPU 4000000// Clock Speed
//#define BAUD 9600
#define MYUBRR 24//F_CPU/16/BAUD-1

///////////////////////////////////////////////USART Init/////////////////////////////////////////////////////////
void USART_Init( unsigned int ubrr)
{
/* Set baud rate */
UCSR0A=(1<<U2X0);		//Divisor in BAUD set to 8. USX0=0 divisor=16, USX0=1 divisor=8
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 1stop bit */
UCSR0C = (0<<USBS0)|(3<<UCSZ00);
}
///////////////////////////////////////////////USART Transmit/////////////////////////////////////////////////////
void USART_Transmit( unsigned char data )
{
PORTD|=(1<<PD6);	//RS485==Transmit
_delay_ms(1);
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */

UDR0 = data;
//_delay_ms(1);
PORTD&=~(1<<PD6);	//PE6: RS485==Receive
}

///////////////////////////////////////////////USART Recieve//////////////////////////////////////////////////////
unsigned char USART_Receive( void )
{
/* Wait for data to be received */
while ( !(UCSR0A & (1<<RXC0)) );

/* Get and return received data from buffer */
return UDR0;
}

///////////////////////////////////////////////Main///////////////////////////////////////////////////////////////
int main(void)
{
   USART_Init(MYUBRR);
   
   DDRA=0xFF;		//PORTA output. LEDs connected to this port
   DDRD=0xFF;		//PORTF output
   DDRC=0x00;		//PORTC input 
   
   PORTC=0xFF;		//Set PORTC to 'High'
            
   PORTA=0xFF;		//Turn OFF all LEDs
   PORTD&=~(1<<PD6);	//PE6: Receive
   
   unsigned char x=0;
      
   while(1)
   {
	   
	   if ((PINC & 0x01)==0)
	   { 
		   PORTA=0x00;
		   
		   USART_Transmit(0x54);		   
	   }	   
	   
	   if ((PINC & 0x02)==0)
	   {
		   PORTA=USART_Receive();
	   }
	   
	   
   } 
}
 

Re: AVR code not working

Are you sure that the code doesn't freeze waiting to receive UART data?

You can use a counter and escape the receive function when it reaches the specified value.

for example

Code:
unsigned char USART_Receive( void )
{
    volatile uint16_t counter=0;

    /* Wait for data to be received */
    while ( !(UCSR0A & (1<<RXC0)) ) {
        counter++;
        if (counter==20000) break; //change according to needed delay

    }

    /* Get and return received data from buffer */
      if (counter != 20000) return UDR0;
	  else return 255; // all leds off

}
Alex
 

Re: AVR code not working

Hello Alex,

Thank you for the answer.
What do you mean by freeze? How is that possible?

Is it correct that when the transmit and receive functions are initialized, it is not necessary to call them in the main function because they are interrupt driven?

Regards
 

Re: AVR code not working

You are currently using this function

Code:
unsigned char USART_Receive( void )
{
[B]/* Wait for data to be received */[/B]
while ( !(UCSR0A & (1<<RXC0)) );

/* Get and return received data from buffer */
return UDR0;
}

Note the bold comment, the execution will stop there (in the while loop) until a byte is received from the UART, until then code execution is considered to be frozen, you will not get any kind or reaction from buttons.

You can use interrupt driven UART communication if you enable this setting, check the following articles , they have everything you need to use the UART.

View topic - [TUT] [SOFT] Using the USART - Serial communications :: AVR Freaks
View topic - [TUT] [SOFT] Using the USART - Interrupt driven serial comms :: AVR Freaks

Alex
 
Re: AVR code not working

Yes yes I see it now. Good to have some "fresh" eyes reviewing. I think I will look into the interrupt driven UART.
Thanks for the help.




---------- Post added at 20:48 ---------- Previous post was at 19:15 ----------

By the way could you suggest a way to use the transmit driven interrupt to receive several bytes?

Regards
 
Last edited:

Re: AVR code not working

Check out those two files from an ATmega1281 project, using USART1. It is the low level implementation (USART1 initialization, receive/transmit byte and interrupts).
Frankly I don't remember if every AVR has the USART control bits at the same position and at the same register. If you use different AVR, compare datasheets and take care of corresponding bits of USART registers to be the same as attached file's initialization routine. These files are working fine in a project of mine, compiled to IAR EW.

View attachment usart.rar


Happy coding!
 

Re: AVR code not working

Alexxx, your code doesn't check the transmitter or receiver buffer, I don't understand how can this work correctly.

Code:
void USART_Transmit( unsigned char data ) {

    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) );
    
	/* Put data into buffer, sends the data */
    UDR0 = data;
}

unsigned char USART_Receive( void ) {
    
	/* Wait for data to be received */
    while ( !(UCSR0A & (1<<RXC0)) );

    /* Get and return received data from buffer */
    return UDR0;
}

if you don't include the above conditions (unless you are using USART interrupts) then you can easily overwrite the transmit buffer multiple times before a character is actually send or get wrong data result from the receive buffer that hasn't received data.
I don't see interrupts being used in your code.

Alex
 
Last edited:

Re: AVR code not working

alexan_e said:
I don't see interrupts being used in your code.

Look into usart.c down to the bottom and you will find the interrupt routines.
 

Re: AVR code not working

Yes I saw the interrupts functions but no code was written in them, I would expect to see the GetByte and SendByte called from the interrupts but I suppose you are using another interrupt function that is not shown.

Alex
 

Re: AVR code not working

alexan_e said:
Yes I saw the interrupts functions but no code was written in them, I would expect to see the GetByte and SendByte called from the interrupts but I suppose you are using another interrupt function that is not shown.

No extra interrupts. My actual code is:

Code:
#pragma vector = USART1_RX_vect
__interrupt void USART1_Rx_ISR (void)
{ 
  USART1RxInterruptCallback(); 
}
  
#pragma vector = USART1_TX_vect 
__interrupt void USART1_Tx_ISR (void)
{ 
  USART1TxInterruptCallback(); 
}

Inside the above callbacks, GetByte() and SendByte() are called, along with many other things like checksum validation, fscanf and fprintf, start and stop frames validation, communication reset where necessary etc. For the time being and as I mentioned, I am posting the low level part.

It is the low level implementation

This is why I left the interrupt functions blank, so that his own code would be placed in there.

The high level part would only be confusing for him right now, since he is currently implementing USART with interrupts. When USART works correctly, then we can discuss about his protocol implementation.


Alexandros
 
Re: AVR code not working

Hi,

About the interrupt routines, is it OK to call functions or multiple inside an interrupt routine?
 

Re: AVR code not working

Yes you can call functions from inside the interrupt function but in any case try to keep the interrupt code as small as possible because the main loop doesn't resume execution until your interrupt function exits.

Alex
 

Re: AVR code not working

Hello,

I have managed to have my USART code in the first post functioning correctly, also with the interrupt routines.
But I am interested in knowing more on how to implement protocols?

Regards
 

tyassin said:
But I am interested in knowing more on how to implement protocols?

When we say protocol, don't think of something really fancy or complicated. It could be fancy, but this is not always the case. It is just an agreed way of communication, so that you will be able to succesfully communicate with another device. If this device is programmed by someone else, then you must agree the protocol with this other person. If you have another device already working, then you should study this device's protocol and implement it on your device. If the devices are programmed by you, then you must implement it to both devices. If more devices are involved (like an RS-485 network), then you should agree this with all the involving programmers. As you understood we are talking about own protocols, and not market standards. But even then an agreement should also be made, at the higher level of what information each byte represents. This must be done at any case.

None can say for sure what an own protocol would include. It depends on the application. Some basic stuff you usually see are a start and a stop byte or frame, a checksum and a timeout counter. Depending on the communication, things could be more complicated. If for example the frame length varies, then one of the databytes should carry the information of the databytes number in the frame. Or the checksum for example. It could be just an addition of all bytes, or XOR, or CRC etc. It depends on how much security you need or how much proccess power you are willing to spend. All these compose a "puzzle" you must carefully think of, in order to construct your own protocol.
 
Last edited:

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…