[TUT] [SOFT] Using the USART - Interrupt driven serial comms

Go To Last Post
341 posts / 0 new

Pages

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(USART_TXC_vect) 
{ 
     sensor= ((ADCH << 8 ) | ADCL);//read value out of ADC 
     UDR = ((sensor<< 6)>>4)| 0x01; //send value to software 
}

It shows me error:

../try_usart.c:27: warning: 'USART_RXC_vect' appears to be a misspelled signal handler

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

'USART_RXC_vect' appears to be a misspelled signal handler

Which AVR are you building for? Have you checked what the vector is actually called in the User Manual or the ioXXX.h file?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
It shows me error:

../try_usart.c:27: warning: 'USART_RXC_vect' appears to be a misspelled signal handler

but the code you show is

Quote:

ISR(USART_TXC_vect) 
...


:roll:
Something is mis-quoted...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am building for ATMEGA640...

Here is my code:


#include 
#include 
#include 
void USART_Init(void);
void USARTTransmit( unsigned char data );
unsigned char USARTReceive( void );
void USART_Init()
{
/* Set baud rate hard coded to 19200 for 12MHz */
UBRR0L = 38;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
UCSR0B |= (1 << RXCIE0); // Enable the USART Recieve Complete interrupt (USART_RXC)
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
}

int main (void)
{
	USART_Init();
	for(;;);
}
//*****************************************
ISR(USART0_RXC_vect)
{
	
	uint8_t c;
	uint16_t address;
	uint8_t byteValue;
	uint16_t wordValue;
	c = UDR0;
	//Disable the intrrupt

		if( c == 'b') // Read Byte 
		{
			// Send command byte 0x62
			// Send address byte
			// Receive data byte

			address = USARTReceive();

			USARTTransmit(eeprom_read_byte((uint8_t*)address));			
		}
		else if(c == 'B') // Write Byte
		{
			// Send command byte 0x42
			// Send address byte
			// Send byte to write

			address = USARTReceive();

			byteValue = USARTReceive();
			eeprom_busy_wait();
			eeprom_write_byte((uint8_t*)address,byteValue);
		}
		else if(c == 'w') // Read Word
		{			
			// Send command byte 0x77
			// Send address high byte
			// Send address low byte
			// Receive word high byte
			// Receive word low byte

			address = (USARTReceive() << 8);
			address |= USARTReceive();

			wordValue = eeprom_read_word((uint16_t*)address);

			USARTTransmit(wordValue>>8);
			USARTTransmit(wordValue);			
		}
		else if(c == 'W') // Write Word
		{
			// Send command byte 0x57
			// Send address high byte
			// Send address low byte
			// Send word high byte
			// Send word low byte
					
			address = (USARTReceive() << 8);
			address |= USARTReceive();

			wordValue = (uint16_t)(USARTReceive()<<8);
			wordValue |= (uint16_t)USARTReceive();

			eeprom_busy_wait();
			eeprom_write_word((uint16_t*)address,wordValue);
		}
		else if(c == 'k') // Read Block
		{

			// Send command byte 0x6b
			// Send size high byte
			// Send size low byte
			// Send EEPROM address start high byte
			// Send EEPROM address start low byte
			// Receive number of bytes specified by size

			//NOTE: We are limiting this to 80 bytes for this test
			// 	this code SHOULD work for the full EEPROM if the
			//  array is set to the EEPROM size - not tested though.
			uint8_t localBlock[80]; 		
			uint16_t size; 
			uint16_t address;

			size = (USARTReceive() << 8);
			size |= USARTReceive();

			address = (USARTReceive() << 8);
			address |= USARTReceive();

			// Limit size to 80 due to localBlock array size
			if(size > 80) 
			{
			 	USARTTransmit('?');
				return; 
			}

			eeprom_read_block((void*)localBlock,(const void*)address,size);				
		
			int i;
			for(i=0;i
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using ATMEGA640.Yes I check manual.

0x0032 jmp USART0_RXC ; USART0 RX Complete Handler

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Vector names for 640 are:

C:\WinAVR-20100110\avr\include\avr>grep _vect iomxx0_1.h | grep USART
#define USART0_RX_vect                  _VECTOR(25)
#define USART0_UDRE_vect                _VECTOR(26)
#define USART0_TX_vect                  _VECTOR(27)
#define USART1_RX_vect                  _VECTOR(36)
#define USART1_UDRE_vect                _VECTOR(37)
#define USART1_TX_vect                  _VECTOR(38)
#define USART2_RX_vect                  _VECTOR(51)
#define USART2_UDRE_vect                _VECTOR(52)
#define USART2_TX_vect                  _VECTOR(53)
#define USART3_RX_vect                  _VECTOR(54)
#define USART3_UDRE_vect                _VECTOR(55)
#define USART3_TX_vect                  _VECTOR(56)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK I got my mistake... I have one more question... How should I debugg my UART?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am trying to follow this tutorial and test UART. I am using ATMEGA640. so I modify the code accordingly. I am using hyper terminal to send and recieve the data.

I am using the internal clock source of 2MZ. I read the datasheet and set the baudrate 9600 to set the minimum error 0.2% according to the table given in datasheet.

I have few question regarding the hyper terminal
(1) Which protocol should I select to send the file
(2) what should be my type of file which I am sending. TEXT or Hex
(3) What should be the type of connection

Here is the my code which I am using:


#include  

#define USART_BAUDRATE 9600 
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) 

int main (void) 
{ 
   char ReceivedByte; 

   UCSR0B |= (1 << RXEN0) | (1 << TXEN0);   // Turn on the transmission and reception circuitry 
   UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes 

   UBRR0L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register 
   UBRR0H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register 

   for (;;) // Loop forever 
   { 
      while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been recieved and is ready to be read from UDR 
      ReceivedByte = UDR0; // Fetch the recieved byte value into the variable "ByteReceived" 

      while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it 
      UDR0 = ReceivedByte; // Echo back the received byte back to the computer 
   }    
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I am using the internal clock source of 2MZ.

You SURE about that? Is it actually working? (once again you have failed to say what the problem actually is)

As for sending files - what kind of files? how big? Sending them from where and to where? Obviously X/Y/Z modem are obvious choices for binary file transfers but is the data binary or is it ASCII? If the latter most terminal programs simply have "send text file" and "capture text file" options anyway.

BTW this thread is to discuss the tutorial and possibly ask questions directly related to it. When your question becomes more general this is NOT the right thread to use to ask about this.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#include 
#include 
#include 

#include "usart.h"



void USARTInit(uint16_t ubrrvalue)
{
	//Setup q
	UQFront=UQEnd=-1;

	//Set Baud rate
	UBRRH=(unsigned char)(ubrrvalue>>8);
	UBRRL=(unsigned char)ubrrvalue;

	/*Set Frame Format
	
	Asynchronous mode
	No Parity
	1 StopBit
	char size 8

	*/

	UCSRC=(1<<URSEL)|(3<<UCSZ0);

	/*Enable Interrupts
	RXCIE- Receive complete
	UDRIE- Data register empty

	Enable The recevier and transmitter

	*/

	UCSRB=(1<<RXCIE)|(1<<RXEN);
	sei();

}

//The USART ISR
ISR(USART_RXC_VECT)
{
	//Read the data
	char data=UDR;

	//Now add it to q

	if(((UQEnd==RECEIVE_BUFF_SIZE-1) && UQFront==0) || ((UQEnd+1)==UQFront))
	{
		//Q Full
		UQFront++;
		if(UQFront==RECEIVE_BUFF_SIZE) UQFront=0;
	}
	

	if(UQEnd==RECEIVE_BUFF_SIZE-1)
		UQEnd=0;
	else
		UQEnd++;


	URBuff[UQEnd]=data;

	if(UQFront==-1) UQFront=0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

some one can explain this coding?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

some one can explain this coding?

It'd be far easier if the author hadn't stripped the comments from it!

It's not complete code. There's no sign of the global variables it uses and it enabled both TX and RX interrupts but only provide an ISR for RX.

However of what is shown it's clear that there's a receive array URBuff[] with a size of RECEIVE_BUFF_SIZE and it appears to have read and write pointers called UQFront and UQEnd. New characters are written to the circular buffer at UQEnd (the write pointer) and when it wraps off the end of the array it is set back to the start (hence circular). It moves the read pointer on by one if the write pointer catches the read pointer (losing one buffered character).

To be honest it looks like a poor implementation of a circular buffer (not least of which is because of the lack of comments). In this thread you'll find a link posted by abcminiuser to his site at fourwalledcubicle.com which has circular buffer routines. You'd be FAR better off using those.

(apart from anything else you get very easy access to support as Dean is a regular here)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this is complete code use as librery file in project of rf communication
[code]
#include
#include
#include

#include "usart.h"

void USARTInit(uint16_t ubrrvalue)
{
//Setup q
UQFront=UQEnd=-1;

//Set Baud rate
UBRRH=(unsigned char)(ubrrvalue>>8);
UBRRL=(unsigned char)ubrrvalue;

/*Set Frame Format

Asynchronous mode
No Parity
1 StopBit
char size 8

*/

UCSRC=(1<<URSEL)|(3<<UCSZ0);

/*Enable Interrupts
RXCIE- Receive complete
UDRIE- Data register empty

Enable The recevier and transmitter

*/

UCSRB=(1<<RXCIE)|(1<<RXEN);
sei();

}

//The USART ISR
ISR(USART_RXC_VECT)
{
//Read the data
char data=UDR;

//Now add it to q

if(((UQEnd==RECEIVE_BUFF_SIZE-1) && UQFront==0) || ((UQEnd+1)==UQFront))
{
//Q Full
UQFront++;
if(UQFront==RECEIVE_BUFF_SIZE) UQFront=0;
}

if(UQEnd==RECEIVE_BUFF_SIZE-1)
UQEnd=0;
else
UQEnd++;

URBuff[UQEnd]=data;

if(UQFront==-1) UQFront=0;

}

char UReadData()
{
char data;

//Check if q is empty
if(UQFront==-1)
return 0;

data=URBuff[UQFront];

if(UQFront==UQEnd)
{
//If single data is left
//So empty q
UQFront=UQEnd=-1;
}
else
{
UQFront++;

if(UQFront==RECEIVE_BUFF_SIZE)
UQFront=0;
}

return data;
}

void UWriteData(char data)
{
//Wait For Transmitter to become ready
while(!(UCSRA & (1<<UDRE)));

//Now write
UDR=data;
}

uint8_t UDataAvailable()
{
if(UQFront==-1) return 0;
if(UQFront return(UQEnd-UQFront+1);
else if(UQFront>UQEnd)
return (RECEIVE_BUFF_SIZE-UQFront+UQEnd+1);
else
return 1;
}

void UWriteString(char *str)
{
while((*str)!='\0')
{
UWriteData(*str);
str++;
}

Last Edited: Fri. Sep 10, 2010 - 07:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

complete code is given above this is use as librery file in project
pleas explain uint8_t UDataAvailable() and ISR(USART_RXC_VECT)block
the main block is

#include 

#include "usart.h"

void main()
{

	uint8_t i; //Clasical loop varriable
	
	uint8_t packet[5],data=0;
	
	DDRC|=0xFF;	//All Output

	//Initialize the USART with Baud rate = 2400bps
	USARTInit(416);

	/*
	Get data from the remote Tx Station
	The data is the value of PORTC on Remote Tx Board
	So we will copy it to the PORTC of this board.
	*/

	while(1)
	{
		//Wait for a packet
		while(!UDataAvailable());
		if(UReadData()!='A') continue;
		while(!UDataAvailable());
		if(UReadData()!='A') continue;
		
		while(UDataAvailable()!=3);

		//Get the packet
		for(i=2;i<5;i++)
		{
			packet[i]=UReadData();
		}

		//Is it ok?
		if(packet[2]!=((uint8_t)~packet[3])) continue;

		if(packet[4]!='Z') continue;

		//The packet is ok
		data=packet[2];

		//Now we have data put it to PORTC
		PORTC=data;
	}
		

}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

pleas someone explain above 2 coding

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why? If you want circular buffers I've already told you a better solution where you'll get well documented code and access to the author if there's anything you don't understand.

You can generally judge the quality of code by how well commented it is. The code you present probably scores 1/10 on the quality scale by that measure.

For a general explanation of circular (aka ring) buffers just google "circular buffer" or "ring buffer".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hai.........

i am working on gsmproject using interrupts.......

i managed to send AT command continuously and i used interrupt subroutine as below:

usart_receive()
{
while ((UCSRA & (1 << RXC)) == 0) {};
return UDR0;
}

ISR(USART0_RX_vect)
{

ch[i]=usart_receive();
i++;

}

using this sub routine i am trying to accept the characters check for "OK" and then trying to glow leds when ch=="OK"............

when MICROCONTROLLER is connected to PC and using hyperterminal AT is transmitted continuously and whenever in between i send "OK" the leds are glowing.......

but when the same thing connected to gsm modem its not responding.....

but when gsm is connected to PC using hyperterminal i sent at and received "OK".......

PROBLEM IS : when i am integrating MICROCONTROLLER with GSM there is no response..........
please suggest me if any modifications is needed.......

sravani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You don't need the while() loop in your code - when the USART0_RX_vect interrupt fires, this bit will always be set (since the interrupt executes only when a character has been received). However, your problem is unrelated to that, it is just less than optimal code.

I suspect that your modem makes use of the extra serial handshake lines, such as DCD and RTS/CTS. You may need to connect these to the appropriate logic levels to allow the modem to transmit. These special handshake lines are used for "flow control", so that the host device (usually a PC) can stop the modem from transmitting until it is ready to receive more data.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes...........
RTS and CTS of microcontroller are shorted as mentioned in avr tool user guide in help option of avr studio software.........

sravani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ALL watchout this is a cross post.

https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=98522&start=all&postdays=0&postorder=asc

the OP has a timing issue but is not listening to what others say.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sorry sir, very sorry for not replying you and made you angry.....now the LEDs problem and transmission with USART is solved. now we are working with reception. And reception is also working when PC & MICROCONTROLLER is interfaced, but when we connect MICROCONTROLLER with GSM modem is not responding.

we identified:
when we type OK in the hyperterminal, LEDs will glow which is a part of the program that we have written as

ISR(USART0_RX_vect)
{
received[i] = UDR0;
i++;
if(strcmp(received,"OK")==0)
PORTA = 0x00;
}

so that we could come to know that it is responding when we interfaced PC & MICROCONTROLLER

PROBLEM:
same command when MICROCONTROLLER transmits to the GSM modem,LEDs are not glowing.

sravani

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a tutorial thread to teach people about using the USART. The subsequent thread is here ONLY to discuss aspects of that article directly. It's not Aunt Agatha's problem page to air every last UART problem you may have. We have a whole forum (AVR Forum) for that. If this is a cross post as meslomp says then continue the discussion in the OTHER thread. Not here.

Moderator.

PS and DO NOT cross post in future.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Excellent guide man, as usual!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Dean, this is great tutorial, I think. Thank you very much.

I want create a project that use UART to communicate two processors. I use ATMEGA168 with 20MHz system clock to send 19 blocks of characters and ATMEGA32 with 16MHz system clock to receive those characters. I also use similar code as "Ring Buffer" that you told it before.

My question, will different system clock on two processor cause trouble in sending and receiving those characters?

and is there any suggestion for me on what type of serial communication that I should use, UART or USRT?

thank you very much.

best regard,
muhammad abdur

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

My question, will different system clock on two processor cause trouble in sending and receiving those characters?

No, as long as they are running the same baud rate then however they get to that doesn't matter. The key thing is simply that both systems are within 2% of the other one's baud rate.

As long as they are using crystals (I guess they must be to run at 16/20MHz) then asynchronous, rather than synchronous will be just fine.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much Dean!!
That's a great tutorial!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wonderful tutorial Dean. I would like to add in my 2ç though. If following along with this tut on an atmega168-20pu, like I was. The ISR vector is USART_RX_vect. No 'C' or number. This one caught me up good even while staring at the page of interrupt vectors for the chip. But I am happy that it now works as expected. :)

edit: spelling.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey,

I'm new to using Atmega uC. I've written the following code to receive the data serially from serial port at 9600 baud. The code works fine!

I wish to increment a variable so that I can keep account of number of bytes recevied in my main program, but while loop which doesnot seem to get this done for me. Can someone kindly point the bug!

I've attached the code herewith;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You've fallen into the #1 trap regarding using C in embedded apps: You've failed to declare your ISR/main-shared variable(s) volatile.

Read more here: http://www.nongnu.org/avr-libc/u...

And here: https://www.avrfreaks.net/index.p...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey!

Thanks for your valuable time! It's was the problem, just declaring it to volatile did the trick!

Thanks very much!!!

- Moses

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

My question, will different system clock on two processor cause trouble in sending and receiving those characters?

No, as long as they are running the same baud rate then however they get to that doesn't matter. The key thing is simply that both systems are within 2% of the other one's baud rate.

As long as they are using crystals (I guess they must be to run at 16/20MHz) then asynchronous, rather than synchronous will be just fine.

thx you clawson.

my second question, is that possible, if I use Rx Interrupt and Tx non interrupt?

thx you so much.

best regards,
muhammadabdur.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

is that possible, if I use Rx Interrupt and Tx non interrupt

That's what I often use myself - so, yes.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ERR

Last Edited: Fri. Sep 2, 2011 - 09:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I'm unable to post a longer code using the "code" & "/code" don't know why, so attached it);

The forum does not like percent-signs in posts.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Can anyone guide me where I'm going wrong?

Your code seems to assume that the buffer is of infinite size and that indx++ can continue until the end of eternity. The whole point about a "ring" or "circular" buffer is that you know that the buffer is N bytes long so you do something like:

indx++
if (indx >= N) {
  indx = 0;
}

in this way you never write past buff[N-1]. When you get to the end of the buffer this just takes it back to the start. Hence the terms "ring" or "circular".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:
Quote:

I'm unable to post a longer code using the "code" & "/code" don't know why, so attached it);

The forum does not like percent-signs in posts.

Yes I read it a bit late! Now I've no problem with this! Thanks!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey,

I got the trick!!! As Clawson interpreted correctly I was trying to fetch every thing that comes my way from UART, finding it a odd way. I got the concept of circular buffer understood right, but my difficulty goes something like this;

I'll read N(N is Known, say 10 bytes) & shift them as the new bytes is available, just like FIFO. Thus at any point I'll have last 10 bytes with me. During process I also have to check the buffer for a particular pattern say "te:" or "No:". Once detected I want to store what ever follows to a safe location up to '\r' or '\n'. If the buffer is shifting continously I'm finding it difficulty in locating the position of the found element pattern. Some guidance needed for this, I'll write my own code.

-Moses

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It was really very helpfull.
Actually Im doing a project on GSM based home automation.
and im using SIM COM 300 GSM module and Atmega16L.....
Im having problem in the coding part,,,,,and i need help,,,, Im not getting what will happen when a new message is received and how to monitor an incoming message....please help.....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This thread only exists to discuss details of the tutorial in the first post - not to diagnose every last UART problem. Take your question to a separate thread in AVR Forum.

Moderator.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi
I now how to send a character?
The program that you've written, any changes I will not care.

#include 
#include 

#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

int main (void)
{
   UCSRB |= (1 << RXEN) | (1 << TXEN);   // Turn on the transmission and reception circuitry
   UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes

   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register

   UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC)
   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed

   for (;;) // Loop forever
   {
         // Do nothing - echoing is handled by the ISR instead of in the main loop
   }   
}

ISR(USART_RXC_vect)
{
   char ReceivedByte;
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived"
   UDR = ReceivedByte; // Echo back the received byte back to the computer
} 

I want to send a number to the micro and micro to the number dialed then I have a job.
But I do not know inside how do I put variable! Please let s a clearer example of the program?
thnx

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To send/receive variable contents it's often easiest (because humans can read these things) to convert to and from ASCII digits. Use sprintf()/itoa() to convert a variable into a human readable string of characters - send this across the UART link then use atoi() at the receiving end to convert the ASCII back to binary if you need it in that form.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sagenepal wrote:
Hello,

I want to share this code in order to help out Stefan and anyone else who wants to to UART transmit using interrupts. This code uses the TXC interrupt, not UDRE. I don't know much about the latter. Maybe it would be better? But this code works, and it has a nice wrap-around buffer for very efficient use of processor time.

- Sage Radachowsky
Boston, USA

// SendWithInterrupt - main.c
//
// by Sage Radachowsky, Feb-Mar 2008 ("sager" at "mit" dot "edu")
//
//
// Program to test sending data to the serial output (UART / RS232) using interrupts
// instead of actively polling to check if the last byte was written.
//
// This has two advantages -- the CPU is using its built-in hardware signals rather than
// burning CPU instructions so it consumes less power, and (2) the CPU is freed
// to do other things rather than wait for some 9600 baud output or even 57k baud output,
// which is a heck of a long time in a multi-MHz world.
//
// This is written for the AT90CAN128 microcontroller, which has 2 UART lines. To rewrite
// it for any Atmel AVR micro that has just one serial line, you would have to change the
// names of all the UART registers to remove the "0".
//
// Note that interrupts must be globally enabled for this stuff to work - of course!
//
// This code sets up the interrupts to interface with stdout, so that "printf()" sends
// by interrupt! Easy and Sweet!
//
// NOTE: Be sure to change your CPU speed if it's not 1.8432 MHz !
//




//**********************************************
//                DEFINITIONS
//**********************************************



// CPU frequency
#define F_CPU 1843200L   // 1.8432 MHz

// UART baud rate
#define UART_BAUD  9600 

// UART buffer size
#define UART_BUFFER_SIZE 256


//**********************************************
//               HEADER FILES
//**********************************************


#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include 




//**********************************************
//            FUNCTION DECLARATIONS
//**********************************************

void         USART0_Init(void);
static int   UART0_Putchar(char c, FILE *stream);
void         DelayAwhile(void);


//**********************************************
//               GLOBAL VARIABLES
//**********************************************

char UartBuffer[UART_BUFFER_SIZE]; // this is a wrap-around buffer
int  UartBufferNextByteToSend; // position of next byte to be sent
int  UartBufferNextFree; // position of next free byte of buffer
int  UartSendingInProgress; // 1 = sending is in progress


/* This is the pointer to the serial interface */
/* Defines the stream interface for write only */

FILE uart_str = FDEV_SETUP_STREAM (UART0_Putchar, NULL, _FDEV_SETUP_WRITE);




// ################## here we GO! ####################

int main()

{

	// initialize the UART and enable interrupts
	USART0_Init(); sei();

	printf ("Hello from SendWithInterrupt.\n");
	DelayAwhile();


	// loop forever
	while (1)
	{

		printf ("This is test output. How's the weather?\n");
		DelayAwhile();

	}


}


//===============================================================================
  void DelayAwhile()

//
// Delays a while, to slow down to a human level.
//


{
	_delay_ms(200);
	_delay_ms(200);
	_delay_ms(200);
}





//****************************************************
//                 UART functions
//****************************************************




//===============================================================================
  void USART0_Init() 

// This routine initializes the UART0 port of the AT90CAN128 and clears the
// write buffer.
//
// This routine does NOT enable the transmit-complete interrupt (TXCIE0).
// That is left up to the UART0_PutChar() routine, after it puts something in
// the buffer for the first time.
//
// This routine also does NOT enable general interrupts. That is left to the
// main() initializing code, and it MUST be done for this stuff to work.
//
// Also sets standard out to the uart interface, so printf() works sweetly.
//

{ 

	// init buffer data structures
	UartBuffer[0] = '\0'; // clear the first byte of buffer
	UartBufferNextByteToSend = 0; // set "next byte to send" to beginning
	UartBufferNextFree = 0; // next free byte is also beginning of buffer
	UartSendingInProgress = 0; // clear "sending in progress" flag

	// set baud rate
	UBRR0H = (unsigned char) (((F_CPU/(16L*UART_BAUD))-1) >> 8); 
	UBRR0L = (unsigned char) ((F_CPU/(16L*UART_BAUD))-1); 

	// Set frame format: 8data, no parity & 1 stop bits
	UCSR0C = (0<<UMSEL0) | (0<<UPM0) | (0<<USBS0) | (3<<UCSZ00); 


	// Enable transmit
	UCSR0B = (1<<TXEN0); //Enable the transmitter only

 	// set standard output stream to our UART interface
	stdout = &uart_str;

} 


//===============================================================================
  static int UART0_Putchar(char c, FILE *stream)

// If transmit is in progress, adds a character to the UART output buffer.
// If transmit is not in progress, kicks off a transmit.
//
// The send buffer is a wrap-around buffer.
//
// If the buffer is full, then this routine returns EOF.
// A successful completion returns 0.
//
// This routine disables the UART Tx interrupt temporarily, because
// things would get funky if the interrupt signal routine were called during
// execution of this routione.
//
// If the buffer was empty to start with, then this routine "primes the pump"
// sending the character directly to the UART.
//
// This routine also adds carriage returns to newlines.
//

{
	register int ReturnStatus = 0; // return 0 for success
	register int UartBufferNextFree_last; // space to save last UartBufferNextFree

	// if character is a "newline" then add a "carriage return" before it.
	if (c == '\n')
		UART0_Putchar('\r', stream);


	// if no send is already in progress, then "prime the pump" by sending directly to UART
	if (UartSendingInProgress == 0)
	{
		// set "sending in progress" flag
		UartSendingInProgress = 1;
		// send the first byte!
		UDR0 = c;
	}
	else
	{
		// disable the Tx Complete interrupt
		UCSR0B &= ~( 1 << TXCIE0 );

		UartBuffer[UartBufferNextFree] = c;

		// increment the next free byte index, while saving last value
		UartBufferNextFree_last = UartBufferNextFree++;

	 	// check for wrap-around
		if (UartBufferNextFree == UART_BUFFER_SIZE) // if we reached the end of the buffer -
	  		UartBufferNextFree = 0; // start back at the beginning

		if (UartBufferNextFree == UartBufferNextByteToSend) // if buffer is full -
		{
			// bump back the index so transmit routine doesn't think buffer's empty
			UartBufferNextFree = UartBufferNextFree_last;
			// return with error code	
			ReturnStatus = EOF; 
		}
		
		// enable the Tx Complete interrupt
		UCSR0B |= ( 1 << TXCIE0 );
	}


	// return with status code
	return ReturnStatus;
}









//********************************
//       INTERRUPT HANDLERS
//********************************


//===============================================================================
   ISR (USART0_TX_vect)


// This interrupt service routine is called when a byte has been sent through the
// UART0 port, and it's ready to receive the next byte for transmission.
//
// If there are more bytes to send, then send the next one and increment the index.
// If the index reached the end of the buffer, then wrap around to the beginning.
//
// If there is not another byte to write, then clear the "UartSendingInProgress"
// flag, otherwise set it if a byte has just been sent.
//

{
	if (UartBufferNextByteToSend == UartBufferNextFree)  // if nothing to send -
	{
	  	UartSendingInProgress = 0;	// clear "sending in progress" flag
	    return; // then we have nothing to do, so return
	}

	// set "sending in progress" flag
	UartSendingInProgress = 1;

	// send the next byte on UART0 port
	UDR0 = UartBuffer[UartBufferNextByteToSend];

	// increment index and check for wrap-around
	UartBufferNextByteToSend++;
	if (UartBufferNextByteToSend == UART_BUFFER_SIZE) // if we reached the end of the buffer -
		UartBufferNextByteToSend = 0; // then start back at the beginning

}

Have fun!

Can this method of using streams and stdout etc be used in a similar way to read in strings? Ie stdin, an Rx interrupt, buffer and then reading with say scanf?

Im half way through doing so and wanted to make sure Im not on a futile path. Im aiming towards a simple way to have interrupt powered functions that easily send and capture complete strings from the UARTs. Thanks guys!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Can this method of using streams and stdout etc be used in a similar way to read in strings? Ie stdin, an Rx interrupt, buffer and then reading with say scanf?

See the user manual:

http://www.nongnu.org/avr-libc/u...

As you'll see that implements two output streams (LCD and UART) and one input stream (UART)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Preface: I have not read all 13 pages of comments -- just the original tutorial, and pages 11 - 13 of comments (i.e., "recent" comments).

After reading the tutorial, I have written my ISR as:

ISR(USART1_RX_vect) {
	uint8_t rxByte;
	uint8_t dummyByte;

	if(!rxFlag1) {	//Buffer has been read by decode function
		while(!(UCSR1A & (1 << RXC1)))
		{}
		rxByte = UDR1;
		if(rxByte == 10 || rxByte == 13) {	//NL or CR
			rxFlag1 = 1;
		}
		else {
			if(bufcnt1 > (RXBUFSZ-1))
				bufcnt1 = (RXBUFSZ - 1);
			rx_buffer[bufcnt1] = rxByte;
			bufcnt1++;
		}
	}
	else {
		while(!(UCSR1A & (1 << RXC1)))
		{}
		dummyByte = UDR1;	//throw away bytes received before ready
	}
}

If I am understanding a comment several pages earlier (by Dean?) correctly, the while(!...) loops are not necessary, because the bit will definitely be set if the ISR is called. Is this correct? Does this change if the incoming messages are extremely rapid, i.e., faster than the ISR can handle them?

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Is this correct?

Yes, there are two ways to use a bit such as RXC or UDRE. One is to simply have a "polled" receive or transmit routine which is called synchronously and does not return until the action has completed. In this case you "block" on the specified bit in a while() loop that repeats until the desired state is achieved. The other way to use the flags is to make use of interrupts and do things asychronously so the main() code can get on and do other things and when triggered the ISR fires and receives/sends the character. The main() code *may* block in this case but it will be on a volatile flag set by the ISR to say something of relevance has happened (perhaps an entire string has been received to the buffer or similar).

What you should not do is mix asychronous use of the flags together with synchronous polling loops. In fact, unless it's guaranteed to happen in microseconds, no ISR should ever block on an asychronous event flag because it could be seconds or minutes before the event occurs (during which time the entire interrupt/main system is blocked from doing anything). Of course you can "block" on a flag even that you KNOW is already set without any problem (which is what your code does) but why would you do this. Even if the while() is done only once it's one time more than you need.

You are on dodgy ground if you start writing ISRs that take longer to process than the period of the event they are reacting too as you may never "get out". But with circular ISR buffering as long as the buffer is large enough to cope with a "sudden burst of activity" (assuming there's then an interval allowing for the buffer to be processed/flushed) then you'll be OK.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clawson: thanks for the reply. As you may have noted, I am also involved in a ... heated... discussion about serial comms over in the other forum. This was an attempt to not get this thread offtrack (not an attempt at cross posting).

I will remove the while loops from my code. That said, is your warning about lengthy ISRs directed explicitly at this piece of code? I am unsure how to make it leaner. My handling routine (that deals with the actual message) may be slow, in which case I am fine throwing away incoming data -- which is what I think happens with the whole rxFlag1 variable (reset by the handling function when it is done).

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

That said, is your warning about lengthy ISRs directed explicitly at this piece of code? I am unsure how to make it leaner

No, by a fluke (perhaps by design) there's no problem with the while() loops you have because they check for a bit that's known to be set so don't (hardly!) delay the action. But more generally you should always be asking yourself if you are really doing the right thing if you ever put ANY kind of iterative loop in an ISR. The goal is that through whatever code path they always complete in a time measured in microseconds (on 1MHz..20MHz processors). With Serial Rx your ISR is almost always going to be identical. You pick up UDR and you put it into a circular buffer at the write pointer position that is then incremented and if it wraps then reset it to the beginning (hence "ring" or "circular"). This action is the only work that HAS to be in the ISR, any "data processing" should be handled outside the ISR with I enabled again so nothing else is being blocked from happening. Having said that some people might put a special check for '\n' in a RXC ISR if they need quick/special notification of the "end of sentence".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Noted. Thanks for the info. I will refrain from using possibly infinite loops in ISRs in the future.

Science is not consensus. Science is numbers.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well explained...thanks...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hii... i`ve simple code that make me so confused...
i want to turn on the led from the keyboard via usart...

this is the code:

#include 
#include 
#include 

#define LED PORTA

uint8_t data;

ISR(USART_RXC_vect)
{
data=UDR;
LED=data;
}

void USARTinit(uint16_t ubrr_value)
{
set baudrate
UBRRL=ubrr_value;
UBRRH=(ubrr_value>>8);


UCSRC=(1<<URSEL)|(3<<UCSZ0);

//ENABLE THE RECEIVER AND TRANSMITTER
UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); //REGISTER RXCIE YANG MENGAKTIFKAN INTERUPT NYA...
sei();
}

int main(void)
{
DDRA=0XFF;
USARTinit(71);

while(1)
{
	
};

}

The program work well...

but if i want to make something different.. like this code :

#include 
#include 
#include 

#define LED PORTA

uint8_t data;

ISR(USART_RXC_vect)
{
data=UDR;

}

void USARTinit(uint16_t ubrr_value)
{
// set baudrate
UBRRL=ubrr_value;
//UBRRH=(ubrr_value>>8);

//	Asynchronous mode
//	No Parity
//	1 Stop Bit
//	Char size 8

UCSRC=(1<<URSEL)|(3<<UCSZ0);

//ENABLE THE RECEIVER AND TRANSMITTER
UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); //REGISTER RXCIE YANG MENGAKTIFKAN INTERUPT NYA...
sei();
}




int main(void)
{

DDRA=0XFF;


USARTinit(71);

while(1)
{
	
LED=data;
};
}

The program cannot work like the previous program...
how to make its work in while(1){};....?

Pages