Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
abcminiuser
PostPosted: Mar 30, 2007 - 09:37 AM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

For an updated version of this tutorial in PDF format, please see this page of my website.

Interrupt driven USARTs

The following is a short extension of my previous tutorial, Using the USART - Serial communications. This tutorial will teach the basics for creating interrupt-driven USART communications. It assumes that the reader has both read and fully understood my previous tutorial on basic serial communications.



Interrupts?

AVRs - and almost all microcontrollers - contain a feature known as interrupts. Interrupts, as their name implies, allows for external events (such as inputs from the user or AVR peripheral) to momentarily pause the main microcontroller program and execute an "Interrupt Service Routine" (shorthand "ISR") before resuming the main program where it left off. Interrupts are extremely useful for dealing with irregular input (such as pin changes or the arrival of a serial byte), as well as for processing "background tasks" like togling a LED each time a timer overflows.

In this tutorial, we are going to make use of the AVR's USART peripheral interrupts.



A recap, our echo program

From the last serial tutorial, we have created a simple program from scratch which will echo bytes received on the AVR's USART interface. The full program listing is as follows:

Code:
#include <avr/io.h>

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

int main (void)
{
   char ReceivedByte;

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

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

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

      while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
      UDR = ReceivedByte; // Echo back the received byte back to the computer
   }   
}


Readers should be able to fully understand this code - if you cannot please re-read the previous tutorial on basic serial communication.

Now, we want to extend this code so that the serial data is echoed back when received in an interrupt, rather than our main program loop. To do this, first we need to include the AVRLIBC standard library header, "avr/interrupt.h". This file contains library functions and macros which relate to the interrupt functionality of the AVR. We'll add this to the top of our code, below the "avr/io.h" header include:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>


Once included, we now have a way to make our ISR to deal with the serial reception. To make an ISR, we use the syntax:

Code:
ISR({Vector Name})
{
   // Code to be executed when ISR fires
}


And place it in our program as if it was a normal function. To add one to deal with the reception of a byte via the USART, we need to look for the appropriate name in our AVR's datasheet. In the datasheet for our example AVR, the MEGA16, we see that the name of the interrupt for when a byte is received is "USART_RXC". The standard AVRLIBC library file "avr/io.h" - included in our program as well as any other AVR-GCC program involving the AVR's IO functionality - defines the vector names for us.

AVRLIBC's symbolic names for each of the interrupt vectors is identical to the datasheet, with the addition of a "_vect" suffix to denote that it is a vector name. So, as our datasheet listed "USART_RXC" as the vector name, the syntax for our program is:

Code:
ISR(USART_RXC_vect)
{
   // Code to be executed when the USART receives a byte here
}


Which we'll place at the end of our program, after our main function. The new program looks like this:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

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

int main (void)
{
   char ReceivedByte;

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

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

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

      while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
      UDR = ReceivedByte; // Echo back the received byte back to the computer
   }   
}

ISR(USART_RXC_vect)
{
   // Code to be executed when the USART receives a byte here
}




Populating the ISR

At the moment our new USART reception ISR doesn't actually do anything - we've just defined it. We want it to echo back the byte that is sent, so we'll move our main loop code:

Code:
while ((UCSRA & (1 << RXC)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR
ReceivedByte = UDR; // Fetch the received byte value into the variable "ByteReceived"

while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ReceivedByte; // Echo back the received byte back to the computer


Over to it. However, we can now remove the two while loops - since the ISR only fires when a byte is received, and only one byte is sent after each reception we can guarantee that both checks are now redundant. When the ISR fires we know that there is both a byte received in the USART input buffer, as well as nothing in the output buffer. Using this knowledge, we can simplify our ISR code to the following:

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


Note that I've also moved the variable declaration of "ReceivedByte" over to the ISR, as that is now where it is actually used.

It's worth mentioning at this point a small section on the datasheet about the RXC interrupt:

Quote:
When interrupt-driven data reception is used, the receive complete routine must read the received data from UDR in order to clear the RXC Flag, otherwise a new interrupt will occur once the interrupt routine terminates.


That's important to remember - if you are using the RXC interrupt, you must read a byte from the UDR register to clear the interrupt flag. We do that in our above code, but keep it in mind for your future projects!


Enabling the USART receive interrupt

Let's take a look at the latest incarnation of our test code:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

#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

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

   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 received byte value into the variable "ByteReceived"
   UDR = ReceivedByte; // Echo back the received byte back to the computer
}


If you compile and run this, you'll notice that nothing happens - no characters are echoed back to the PC. This is because although we've defined and populated the ISR, we haven't enabled it. To do so, we need to do two things:

    1) Turn on global interrupts
    2) Enable the USART Byte Received interrupt



Item one is simple, so we'll do that first. The AVR microcontrollers contain a global flag which can be set or cleared to enable or disable the handling of interrupts. Note that setting this flag doesn't enable all interrupts, it only allows for the possibility of running them. If the Global Interrupt Enable flag is disabled, all interrupts will be ignored, even if they are enabled (more on that later).

To turn on the Global Interrupt Enable flag, we can use the macro "sei()" which the "avr/interrupt.h" library helpfully defines for us. This is so named as it generates a "SEI" assembly instruction in the final code listing, which the AVR interprets as an order to set the Global Interrupt Enable flag. The compliment of "sei()" is "cli()" (to turn off the handling of interrupts) however we will not be using that macro in this tutorial.

We'll add our "sei();" instruction to our main routine, after configuring the USART registers:

Code:

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

   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed

   for (;;) // Loop forever
   // ...



Now for item 2 on our list, which needs to be performed before the interrupt will be enabled. We need to specifically enable the USART Receive Complete interrupt, which we can do by setting the appropriate flag in the USART control register.

In the MEGA16, this bit is called RXCIE (Recieve Complete Interrupt Enable) and is part of UCSRB. Setting this bit enables the handling of the USART_RXC event vector:

Code:
UCSRB |= (1 << RXCIE);


We'll add this to our main routine, before our new "sei();" command.



Putting it all together

Now we have a working interrupt driven serial example:

Code:
#include <avr/io.h>
#include <avr/interrupt.h>

#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

   UBRRH = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
   UBRRL = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low 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 received byte value into the variable "ByteReceived"
   UDR = ReceivedByte; // Echo back the received byte back to the computer
}


Which, like out original program, will echo characters received via the USART. However, because our program is now interrupt driven, we can add in code into the main loop which will be executed when data is not received - such as flashing a LED.


Interrupts allow for infrequent "background" tasks to be executed when they occur, without posing a run-time penalty of having to poll the hardware until the even occurs. This frees up our main loop to take care of the critical code, with the interrupt code pausing the main code to execute when the event of interest ocurs.

Interrupts should be made to be as short as possible in execution time. This is because while one ISR is executing, others are blocked and thus if another ISR condition occurs while one ISR is executing, that ISR event will be missed or delayed.

Because of this, communication ISRs are generally made short by receiving in characters via an ISR, and placing them into a buffer which the main code may read at its leisure. This ensures that received data will not be missed, while giving the main program time to complete what it is currently doing before having to process the input. Similarly, long transmissions may be made by placing the data to be sent into a buffer, and have an interrupt send the data as the hardware is ready while the main program performs other tasks.




Please note that the names of the registers and bits for the UART(s) in the AVR you are using may be different from those shown above. In place of UDR, UBRRH, UCSRA etc. you may find they are called UDR0 (or UDR1), UBRR0H, UCSR0A and so on.

I hope this tutorial is informative - if not please post your suggestions! I'm open to feedback, and please feel free to post your own examples, code, etc. below.


For an updated version of this tutorial in PDF format, please see this page of my website.

- Dean Twisted Evil

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


Last edited by abcminiuser on Oct 02, 2013 - 01:01 PM; edited 9 times in total
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Bitshuffler
PostPosted: Mar 30, 2007 - 03:45 PM
Newbie


Joined: Feb 27, 2006
Posts: 17


Hi Dean, thanks for the great tutorial. One thing - I think the line:

Code:

   UCSRB |= (1 << RCXIE); // Enable the USART Recieve Complete interrupt (USART_RXC)


actually needs to use RXCIE rather than RCXIE. I have this running and it's working great in hyperterminal.

A quick question: Do you know a way to do a 'full speed' loopback test in windows? Typing isn't really stressing it at all. I'm using Artur Lipowski's USART library in a motor controller project and I'm losing the occasional character (with a 0% error clock frequency). I'd like to blast a large text file through the loopback, capture it when it gets back to the pc and then do a file compare to test for differences. ie if the avr is doing nothing but passing the character back and there are still errors I can narrow it down to some problems on my board.

Thanks again for the tutorial, it's very timely. I've been fighting with the usart for a couple of days now. much appreciated.

Update: I went away and checked and hyperterminal has a "paste to host" option that allows you to paste in a large block of text. I turned off local echo and posted in a large source file. Although this method doesn't allow an actual file compare, inspection showed that the AVR returned the text file completely intact. I guess this means there is some problem with my motor control code fighting with the code to handle the USART, although I'm not sure how.

Anyway, thanks once again for your great tutorial. I'll look at implementing a simple circular buffer based off your code and swapping my existing handler out.

Cheers
Andrew


Last edited by Bitshuffler on Mar 30, 2007 - 04:05 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
smileymicros
PostPosted: Mar 30, 2007 - 04:01 PM
Raving lunatic


Joined: Nov 17, 2004
Posts: 6504
Location: Great Smokey Mountains.

Connect your TxD pin to your RxD pin.

Smiley

_________________
FREE TUTORIAL: 'Quick Start Guide for Using the WinAVR C Compiler with ATMEL's AVR Butterfly' AVAILABLE AT: http://www.smileymicros.com
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Bitshuffler
PostPosted: Mar 30, 2007 - 06:42 PM
Newbie


Joined: Feb 27, 2006
Posts: 17


Thanks for the thought, Smiley. But I don't think that's what I need - I was sorta using the avr for the loopback, just sending stuff to the chip and trying to measure if I got exactly the same stuff back.

Actually I think I understand what's happening now.

The UART code works fine in a project that does nothing but send/recieve characters, but if I include it in the motor controller (with 5 servo motors) it drops characters.

BUT (and here's the n00b thing to watch) if the motors are disconnected there's no problem and no dropped characters. So it appears to be the motors drawing current that are causing the problems. (Typical - I'm a software guy so I think in terms of software problems. I'll just go and beat myself with a stick now. :-/ )

I've seen many schematics that put a capacitor between Supply and ground probably for this very reason. Please pardon my ignorance. Perhaps if someone could confirm I'm guessing right, and verify what to do about it it'd be great, and thanks again.

Andrew
 
 View user's profile Send private message  
Reply with quote Back to top
bloody-orc
PostPosted: Mar 30, 2007 - 07:17 PM
Posting Freak


Joined: Dec 17, 2005
Posts: 1610
Location: Europe- Estonia- Tallinn

"reverse" diodes on the motor lines (4 in total per motor), a 0.1uF ceramic cap as close as possible to the AVR power pins. this should minimize the motors effect on the circuit. power isolation would be the best (with optical isolation on the control signal) but i doubt you need that much of "protection".
You could also add a capacitor triangle on the motor leads (if using DC motor): cap between leads, lead1 to case, lead2 to case. also ceramic.

very OT although Wink maybe could be moved to another thread in OT or something...
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
Bitshuffler
PostPosted: Mar 31, 2007 - 01:37 AM
Newbie


Joined: Feb 27, 2006
Posts: 17


Thank you very much for your help (although I profess to not completely understanding what you said i can research it and work it out now you have given me a direction.) Smile

Apologies if this is off topic. I considered before posting here, but thought - if the beginner is trying to use the USART and it's dropping characters then it'd be worth highlighting this as possible cause to consider. Once again, apologies and let me know if I should delete my posts here, and thanks again.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Mar 31, 2007 - 04:40 AM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

Quote:
actually needs to use RXCIE rather than RCXIE. I have this running and it's working great in hyperterminal.


Whoops! I wrote the above in response to your post, since you were having trouble (and I thought I could help others at the same time). Should have checked the datasheet more thoroughly. I'll fix that ASAP.

Sorry about the lack of polish on this one - I only had an hour in which to write it. So long as I get my main point across I suppose it's a passable tutorial Wink.

- Dean Twisted Evil

_________________
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Tobbe
PostPosted: Apr 03, 2007 - 06:53 PM
Newbie


Joined: Apr 03, 2007
Posts: 3


Great tutorial. It will definitely come in handy. Thanks! I have a question though I am not entirely sure I should post it here, but I'll do so anyway. (If you want me to delete it and repost somewhere else, just ask!)

Your code works wonders if I only recieve one byte (one character) of data. But what happens if I want to recieve, let's say, 5 consecutive bytes? This probably just requires some smart C-code, but it I believe it is somewhat connected to how the AVR works too. Remember that I am a novice, but I still hope my question makes sense. Let me explain.

Let's say I want to send 5 bytes of data. Now as I see it, if I have multiple interrupts enabled in my program, they will stack them and do them one after another in the order they happened? Is that correct? So let's say that I send a byte but I am currently in another interrupt, that is when a character is sent I will not directly go to ISR(USART_RXC_vect) since another interrupt is currently beeing processed. Let's say this interrupt also takes some time. What will happen then? Will the sender just write 5 characters really fast and thus not let the AVR get a chance to read the bytes one by one. ie will only the last byte sent be read when the AVR finally goes into the ISR(USART_RXC_vect) interrupt function? Will only the last byte be in the UDR?

What I am basically asking is will the AVR somehow recieve bytes into a certain buffer and not send them out to the UDR register until it has been read when receiving data? Or do I have somehow have to use the RTS/CTS flags in the RS232 protocol? (even though I have no clue how that would work anyway with this particual problem)

Thanks for any answers I might get.

Edit:
I also found a very nonsignificant error heh.
Code:
char ReceivedByte;
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived"

should probably be:
Code:
char ReceivedByte;
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ReceivedByte"
 
 View user's profile Send private message  
Reply with quote Back to top
bloody-orc
PostPosted: Apr 03, 2007 - 07:40 PM
Posting Freak


Joined: Dec 17, 2005
Posts: 1610
Location: Europe- Estonia- Tallinn

No they will not be stacked like you said. when you are in a interrupt routine all other interrupts are disabled. so you should get out if it as fast as possible.

I'll see if I can find my code on receiving more than one byte...
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 04, 2007 - 03:27 AM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

The UDR register is double buffered, I think, so you have have two pending characters in it at a time (reading one then frees up that place for the next character).

If one interrupt is executing, other interrupts that are pending will have have to wait until the current interrupt is complete. It's possible to make interrupts that are themselves interruptible, but that's an advanced topic and certain to cause problems if you don't know what you are doing.

To receive blocks of characters, you need to stuff them into a buffer inside the interrupt (to keep it short), then read those characters out later in your main routine to process them. This is commonly done in the form of a "Ring Buffer", a special type of circular buffer. You might want to Google that to find some example code (or I could PM some to you).

- Dean Twisted Evil

_________________
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Tobbe
PostPosted: Apr 04, 2007 - 11:08 PM
Newbie


Joined: Apr 03, 2007
Posts: 3


Thanks for the informative answer Dean. I just have one followupquestion. bloody-orc said all other interrupts are disabled. I read that as they won't happen at all if I'm currently in another interrupt. When I read your post I read it as they will indeed stack and happen one after another, in the order they happened? Which one of thoose two statements are correct?

Also, I'd love some example code! Thanks in advance.
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 04, 2007 - 11:40 PM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

The interrupts semi-stack. What happens when an interrupt is entered, is that the global interrupt flag (allowing for the processing of pending interrupts) is disabled. Interrupt conditions can still cause other interrupt's flags to be set, however the ISRs won't fire until the currently executing ISR ends (and re-enables the global interrupt enable flag). The order of which the pending interrupts are processed once the ISR exits is dependent on the Interrupt's priority - its order in the vector table.

Each interrupt can only have its flag set once, so if two Pin Change interrupts occur (for example) while you are processing the LCD interrupt, the Pin Change ISR will only fire once when the LCD ISR completes.

Make sense?

- Dean Twisted Evil

_________________
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Siebesiech
PostPosted: Apr 05, 2007 - 10:55 AM
Newbie


Joined: Nov 09, 2006
Posts: 2
Location: Switzerland

Hi together
I have a similar problem but in the opposite way.
I have to dend data with a baudrate of 38400 over the rs232 to an other software.
I tried to make an interrupt on the "USART_TXC_vect" that looks like this.

Code:
(main)
sei();
UCSRB |= (1 << RXEN) | (1 << TXEN) ; // Turn on the transmission and reception circuitry


(Timerroutine)
ISR(SIG_OVERFLOW1)
{
...
program
...
after initialisation the software
UCSRB |= (1 << TXCIE); // Enable the USART Transmit Complete interrupt (USART_TXC)
...
(end timerroutine)

//Interruptroutine
ISR(USART_TXC_vect)
{
     sensor= ((ADCH << 8 ) | ADCL);//read value out of ADC
     UDR = ((sensor<< 6)>>4)| 0x01; //send value to software
}


I tried this but it doesn't work.
Is this generally posible like this?
(I have to send with this baudrate, but parallel to sending data I've to controll the display and keys of my device(this works) in my program.)
Thanks for some help.
Stefan
(I've an atmega32)
 
 View user's profile Send private message  
Reply with quote Back to top
abcminiuser
PostPosted: Apr 05, 2007 - 12:33 PM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

Please use the forum [code ] [ /code] tags (without the spaces) when posting code - it keeps the formatting and makes it easier to read. I've fixed your above post, but the indentation was eaten by the board.

You don't seem to have set up the ADC in your code. You need to do that before the ADCH/ADCL register values become valid.

Also, "sensor" isn't defined in your code. Where is it defined and what is it defined as?

The shifting and ORing of the two ADC registers creates a 16-bit value (of which only 10 bits are used), which is placed in your "Sensor" variable. However, the UDR register is only 8-bit, so you'll be loosing bits when you send them. You seem to have some weird shifting going on:

Code:
UDR = ((sensor<< 6)>>4)| 0x01; //send value to software


Equates to:

Code:
UDR = ((sensor << 2)| 0x01); //send value to software


Which means you're shifting the 10 bits to the left twice, then ORing with 0x01. That will cause bit 0 to always be one, and bit 1 to always be read as 0. Is this what you want? Also, since UDR is only 8 bit as mentioned, that value will be cast down and the upper 8 bits thrown away. So what you're actually sending is the lower 6 bits of the ADC register pair shifted left twice, and the LSB set.

- Dean Twisted Evil

_________________
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
lfmorrison
PostPosted: Apr 05, 2007 - 01:07 PM
Raving lunatic


Joined: Dec 08, 2004
Posts: 4722
Location: Nova Scotia, Canada

One other thing to keep in mind is that there are actually two different interrupt vectors associated with the USART transmitter:
1) A "UART Data Register Empty" (UDRE) interrupt will fire continually as long as there's space in the double-buffered UDR for additional characters to be added to the hardware queue.

2) A "UART Transmit Complete" (TXC) interrupt will fire once following the completion of the final queued character.

If you design an application based solely on the TXC interrupt -- as you've done above -- you must "prime the pump" by sending the first character of a multi-byte transaction manually, and then the TXC interrupt will eventually fire when that byte is totally finished and the UART is sitting idle waiting for some more data.

I think it's easier to write software based on the UDRE interrupt instead. All you need to do in that case is populate a software buffer, then enable the UDRE interrupt source -- the hardware will take care of the rest.

In some circumstances it is appropriate to use both forms of transmitter interrupts in tandem -- for example when you don't want to have to bother with "priming the pump" so the UDRE interrupt is more convenient, but you also need to take a special action (such as switching the data direction of an RS485 transceiver) after you're certain that the final byte of a transaction has cleared the UART.


Last edited by lfmorrison on Apr 05, 2007 - 01:08 PM; edited 1 time in total
 
 View user's profile Send private message  
Reply with quote Back to top
Siebesiech
PostPosted: Apr 05, 2007 - 01:08 PM
Newbie


Joined: Nov 09, 2006
Posts: 2
Location: Switzerland

Sorry, perhaps i was a bit imprecise.
It works with the ADC, i didn't wrote de code above to save time and don't confuse you Wink...
I "only" have problems to get the baudrate, so that every circle has a new "Sensor"-value.
So I tried to make an interrupt with the TXCIE-Bit to know when it's ok to fill in the data to UDR (when the UDR is empty).
Or to say it in another way: when TXE-Interrupt comes, i use to write the sensor-data to UDR.
I hope you got what i mean. it's a little bit complicated to explain.
 
 View user's profile Send private message  
Reply with quote Back to top
Tobbe
PostPosted: Apr 05, 2007 - 03:31 PM
Newbie


Joined: Apr 03, 2007
Posts: 3


Thanks Dean. It makes perfect sense. It stacks the interrupts by priority. So if a priority interrupt flag of priority 1 is set, it goes is put at the top of the stack and fires as soon as the current ISR is finished.

Also, I am fairly certain I could create the "ring buffer" code myself, but I'd be more than happy if you could provide me with an example through a PM. It'd save me time. Thanks again for the wonderful and detailed explanations.
 
 View user's profile Send private message  
Reply with quote Back to top
anilsoni85
PostPosted: Apr 18, 2007 - 12:21 PM
Rookie


Joined: Mar 29, 2007
Posts: 32


hey this code not working when i tried to complie this code i got an warning that
../SMS_Controller.c:135: warning: 'USART_RXC_vect' appears to be a misspelled signal handler
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
abcminiuser
PostPosted: Apr 18, 2007 - 12:26 PM
Moderator


Joined: Jan 23, 2004
Posts: 10228
Location: Melbourne, Australia

You may be using an old version of WinAVR (actually, an old version of avrlib-c which is included in the package). The "*_vect" names were added in a recent release and the old "SIG_*" names deprecated - an up-to-date version is in the current WinAVR 20070122.

If you don't want to upgrade, try the old name "SIG_USART_RECV" (or "SIG_UART_RECV" depending on your chosen AVR model).

- Dean Twisted Evil

_________________
Make Atmel Studio better with my free extensions. Open source and feedback welcome!
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
anilsoni85
PostPosted: Apr 18, 2007 - 08:44 PM
Rookie


Joined: Mar 29, 2007
Posts: 32


I am using the latest verion of WinAVR 20070122 and my avr is atmega8535 still i m getting this warining what could be reason behind this??
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits