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

Go To Last Post
339 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

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:

#include 

#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:

#include 
#include 

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:

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:

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:

#include 
#include 

#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:

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:

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:

#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

   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:

   // ...
   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:

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:

#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

   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:

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

Last Edited: Wed. Oct 2, 2013 - 12:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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

   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: Fri. Mar 30, 2007 - 03:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Connect your TxD pin to your RxD pin.

Smiley

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

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

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

"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 ;) maybe could be moved to another thread in OT or something...

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

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.) :)

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.

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

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 ;).

- Dean :twisted:

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

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

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.

char ReceivedByte; 
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 

should probably be:

char ReceivedByte; 
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ReceivedByte" 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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...

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

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:

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

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

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.

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

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:

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

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

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.

(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)

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

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:

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

Equates to:

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:

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

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

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: Thu. Apr 5, 2007 - 12:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

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 ;-)...
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.

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

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.

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

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

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

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:

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

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

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??

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

For the MEGA8515, the datasheet says that the vector is named "USART_RX_vect". "SIG_UART_RECV" should have also worked (despite being deprecated) - what error did you get when you used that?

- Dean :twisted:

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

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

I'm also having the same "warning: 'USART_RXC_vect' appears to be a misspelled signal handler" messages, however after I replace it to SIG_USART_RECV the warning message disappear, 0 warning message :D

but nothing is echoed back, nothing is shown in my hyperterminal windows, I used the same circuitry from 1st usart tutorial.
while the result from 1st tutorial are somewhat ok, this times it's far from ok :( :cry:

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

coolleo,

Sounds like your avr-gcc and avr-libc is out of date then. As you are using Windows I guess you are also using WinAVR - the latest is WinAVR20070525

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

Hi. I tried using the code posted in the tutorial. However, the microcontroller seems to be hanging once the interrupt occurs. I dont get back the sent data. Also, the background programme(a blinking LED) also stops the moment I transmit a byte from the computer.

I am using atmega16 with 1.8432 Mhz crystal. Normal usart works fine.Could you tell me what was going wrong?

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

Hey Dean,
Any plans to expand this to include interrupt driven transmition?
After reading lfmorisson's post in this thread I was thinking that the best way to do buffered transmition would be to have a function to queue data like

if (buffer empty interrupt off)
{
  enable buffer empty interrupt
  place first byte in buffer to send
  place the rest in the queue
}
else
{
  place everything in the queue
}

and then have the following in my buffer empty interrupt...

if (more stuff queued)
{
  place next byte in buffer
}
else
{
  disable buffer empty interrupt
}

This would allow my main code to actually go to sleep for periods at a time instead of constantly being awake if I just enabled the buffer empty interrupt and let it go all the time. Sound good?
I'm just worried that an interrupt may fire after doing the check in the queuing function, and turns off the interrupt if the queue is empty. Should I do a cli() just before the check and sei() after the end of the else statement?

Edward

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

I have the same query as above, by Edward (futrtrubl). The USARTs on my mega164p have a similar issue while receiving constant data at 4800 baud. I have ended up polling for flags ("loop_until_bit _is_set") on both Tx and Rx ends and miss a fair bit of characters (I still do that on the transmission end as you can see in the code). For starters, I'd atleast like an interrupt driven procedure for the incoming data on the reception end; but so far the service routine seems to miss out when it comes to execution.


static int uart_putchar( unsigned char cg , FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

static int uart_putchar(unsigned char cg, FILE *stream)
{
   if (cg == '\n')
        uart_putchar('\r', stream);
      loop_until_bit_is_set(UCSR0A, UDRE0);
      UDR0 = cg; // to terminal window at 1200baud.
      return 0;
}
void main(void)	
{

	init_devices(); // call to various initializing function. 
	PORTA = 0x01;
	
	for(;;)
	{
		if (newintFlag)
		{
			stdout = &mystdout;
			printf("%c\n",uart_rxData);
                        // printf("HelloWorld\n");
		}
	}
}

ISR(USART1_RX_vect)
{	
  uart_rxData=UDR1; // this variable is a volatile unsigned char 
  newintFlag = 1; // volatile static int

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

sorry , I missed a line while cleaning up the code.
I set the volatile variable newintFlag =0; in the if statement of my main().

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

I could expand it to include buffered transmission - it's very simple. The algorithm would be:

FUNCTION Main
  Enable TX Interrupt
  Enable Global Interrupts

  LOOP FOREVER
    {Do Stuff}
    Transmit_Data(Data)
    Sleep
  END LOOP
END FUNCTION

FUNCTION Transmit_Data(Data)
  IF (UDR NOT FULL)
    Store Data into RingBuffer
  ELSE
    UDR = Data
  END IF
END FUNCTION

ISR TX_ISR
  IF RingBuffer NOT EMPTY
    UDR = RingBuffer.Next
  END IF
END ISR

Fairly simple - you just need a buffer to hold the data before transmission. I've written just such a library - check out the "Advanced Configurable RingBuffer Library" entry on my Website here.

- Dean :twisted:

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

Last Edited: Tue. Aug 31, 2010 - 01:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The AVR actually has two different transmission-related interrupt mechanisms. The TX Complete inteerrupt fires after the last bit data has been clocked out of the UART and it is now sitting idle.

Alternatively, the TX Buffer Empty interrupt fires after the byte currently sitting in UDR as been moved into the shift register and it's safe to write a new byte to UDR for future transmission. This mechanism is possible because the UART't transmission system is actually buffered -- there are physically two separate registers, one of them is the shift register which holds the byte currently being clocked out, and the other is a holding register which can be filled ahead of time to ensure that there's always a byte queued up ready to automatically start transmission as soon as the transmitter is ready for it. This eliminates the idle period between the end of one byte and the start of the next.

Using the TX Buffer Empty interrupt can shave a few microseconds of idle time off of the transaction, potentially speeding up large bulk transmissions.

If Dean's algorithm doesn't meet your fancy, an alternative implementation would be:

FUNCTION Main 
  Enable Global Interrupts 

  LOOP FOREVER 
    {Do Stuff} 
    Transmit_Data(Data) 
    Sleep 
  END LOOP 
END FUNCTION 

FUNCTION Transmit_Data(Data) 
  Store Data into RingBuffer 
  Enable TX Buffer Empty Interrupt (instead of Dean's TX Complete Interrupt)
END FUNCTION 

ISR TX_BUFFER_EMPTY_ISR 
  IF RingBuffer NOT EMPTY 
    UDR = RingBuffer.Next 
  ELSE
    Disable TX Buffer Empty Interrupt
  END IF
END ISR 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Dean and lfmorrison. I think I will stick with the buffer empty interrupt route, as it simplifies my send function if I send more than one byte at a time, and shaving of idle time is always nice.

Edward

PS Dean, I think there could be a problem if the interrupt fires after you check that UDR is empty in Transmit_data() and there is no more data in the ring buffer. Data will be stuffed into the ring buffer but the tx interrupt will not fire again until another call to Transmit_data, at which point the data will be sent in the wrong order.

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

Dean:
I get the following error when attempting to implement the Ring Buffer Library:
../RingBuff.c:12: error: 'for' loop initial declaration used outside C99 mode

would you know what could cause that. I am actually trying to loop my transmitted data from one UART to the other via the ring buffer. However, I run into another problem when I initialize with both the RXC (rx_complete interrupt) and UDRE ( tx_buffer_empty interrupt) I fail to read anything ( on the output terminal). here is what I am trying to do:


RingBuff_t* DataBuff;
void main(void)	
{
	init_devices(); // Buffer_Initialize(DataBuff);

	for(;;)
	{
	}

}



//========= Rx Receive Flag Service Routine==================
ISR(_VECTOR(28)) //USART1_RX_vect
{
  Buffer_StoreElement(DataBuff, UDR1);
  UCSR0B |= (1 << UDRIE0) ; // enable output buff empty interrupt
 // uart_rxData = UDR1; 
 // newintFlag = 1;

}



ISR(_VECTOR(21)) //USART0_UDRE_vect
{
	if (!(Buffer_GetElement(DataBuff)))
	{
		// If Buffer Empty
		UCSR0B |= (0 << UDRIE0) ; // disable output buff empty interrupt	
	}
	else
	{
		UDR0 = 	Buffer_GetElement(DataBuff);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You need to configure your GCC installation to use the C99 standard. If you're using a makefile, change your -std line to:

CSTANDARD = -std=gnu99

If using AVRStudio as your frontend, change the standard via the project options screen.

- Dean :twisted:

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

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

thanks mate. got it working.

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

Dean:
actually I have been unable to store the "unsigned char" datatype in the ring buffer. i set the BUFF_DATATYPE configuration variable (default: uint8_t) to unsigned char with no luck. could you point me in the right direction here.

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

Hi santafree,

Sorry! I just went over my code and it took me quite a long time to realize I made a silly boo-boo. Your buffers should not be pointers to a RingBuff_t and should be passed by address. I've updated the zip on my site - download that and check out the corrected example (also made a few minor code changes).

- Dean :twisted:

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

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

abcminiuser wrote:
You need to configure your GCC installation to use the C99 standard. If you're using a makefile, change your -std line to:

CSTANDARD = -std=gnu99

If using AVRStudio as your frontend, change the standard via the project options screen.

- Dean :twisted:

I have the same problem with the GCC config, I'm usign AVRStudio and I cannot see how to change the standard in the project options screen.. would it be beacuse of my version? I'm using ver 4.13.524... or how can I change to the C99 standard??

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

Project-configuration options-custom options

If a -std=???? already exists then select it and use [edit], pressing [add] when finished. Otherwise just type "-std=gnu99" into the box to the left of [add] and then press that same add button.

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

In AVRStudio:

Project Menu -> Configuration Options. Select the "Custom Options" tab, in the text box type "-std=gnu99" and press the "Add" button. Click "Ok" to close the window and it should work fine.

Also check out my other tutorial on configuring AVRStudio for optimal GCC projects, as there's a few other pointers in there.

- Dean :twisted:

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

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

My program is not working, Help me please!!!

#include 
#include 
#include 
#include 
#include 

//Variables
#define Frec_Osc_Cristal 16934400  
#define Baud_Rate 250	
#define _U2X 1   //1 ó 0

//Definicion del UBRR para el Baud rate
#define _UBRRL ((Frec_Osc_Cristal/(Baud_Rate*(8*(2-_U2X))))-1)
int n;


void inicio(void)
{
	//Definicion del baud rate
	UBRRH = (_UBRRL>>8);
	UBRRL = _UBRRL;
	
	//8 bits|8 bits|2 stop bits|lecturaUCSRC pag 167
	UCSRC =(1 << UCSZ0 | 1 << UCSZ1 | 1<<USBS | 1<<URSEL);
	
	//habilit de interrup de Tx completada | habilit de interrup reg vacio|habilit tx
	UCSRB =(1 << TXCIE | 1 << UDRIE | 1<<TXEN);
	
	//si es uno doble el baud rate
	if (_U2X) UCSRA |= (1 << U2X);
	
	sei(); //Habilito las interrup globales

}


SIGNAL (SIG_UART_DATA) 
{ 
	n=0;
	while(n<=20)
	{
		n++;
		UDR = 0x01;
		PORTC =0xFF;
	}
}


SIGNAL (SIG_UART_TRANS) 
{ 
	PORTC =0x02;
}



void USART_Transmit( unsigned char data )
{
  while ( !( UCSRA & (1<<UDRE)) )
  UDR = data;
}



int main(void)
{
	inicio();
	//pin 0 y 1 de portc como salida
	DDRC=0xFF; 
 	
	
	while(1)
	{
		while(!(UCSRA & (1 << UDRE)))
		USART_Transmit(43);
		//PORTC =0x02;
		USART_Transmit(0xAA);
		PORTC =~ PORTC;
		n=0;
		
		while(n <= 0xFFF)
			n++;
	}
}

I don´t know that is my error

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

"not working" ???

(BTW SIGNAL() is deprecated - use ISR() these days)

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

clawson wrote:
"not working" ???

(BTW SIGNAL() is deprecated - use ISR() these days)

The led in portc no turn on, because USART_TXC_vect interrupt no working

#include 
#include 
#include 
#include 
#include 

//Variables
#define Frec_Osc_Cristal 16934400  
#define Baud_Rate 250	
#define _U2X 1   //1 ó 0

//Definicion del UBRR para el Baud rate
#define _UBRRL ((Frec_Osc_Cristal/(Baud_Rate*(8*(2-_U2X))))-1)
volatile int m=0;
int n;

void inicio(void)
{
	cli();
	
	//pin 0 y 1 de portc como salida
	DDRC=0xFF; 
	
	//Definicion del baud rate
	UBRRH = (_UBRRL>>8);
	UBRRL = _UBRRL;
	
	//8 bits|8 bits|2 stop bits|lecturaUCSRC pag 167
	UCSRC =(1 << UCSZ0 | 1 << UCSZ1 | 1<<USBS | 1<<URSEL);
	
	//habilit de interrup de Tx completada | habilit de interrup reg vacio|habilit tx
	UCSRB =(1 << TXCIE | 1 << UDRIE | 1<<TXEN);
	
	//si es uno doble el baud rate
	if (_U2X) UCSRA |= (1 << U2X);
	
	sei(); //Habilito las interrup globales

}

ISR(USART_UDRE_vect)  

{ 
	m++;
	if (m < 20)
	{
		UDR = 0x01;
		
	}
	else
	{
		m=0;
		PORTC=0x00;
	}
}


ISR(USART_TXC_vect) 
{ 
	PORTC =0xFF;
}



void USART_Transmit( unsigned char data )
{
  while ( !( UCSRA & (1<<UDRE)))
  UDR = data;
}

int main(void)
{
	inicio();
	while(!(UCSRA & (1 << UDRE)));
	USART_Transmit(43);
	
	while(1)
	{
	}
}

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

The TXC interrupt vector will only fire once after the final bit of a frame has been clocked out and there's nothing else buffered in UDR waiting for transmission.

Because of the way that your UDRE interrupt service routine is structured, there will *always* be something waiting in the UDR buffer. (Remember, the UDRE interrupt fires continually as long as there is space left in the UDR buffer.) Therefore, the TXC interrupt will *never* have a chance to fire.

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

With respect, as you would modify the program so that each 20 data (UDRE interrupt´s) the interruption TXC fire?

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

Well, that sort of depends, because I'm not convinced of exactly what you actually want that software to do.

You've got a call to UART_Transmit() in the mainline which will be competing with the constantly-firing UDRE interrupts for writing to UDR.

It's impossible for me to judge exactly what you actually intended to accomplish with the mainline's UART_Transmit() call, because the UDRE interrupts will already have started start firing, stuffing 0x01's through the UART, as soon as the last line of code in inicio() finishes executing.

I'd prefer to see a more complete process specification before I commented on how to structre any changes.

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

Just wondering if I can expect to be able to reliably test a Max232 chip on a breadboard? I have a VB6 program that is polling an AVR regularly and displaying the results on screen. Through the spare RS232 on the STK500 it works very well. But when I try to use a max232 chip I have set up on a breadboard using the circuit here the communications is not so good. It keeps losing connection as I am not getting a return from every request for data. I just want to make sure my circuit is OK before I make a pcb.

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

Taipan,

But you don't show the clock source to the AVR on your own circuit. Reliable comms generally means reliable clock source (and vice versa). Also do you have a scope and can look at the TX/RX signals for timing and any noise etc.

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

clawson wrote:
Taipan,

But you don't show the clock source to the AVR on your own circuit. Reliable comms generally means reliable clock source (and vice versa). Also do you have a scope and can look at the TX/RX signals for timing and any noise etc.


I have tried it 2 different ways, firstly with an Atmega16 along with a 7.3728 crystal and the Max232 on the breadboard, and secondly using the AVR on the STK500 and just routing the TXD/RXD to the Max232 on the breadboard. Both ways give about the same result.

Using Bray's Terminal I just have to send a single ascii character to get a return from the AVR. If I use the Spare RS232 on the STK500 I can hold down the key sending a continual stream of characters and get 100% return from the AVR. When I use the Max232 on the breadboard I am getting about an 80% return.

I do have a scope, but I don't know a lot about using it. I'll get it out tomorrow and give it a try. Thanks for the help.

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

I found my circuit worked OK at 9600 baud but I was initially trying to use 115200. At that speed some of the sent characters were arriving corrupted.

I forgot to say thanks for the great tutorial. It certainly made things easy for a beginner like myself.

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

By looking at iom8535.h, the recognized vector is USART_RX_vect. This is inconsistent with the datasheet, but USART_RX_vect (without the 'C') is copied from AVR Studio's partdescriptionfiles. I ran into the same problem with atmega8515, where the vectors are defined to be UART instead of USART. We maybe in a situation where GCC would say it is a problem originated from Atmel, and Atmel would say the partdescriptionfiles are only meant for AVR studio.

#define USART_RX_vect _VECTOR(11)

anilsoni85 wrote:
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??

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

Dean,
Thanks for posting such a clear tutorial! It is immensely useful in getting started with the USART.
One suggestion to clarify the ISR use: Please include a line mentioning how the Recieve Complete Interrupt flag clears (from the ATmega16 datasheet):

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.

This is similar to the explanation you gave in your timers tutorial for the OCF1A flag:
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106
In fact, had I not read that very useful tutorial, I wouldn't have known where to look in the datasheet to understand how the interrupt flag clears.
Again, thanks for adding such useful content to the forum. Keep 'em coming!!

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

Hi reg2117,

Thanks for the praise and comment. That's a good idea - I've added the datasheet quote to the tutorial. Thanks for the feedback!

- Dean :twisted:

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

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

Hi everyone. I encounter some problems when using USART. This is the senario: I need to transmit a string of characters through USART to a PC. Hyperterminal is the terminal emulator that I use at the PC end. I know this terminal is not good. But I have to use it. I tried to run the code posted over here and it worked perfectly. I can see every characters that I pressed. But when I change

UDR = ReceivedByte;

to

UDR = 'J';

or some other characters, something else will turn up on the terminal window. I don't have any idea how that happen. Do I need to set anything other than the baud rate and flow control? I normally use 2400, 8-N-1, Auto detect emulation.

Also, I am using ATmega8, at 8Mhz using calibrated internal RC oscillator.

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

Calibrated against what?

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

clawson wrote:
Calibrated against what?

I am not quite sure. I just load the calibration bytes into OSCCAL register

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

Well as long as you operate at normal room temperature and from a 5V supply the Atmel factory profiled valued should be OK and the 207 you load into UBRRL should be giving you just 0.2% error but to check maybe use a scope to measure the bit widths on transmitted characters (repeatedly sending 'U' is good for this!). For 2400 baud you are looking for 416.6us

Cliff

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

clawson wrote:
Well as long as you operate at normal room temperature and from a 5V supply the Atmel factory profiled valued should be OK and the 207 you load into UBRRL should be giving you just 0.2% error but to check maybe use a scope to measure the bit widths on transmitted characters (repeatedly sending 'U' is good for this!). For 2400 baud you are looking for 416.6us

Cliff


I know what you mean. I am aware of the 0.2% error too. I just don't understand why the Hyperterminal can recognize the echoed characters, but not the characters that are coded in the program. I am suspecting that Hyperterminal is not configure properly to recognize char that is sent by USART.

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

hello everyone, i am facing some problem when using the code below

ISR(USART_RXC_vect)
{ // USART RX interrupt
unsigned char c;
c = UDR;
}
the compile result get this
warning: 'USART_RXC_vect' appears to be a misspelled signal handler

i have no idea wat happening, :?

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

what AVR are you using, maybe it has more than one USART and needs to be USART0 or USART1?

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

i am using ATmega8535
because this interrupt is very simple to use..
1 more problem dunno anyone can help..
i am trying to set the
F_CPU = 11059200
baudrate = 2400
MYUBRR = 287
using the pony prog, and set the CKOPT at the configuration and security bit
the programmer circuit also putting 12MHz oscillator + 22pf capacitor..
and trying with hyperterminal, using IR communication
but unlucky that cant show the result when transmit from AVR to the hyperterminal..
can anyone help?
thanks :( :(

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

From iom8535.h:

/* USART, RX Complete */
#define USART_RX_vect			_VECTOR(11)

So try making it:

ISR(USART_RX_vect) {
  ...

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

Hi,

I seemed to have a problem with interrupt driven Usart so I tried to follow the example given in this tutorial. I have a AtMega128 at 16 MHz and I'm using USART1 on the device. Usart communication with polling is working on the same exact cirtuitry but interrupt based communication isn't.

My source code is as follows:

#include 
#include 
#include 

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

#include 

void delay(uint8_t);

int main (void)
{
   //char ReceivedByte;

    UCSR1B |= (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);   // 10011000 UCSRnB
    UCSR1C |= (1 << UCSZ0) | (1 << UCSZ1); // 00000110 UCSRnC

    UBRR1L = BAUD_PRESCALE; // Load lower 8-bits of the baud rate value into the low byte of the UBRR register
    UBRR1H = (BAUD_PRESCALE >> 8); // Load upper 8-bits of the baud rate value into the high byte of the UBRR register
	DDRA |= 1<<PA6; // Port A pin 6 as output
	sei(); // enable interrupts
	
   for (;;)
   {
   	delay(250);
   	PORTA ^= 1<<PA6; // Toggle led on and off
   }   
}

int SRI(USART1_RX_vect){
	char ReceivedByte;
   ReceivedByte = UDR1; // Fetch the recieved byte value into the variable "ByteReceived"
   UDR1 = ReceivedByte; // Echo back the received byte to the computer
   return 0; back 
}

When I run the code, led toggles happily. The time when I try to connect Usart with MiniCom it seems that the program hangs inside of the interrupt handler. I am using Linux and as there where proposals earlier in this thread that older versions of AVRLibC and AVR-GCC might be the problem, I compiled version 4.2.2 GCC as target AVR and I also compiled AVRLibC 1.4.6. Oh and of course binutils 2.18.

Any idea what might be wrong? Am I forgetting something or is my AVR broken or Is the fault in my toolchain?

I configured the source for toolchain like this:

binutils 2.18

configure --target=avr --program-prefix="avr-"

(avr-)gcc 4.2.2

configure --target=avr --program-prefix="avr-" --enable-languages=c --disable-libssp

AVRLibC 1.4.6

configure --host=avr

When I compile the code I showed earlier it compiles without warnings (with -Wall). Should I use some other flags when compiling the gcc? Or any other idea what might be wrong? I would need help with this problem urgently. I really hope that someone could help.

thanks
Mikko

"I have made this letter longer than usual, because I lack the time to make it short." - Blaise Pascal

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

Obvious things first. Have you disabled the M103 compatibility fuse? That'll certainly cause the interrupt vectors to mis-behave if it's still set.

- Dean :twisted:

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

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

abcminiuser wrote:
Obvious things first. Have you disabled the M103 compatibility fuse? That'll certainly cause the interrupt vectors to mis-behave if it's still set.

- Dean :twisted:

After reading your reply I thought that it must be that fuse.. But output from avrdude is:

&>avrdude -c stk200 -p m128 -P /dev/parport0 -v

***clip***

avrdude: Device signature = 0x1e9702
avrdude: safemode: lfuse reads as CF
avrdude: safemode: hfuse reads as 9
avrdude: safemode: efuse reads as FF

***clip***

Regarding that efuse seems to be 11111111.
In M103 compatibility mode it should be 11111101, right?

-Mikko

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
int SRI(USART1_RX_vect){ 

Is this a typo (but I guess you did not type all that in)?

ISR(USART1_RX_vect){ 

would be correct.
/Lars

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

Lajon wrote:

int SRI(USART1_RX_vect){ 

Is this a typo (but I guess you did not type all that in)?

ISR(USART1_RX_vect){ 

would be correct.
/Lars

Yes, I would think so too but my compiler doesn't:

../uart.c:39: warning: return type defaults to ‘int’
../uart.c: In function ‘SRI’:
../uart.c:44: warning: control reaches end of non-void function

No idea where that comes from but changing that wont do any good either. I tried also to echo a single character by typing "echo "U" > /dev/ttyS0". It also hangs the whole avr. I also tried compiling (WinAVR 2007-05-25) in windows and avrdude did a good job with messing LFUSE bits even if I did not ask it to do so... For example a few second delay that I use in main changed to maybe 200 milliseconds etc.. I didn't bother to find out what caused it but I changed fuse bits to original and went back to Linux later on. Compiled with WinAVR's avr-gcc sending a char for usart still hung the AVR.

thanks anyway
Mikko

edit: And yes, I had misspelled ISR to SRI at some point... but still no go. Could it be that USART1_RX_vect is wrong interrupt vector afterall?

Last Edited: Wed. Oct 10, 2007 - 10:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you're getting those warnings, it means that you *are* trying to make the ISR with the code:

int SRI(...)

Your ISRs should be defined verbatim as:

ISR(...)

As the "ISR" is a macro which is defined in avr/interrupt.h and expanded out at compile time to all the right compiler hints. Try changing your code's "int SRI" to plain "ISR" and see if it will recompile. Remember to do a "make clean" between builds to ensure a fresh compile!

- Dean :twisted:

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

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

ok, now code looks like this:

int main (void)
{
   UCSR1B |= (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
   UCSR1C |= (1 << UCSZ0) | (1 << UCSZ1);

   UBRR1L = BAUD_PRESCALE;
   UBRR1H = (BAUD_PRESCALE >> 8); 
   DDRA |= 1<<PA6;
   sei();

   for (;;) // Loop forever
   {
   	delay(100);
   	PORTA ^= 1<<PA6;
   }
   return 0;
}

ISR(USART1_RX_vect){
	char ReceivedByte;
   ReceivedByte = UDR1;
   UDR1 = ReceivedByte;
}

Compiles without warnings. But it is not still working. There should not be bits and pieces of old code since using make clean.

- Mikko

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

So, it works if you do not enable the interrupts?

Does it work OK if you leave out the ISR()?

Can we see your delay()?

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

davef wrote:
So, it works if you do not enable the interrupts?

It wont of course echo back anything then. If I poll RXC bit in UCSR1A I can read from USART and send characters back.

davef wrote:

Does it work OK if you leave out the ISR()?

Does the same

davef wrote:

Can we see your delay()?

void delay(uint8_t t){
uint8_t foo;
for (foo = 0; foo < t; foo++) _delay_ms(20);
}

This should not be causing it because even if there is an empty for loop in the main (without delay or led blinking), there is still no echo.

-Mikko

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

Sorry, by "not working" I thought you meant the LEDs didn't blink anymore!

Moving right along . . .

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

davef wrote:
Sorry, by "not working" I thought you meant the LEDs didn't blink anymore!

Moving right along . . .

Well actually I said before that led stops blinking at the moment I send the byte to the Usart (when interrupt is enabled). I just tried with another mega128 but same problem exists, so I quess that I have to try some other compiler/version.

- Mikko

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

Hi,

Got it working in WinAVR without changing the source code. But I have still check into what the toolchain does wrong in Linux by disassembling the object files. Just in case someone else runs into same problem. Maybe I'll just change back to older versions on Linux.

Thanks for help

- Mikko

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

Hy all,

let me start by thanking everyone for the great tutorials and comments ! I'm a newbie to avr and this is the motherload for me :)

I'm trying to parse files line by line via USART, I've managed to get a CRLF terminated textfile bounce line by line in minicom when catting to /dev/modem... But I want to parse file line by line. I think I should parse 'm inside ISR(USART_RX_vect) but how to fill UDR line by line in stead of filling SRAM/FLASH (file sizes unknown)

I've also tried the "static FILE mystdio = FDEV_SETUP_STREAM(usart_putchar,usart_getchar,_FDEV_SETUP_RW);"
routines, but I'm not sure how to implement them with interrupt driven UART and I also loose chars when catting a file to /dev/modem ...

I hope this makes some sense :)

bye,
gert

#include 
#include 
#include 

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

// Global variables
unsigned short int ports, leds ;

// A delay routine
void delay(uint8_t t){
uint8_t foo;
for (foo = 0; foo < t; foo++) _delay_ms(10);
} 

int main (void)
{
   UCSRB |= (1 << RXEN) | (1 << TXEN);   
   UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); 

   UBRRL = BAUD_PRESCALE;
   UBRRH = (BAUD_PRESCALE >> 8);
   UCSRB |= (1 << RXCIE); 
   sei();

for (ports=0;ports<=7;ports++)
  {
  DDRD&=~_BV(ports);//set PORTD (button) pin{ports} to zero as input
  PORTD|=_BV(ports);//Enable pull up
  PORTB|=_BV(ports);//led {ports} OFF
  DDRB|=_BV(ports);//set PORTB (leds) led to zero as output
  }

   for (;;) // Loop forever
   {
         // RS232 communication is now handled by the ISR instead of in the main loop
	 // This frees up MCU to do other stuff in stead of waiting around for RX

     if (bit_is_clear(PIND, 0))//if button is pressed
	{
		PORTB&=~_BV(0);//led 0 ON
		loop_until_bit_is_set(PIND, 0);//LED ON while Button is pressd
		PORTB|=_BV(0);//led 0 OFF
	} else if (bit_is_clear(PIND, 7))
		{ PORTB&=~_BV(7);//led 7 ON
	          loop_until_bit_is_set(PIND, 7);//LED ON while Button is pressd
		  PORTB|=_BV(7);//led 7 OFF
		}
     else { 
             // blink blink
	     for (leds=0;leds<=7;leds++)
	    	{ delay(2) ;
		  PORTB&=~_BV(leds) ;
		  delay(2) ;
  		  PORTB|=_BV(leds) ;
		}		  
	  }
    }
  return 0 ;
}

ISR(USART_RX_vect)
{
   char DaTa;
   DaTa = UDR; 

   // Must find way to read line by line ...
   
   // pseudo code
   if (DaTa=='\0') { myline = DaTa_from_ringBufffer? ;
                     parse_myline();
                   }
   UDR = DaTa; 
}

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

What you need to do, is set up some buffers that are larger than the longest line you want to read in. You'd probably need two of them, one for reading in from the USART and one for processing (you'd "ping-pong" between them, to ensure you never lose bytes).

Your ISR would read in the UDR bytes and stuff them into the current write buffer, until a \n is reached. When the newline character is sent, you need to set a flag to indicate to the main program that the buffer is ready to be parsed, and start writing to the other buffer.

Your main program then has to wait for the "ready to be parsed" flag to be set on each buffer, whereupon it clears the flag and does the parsing.

- Dean :twisted:

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

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

i am working with atmega 8..what i have seen is the registers are the same as in case of atmega 16

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

Hey Dean,

thnx for the reply, I think I worked something out ...

abcminiuser wrote:
What you need to do, is set up some buffers that are larger than the longest line you want to read in. You'd probably need two of them, one for reading in from the USART and one for processing (you'd "ping-pong" between them, to ensure you never lose bytes).

Indeed, I think I'm not losing any ...

Quote:
Your ISR would read in the UDR bytes and stuff them into the current write buffer, until a \n is reached. When the newline character is sent, you need to set a flag to indicate to the main program that the buffer is ready to be parsed, and start writing to the other buffer.

Here's the ISR part now ...

// Read in USART and place in buffer for later usage ...
ISR(USART_RX_vect)
{
	uint8_t c ;
	c = UDR ;

	if (bit_is_clear(UCSRA, RXC))
	{ 
		rxbuff = c ;
		intflags.rx_int = 1 ;
	}
}

Quote:
Your main program then has to wait for the "ready to be parsed" flag to be set on each buffer, whereupon it clears the flag and does the parsing.

and here's the part that parses untill "\n" ... catting works fine

   for (;;) // Loop forever
   {
      if (intflags.rx_int)
        {
          intflags.rx_int = 0;
	  
	  p=string_buffer ;
	  
          if (rxbuff == '\r')
            {
	      *p=0; // terminate string
            }
	  else { 
		  if (i<10) // charbuffer size
			{ *p++=rxbuff ;
				i+=1 ;
			}
		  UDR = rxbuff ; // bounce

	  }
      }
  }   

Now I can read in line by line (if file is CRLF terminated at least); that leaves me with the part of parsing the strings, but while this parsing is going on, won't I risk loosing input from USART this way ? I'll figure this out when my parsing code is there I guess ...

bye,
Gert

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

Quote:

but while this parsing is going on, won't I risk loosing input from USART this way ?

Which is why I suggested two large buffers. You fill one in the ISR, then null-terminate it when you receive the newline character, and set a flag. Your main code then parses the line while the ISR switches to filling the other buffer while the parser runs on the first buffer. When the next line is ready you set another flag to tell the parser to work on the second buffer while you start filling the first again.

- Dean :twisted:

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

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

Hya Dean,

I understood what you meant the first time, but I don't to see how 2 buffers (or even 3 of 4 for what that matters) will be sufficient for ISR RX throttling.

The usart will receive approx. 200Kb (or more) data, which needs to be parsed and will trigger delays and high/low on several pins - if I use interrupts for these, will this temporarly block ISR UART, and will a "cat file > /dev/ttyS0" be able to handle this ? -

Won't a 2nd (or 3d, 4th etc.) buffer also loose chars if the parsing and following delays() & pin changes take quite long to finish ? Maybe I should call cli() when parsing a string ? Or use uart polling ?

I've also thought about storing entire usart input in PROGMEM and read from there, but that means restriction on file size. I've read many excellent docs about U(S)ART but implementation in these docs are focused on bouncing, uart<->uart or cmdline-interface... These I've got sorted 8)

However, I've only been doin' C and AVR for 1 month, so maybe I'm missing the point entirely :oops:

Thnx for yer time :)

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

I wouldn't have thought you'd have time to wait for the SPM operation of writing PROGMEM data to complete anyway. Wouldn't it be easier to add some buffer RAM to the AVR - maybe an SPI or I2C/TWI connected SRAM devices or, if it needs to be non-volatil, FRAM

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

Well, as long as your operations on a single line (buffer) are shorter than the time it takes to read in another line, you won't loose any characters - the ISR fills the opposite line buffer to the one being operated on.

A better way to do this would be to use a large ringbuffer (see the "AVR Experiments" page of my site for a code example) to store the characters. You'd also keep a counter for the number of *complete* lines stored in the buffer. The system would work like this:

volatile uint8_t TotalRecLines;
volatile RingBuffer_t RingBuff;

ISR(Byte Recieved)
{
   uint8_t RecByte = UDR;

   if (RecByte == '\n')
   {
      TotalRecLines++;
      RecByte = '\0';
   }

   StoreByte(&RingBuff, RecByte);
}

int main (void)
{
 // Usual setup code

 for (;;)
 {
    if (TotalRecLines) // Line waiting to be processed
    {
        // Process line, read in bytes from ringbuffer until \0 is reached
        TotalRecLines--;
    }
 }
}

That way, the ISR just has to keep feeding in bytes into the ringbuffer. When a complete line is read it increments the counter to tell the main program to start reading it back out of the buffer again and process it. While the processing is being done, the ISR can still add bytes to the ringbuffer, so no information is lost as long as the buffer is large enough.

- Dean :twisted:

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

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

Hy,

I'm not sure I quite understand how to use AdvRingBuffer, I understand what it does, but I struggle to get the data back out of the buffer. Should I read chars until '\0' and then strcpy to a string ?

// RingBuffer stuff
#include "RingBuff.h"
volatile uint8_t TotalRecLines;
volatile RingBuff_t RingBuff;

ISR(USART_RX_vect)
{
    uint8_t c ;
    c = UDR;
    if (c == '\r') {
	TotalRecLines++ ;
	c = '\0'; // Null terminate
    }
  Buffer_StoreElement(&RingBuff, c); // store in RingBuffer
}


void check_RS232(void)
{
    if (TotalRecLines) {
	uart_rxbuf[uart_rx_pos] = Buffer_GetElement(&RingBuff); // read chars from ringbuffer
	if (Buffer_GetElement(&RingBuff) == '\0' ) { // till '\0' encountered
		strcpy(buffer, uart_rxbuf);
		uart_rx_pos=0;
	} else {
		uart_rx_pos++;
		}
	TotalRecLines-- ;
	}
}

bye
djeez

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

Here's a quick example of what I was getting at:

// RingBuffer stuff
#include "RingBuff.h"
volatile uint8_t TotalRecLines;
volatile RingBuff_t RingBuff;

ISR(USART_RX_vect)
{
    char c = UDR;

	if (c != '\r')    // Ignore the \r in the standard \r\n sequence
		return;

	if (c == '\n')    // Reached the \n in the \r\n sequence
	{
		TotalRecLines++; // Indicate that an entire line is ready
		c = '\0'; // Null terminate
    }

	Buffer_StoreElement(&RingBuff, c); // Store next byte in RingBuffer
}


void check_RS232(void)
{
	char LineBuffer[100]; // Max line length is 100 bytes
	
    if (TotalRecLines) // Wait for a whole line to be buffered before reading it out
	{
		char c;
		uint8_t LineSize = 0;
	
		do
			LineBuffer[LineSize++] = Buffer_GetElement(&RingBuff);
		while ((c != '\0') && (LineSize != sizeof(LineBuffer)))
		
		if (LineSize == LineBuffer) // Line too long for buffer
			LineBuffer[sizeof(LineBuffer) - 1] = '\0'; // Terminate string
		
		TotalRecLines--;

		// LineBuffer now contains the next line from the USART - process it here
   }
}

Haven't even tried to compile it, but you should get the basic idea of what it's trying to do.

- Dean :twisted:

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

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

Hello, i was trying this Tutorial-code with ATmega32 and it wont work. I tried the code suggested in the datasheet and got some strange results:

if i am just sending stuff via:

void USART_transmit( unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) )
;
/* Put data into buffer, sends the data */
UDR = data;
}

i get all the chars on HyperTerminal, but my Problem is, i cant recieve any Characters. I use the same Init as given in the tutorial. Could i've missed something or maybe its a Problem with a RX part of the cable?

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

I'd wager it's a hardware problem. If you've tried the datasheet code also, and others have tested my code then your failure to receive characters is most likely an issue with your RX pin connection.

- Dean :twisted:

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

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

Yea, i tried another cable and its working now. Thanks for the great Tutorial, Dean.

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@infibit

Everything in this tutorial + everything in the ADC tutorial plus the use of the itoa() function in the C library.

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you using the internal RC oscillator? If so, is it calibrated? At the very least you should load the calibration value for 8Mhz in the OSCCAL register. The calibration for 1Mhz is loaded at reset so you could try running at 1Mhz also (lower the baud rate to 4800 or lower if you do). You can ignore all this if you have an external 8Mhz crystal.

The ADC questions are off-topic here but anyway:

Quote:
dint even connect anything to the ADC port and numbers just kept flowing in randomly.

What do you expect if you have nothing connected? The input will be floating and you will get some random values. Start with grounding the input and verify you get 0. Then try some voltage near the reference and verify you get a value close to 1023.
Have you connected a reference voltage at AREF btw? AREF is what you have selected as the reference by having the bits REFS1 and REFS0 both 0 in ADMUX.
/Lars

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi

Last Edited: Sun. Mar 2, 2008 - 03:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi

Last Edited: Sun. Mar 2, 2008 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I have configured the atmega8 now to 1mhz

Crystal or internal RC oscillator? If latter how are you calibrating it?

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But you haven't told us how you are calibrating it?

(to cut a long story short, if you want to use the UART get a crystal)

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

hi

Last Edited: Sun. Mar 2, 2008 - 03:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I dint even connect any device.
Again, I suggest you connect some known voltage to the ADC input.

Calibration or not depends, if you are using a reasonable baud rate and are just experimenting you may not need it. But this is still good advice for long term reliable communication:

Quote:
(to cut a long story short, if you want to use the UART get a crystal)
And since you already have a crystal why not just enable it.
/Lars

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

First of all, I really found this guide useful. Thanks!

I am using an ATMEGA8L AVR. I have switches connected to my PIND2 and PIND3, which are used for INT0 and INT1 respectively. With this interrupt-driven UART code enabled, I can get INT1 to work, but not INT0. However, if I comment out all the UART code, both INT0 and INT1 work fine. Is there something about this code that alters the functionality of INT0? If so, can someone explain it to me? I can post my code if needed, but I figured my question is probably general enough not to require the posting of my code (not that I mind posting it; I just want to avoid the clutter here).

Thanks. Just getting back into the AVR after a hiatus due to the completion of an I2C-accelerometer project :)

-Eric

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

Eric,

That is not a general issue so I think we need to see your code but it'd probably be most appropriate to start a new thread about it in AVR Forum.

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

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!

Why choose? Be there *and* be square!

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

nice tutorial

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

After I wrote my UART transmit by interrupt, I found this library by Pascal Stang:
http://www.mil.ufl.edu/~chrisarn...

I repeat the link here, because I think every AVR freak should know about it. There are many good functions there.

Actually, this link is the documentation:
http://www.mil.ufl.edu/~chrisarn...

Why choose? Be there *and* be square!

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

Note to self and others, GCC doesn't produce an error for a misspelled interrupt handle, it just gives you a warning.

Don't learn the hard way....

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

I'd suggest *always* using the -Werror command line switch. That indicates to GCC that all warnings should be treated like errors, preventing successful compilation.

I'm a firm believer that correct code should produce no warnings, and no errors. If code which triggers a warning is desired, then it should either be reworked or the warning suppressed through other means.

- Dean :twisted:

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

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

michael_R wrote:
Note to self and others, GCC doesn't produce an error for a misspelled interrupt handle, it just gives you a warning.

The implication of that is that you just ignore the warnings? If there's a lesson to be learned it is never ignore the warnings. In fact strive to get code compiling with no warnings at all and even so that it is split/lint-able. As Dean says -Werror is a good idea.

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

Thanks a ton for the guides on USART, I'm now able to successfully talk to myself through my microcontroller, a new low! :D

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

Good morning

It seems my interrupt is firing on its own (after about 20 seconds from MCU start up) without any data being sent to it (there physically are no wires connecting to the Rx pin!)

ISR(USART0_RX_vect) {
// code
} // ISR USART0

Is there a timeout or some other function that would fire the interrupt even if there is no data being sent to it?

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

I am using modem in my project to send an sms depending of some conditions. The sending of sms is not urgent ie. sms is not supposed to be fired instantly. Now my question is which way is good one to use - polled or interrupt for interfacing modem.

Moreover, is there any limitation on number of interrupts that we can use.

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

If it's not urgent, don't use interrupts (which should be used for time-critical events). There's no code limitation on the number of interrupts, but keep in mind that each one requires cycles to process -- to many happening simultaneously and you'll start to miss some or have them severely delayed.

- Dean :twisted:

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

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

Trying the (excellent!) tutorial here I see something I don't understand. I modified the final code slightly:

//includes...

static void uart_putchar(char c) {
    loop_until_bit_is_set(UCSRA, UDRE);
    UDR = c;
}

int main(void) {
    //...init usart for the corresponding avr

    UCSRB |= (1 << RXCIE);
    sei();
    
    uart_putchar('p'); //so I just print a character here

    for (;;); // Loop forever

    return 0;
}

ISR(USART_RX_vect) {
    char ReceivedByte;
    ReceivedByte = UDR;
    UDR = ReceivedByte;
}

I load the binary to my attiny2313, go to my terminal program and surely see a

p

sitting there (I just printed it there, right). I press the comma (',') key of my keyboard and as expected the avr starts bouncing commas back to me. But the whole output actually looks like this:

p,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,p,,,,,,,
,,,,p,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,p,,,
,,,,,,,,,,,,,,,,,,,,,p,,,,,,,,,,,,,,p,,,
,,,,p,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

which tells me that somehow the main routine gets re-executed or reset or something... And seems to be pretty undeterministic too - I could have any number of commas between the 'p's. I read wathcdog timers can reset your avr (so the main() starts over), but I don't have that fuse set. As far as I know in C, the main() can be executed only once (unless you do some sort of recursion may be?). Tried putting something more meaningful in the for loop (in my case flipping a pin between 0 and 1) but that didn't change things much. The only other possibility is that the interrupt causes the main program reset but haven't seen that mentioned as an option either (and frankly it would be a bit disturbing). So what am I missing?

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

Hi Dean,

Nice tutorial. I'm new to AVRs and serial programming but it's a lot of fun ;-)

I went through this tutorial and the basic one about serial communications. I have changed the code just to test and to make sure the that it is really the AVR talking to me through the serial port. Basically I wanted it to send back a 'x' with echoed character I send to the AVR.

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
   while ((UCSRA & (1 << UDRE)) == 0) {}; 
      UDR = 'x'; 
}

What I get back is very weird though. At times it works fine and sometimes I get an 'a' back when I send an 'A' and sometimes I will get an '|' back instead of a 'x'. For example every second 'A' I send will return as 'a|' instead of 'Ax'. What's even stranger is that only 'A's will return in lower case. All other characters are echoed in the same case. Sometimes it works fine so results are very spontaneous and I can't pick up a pattern.

I use a Atmega8 and Minicom in linux (i've even tested it with my own C code on linux and with Bray's Terminal in windows, same result). I hooked up and external crystal clocking at 7.3728MHz

Is it caused by the extra code I have added? Like I said, that code is not needed, I'm just using for testing purposes.

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

pepper_bg:

That's very odd behavior. Is that the only code running in your system? Does it appear to reset by itself (when you don't try to send characters) or only after you're sending data to it?

kakasi:

Spinloops in ISRs are usually a very bad idea - you run the risk of delaying too far and missing other interrupts. That said, if that's your only ISR you should be fine with low data rates.

I'd suspect that its either an issue with noise on the line or (more likely) a slight baud mismatch. What are you using for your AVR's clock source? If it's the default internal RC oscillator, you'll have problems as it's too low tolerance for reliable communications.

- Dean :twisted:

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

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

I'm using the external crystal as the clock source. Both the PC's port and the AVR is set up for 9600 bps...is it possible that crystal is unstable?

Thanks for the info...there is a possibility of noise, coz i built the circuit on a breadboard, right?

:roll:

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

Noise is *always* a possibility ;).

How certain are you that the external crystal is being used? Plenty of people attach the crystal and blindly assume it's the AVR's clock source, but never change the AVRs fuses. My apologies if I'm going over things you already know, but it's a common trip-point for newbies.

The crystal might be unstable if the breadboard is giving it too much capacitance. However that voodoo-electronics is not my area, and you'd really need an oscilloscope to check it easily.

I'd rule out the cable first, as bad (or too long) cables can garble data more easily than you'd think.

- Dean :twisted:

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

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

hehe, no problem. it's definitely using the external clock...I had a flashing LED app running on the mega8, and right after connecting the crystal and burning the fuses, it started to flash much faster. That was easily fixed by specifying the new clock speed (#define F_CPU 7372800UL) ;-)

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

OK, i have taken out the code that send the 'x', so I obviously don't get the random '|' back from the AVR anymore. But, I still have a problem with the 'A'...sometimes it echoes 'A' back and sometimes 'a' when you send 'A'.

I went through all the keys on my keyboard, and it gets even weirder. When I send a 'P' or 'p' it returns a 'X' or 'x' and sometimes it returns the correct results.

I doubt if it is noise, because it ONLY happens to these characters.

Is this happening to anyone else?

I don't know why it only happens to these chars but this is interesting:
P - 101 0000
X - 101 1000

p - 111 0000
x - 111 1000

A - 100 0001
a - 110 0001
...there's only one bit chat changes between the pairs.

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

It seem to be working now...I have changed the baud rate to 19200 and no more funny results echoed back the the PC :D

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

..just some feedback...
I have moved all the components to my "production" pc board, and I also used another crystal (same specs as the one I used on my breadboard). I changed the baud rate back to the original 9600bps and everything is working as it should.

I think that either the crystal I used was faulty, or there is less noise or less capacitance on the pcboard. Unfortunately I am not a guru in electronics so I'm not sure exactly what caused the strange behavior on the breadboard. ;-)

Thanks for the assistance Dean!

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

good tutoril!

i'm planning to implement rs485 network for my application,where i may have a PC and several mcu units and i think one more tutorial on multi-processor communication would be helpful to some me and someone out there!

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

Did anyone solve that 'USART_RXC_vect' problem? I'm using the latest WinAVR with ATmega640 and getting the same error . . . Does it have anything to do with the fact I have four UARTs?

I've tried every permutation of it:
USART_RXC_vect
UART_RXC_vect
USART_RX_vect
UART_RX_vect
USART1_RXC_vect
UART1_RXC_vect
USART1_RX_vect
UART1_RX_vect
and more . . .

Interestingly, all of them give me the 'misspelled' error except this one:
USART1_RX_vect

Which gives me this error:
Loaded plugin STK500
Loaded plugin AVR GCC
Loaded partfile: C:\Program Files\Atmel\AVR Tools\PartDescriptionFiles\ATmega640.xml
gcc plug-in: Error: Object file not found on expected location C:\My_Robots\Axon\Axon.elf
Make sure your makefile specifies the output .elf file as Axon.elf

How do YOU make a robot?
http://www.societyofrobots.com

Last Edited: Mon. Aug 4, 2008 - 04:59 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looking at the part header files, "USARTn_RX_vect" is the correct vector name, where "n" is 0 to 3 inclusive.

That error indicates other build problems (as the binaries weren't produced). Run a "make clean" and then a "make all", and post the compiler output.

- Dean :twisted:

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

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

You could always simply give in on the "guessing game" and read the manual:

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

The mega640 is listed (for RX vectors) against:

USART0_RX_vect
USART1_RX_vect
USART2_RX_vect
USART3_RX_vect

So it's no surprise that USART1_RX_vect "half worked" for you. As to the rest of the error, it's probably a link error in the build so switch back to the build tab to see what that was.

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

Does anyone have any code for receiving a string of characters (15 bytes in specific). Each string begins with 0x41 and ends with 0x0A. I am using interrupt driven receive. I have my code working where I can get the first character stored in my receive[0] array, but I cannot seem to figure out how to collect the other 14 bytes in the transmission and put them in receive[1]-receive[14]. Any help would be great. Also thanks for the tutorials and the informative posts; very helpful to people who are new and stuck!

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

I am using USART_RXC interrupt, when when an '1' arrives to the UDR it's saves in a register and then return to the cycle loop where It's compared where if its 0, sending zeros to the port c, if it's 1, go will to the label start and starts the adc, when the conversion ends interrupt and go to ISR end_conversion, and returns to where the flag ADIF is polls so if the UDR comes a new date of information it receives in the ISR of RXC is executed but fails to return to the cycle of comparison but again the cycle of poll flag ADIF, Which I can do to solve this?

This is a my code

.cseg
.include "m8535def.inc"

.EQU fq=4000000 ; Xtal frequency
.EQU baud=9600 ; Baudrate
.EQU bdpresc=(fq/(16*baud))-1 ; Baud-Divider

.DEF c=R30 ; char.

;VECTOR DE INTERRUPCIONES****************************************************

.ORG 0x0000
rjmp RESET
rjmp EXT_INT0
rjmp EXT_INT1
rjmp TIM2_COMP
rjmp TIM2_OVF
rjmp TIM1_CAPT
rjmp TIM1_COMPA
rjmp TIM1_COMPB
rjmp TIM1_OVF
rjmp TIM0_OVF
rjmp SPI_STC
rjmp UART_RXC
rjmp UART_UDRE
rjmp UART_TXC
rjmp fin_de_conv; interrupt end of conversion
rjmp EE_RDY
rjmp ANA_COMP

EXT_INT0: reti
EXT_INT1: reti
TIM2_COMP: reti
TIM2_OVF: reti
TIM1_CAPT: reti
TIM1_COMPA: reti
TIM1_COMPB: reti
TIM1_OVF: reti
TIM0_OVF: reti
SPI_STC: reti
UART_UDRE: reti
UART_TXC: reti
EE_RDY : reti
ANA_COMP: reti

UART_RXC:

in c, udr

OUT UDR, c

reti

fin_de_conv:

cbi adcsra, adie

in r18, adch

out portc, r18

reti

Reset:

ldi r26, low (RAMEND)
out spl, r26
ldi r26, high (RAMEND)
out sph, r26

ldi r26, 0xff ; port c outputs
Out ddrc, r26

ldi r26, 0x00 ; Port a inputs
out ddra, r26

;Configuración USART *****************************************************

ldi r20, HIGH (bdpresc)
out UBRRH, r20
ldi r21, LOW (bdpresc)
out UBRRL, R21

ldi r16, 0b10011000 ; RXCIE, RX y Tx
out UCSRB, r16

ldi r16, 0b10000110 ;
out UCSRC, r16

;Configuración ADC *******************************************************

ldi r26, 0b01111100 ; Aref = vcc, adlar=1, adc4+, adc2-
out admux, r26

ldi r26, 0b10100101 ; prescaler = 32
out adcsra, r26

sei

loop:

Ldi r22, '1'
cpse c, r22
rjmp stop
rjmp start

stop:
cbi adcsra, adie
clr r17
out portc, r17
rjmp loop

start:

sbi adcsra, adsc

sbi adcsra, adie
fincon:

sbis adcsra, adif
rjmp fincon

rjmp loop

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

how i can avoid buffer overrun?? i try to send data full duplex (continues both from AVR to PC), but after 3-4 minutes my avr stop communication, because data overrun? any suggestion about using timeout when receive data (interrupt AVR - UART RX)?

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

Well you either have to consume the data at a faster rate than it arrives or slow the rate at which it is arriving.

If you are currently polling the received data then implenting an Rx-interrupt may help things.

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

Dean,

So, now lets say we've gotten advanced and have our UART code working nicely. How does one go about making a clean interface for handiling the transmission of multiple data streams?

Quote:

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.

From what I understand, we create a transmission buffer in which the main loop will place data in. Then, when it is ready, the program sends the data in the transmit buffer by successively printing each character.

When I try to do this, I have issues, such as one transmission being overwritten by another, etc. Could you point out some ways to fix this problem? Would it be wise to use flags? Perhaps some kind of flag to prevent the UART from printing more data until the latest data has finished being sent? Your help is much appreciated.

Diode Dan

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

You need two ring buffers - one for reception and one for transmission. When transmitting, before adding the next byte to the buffer you need to spinloop until space is available. The TX USART interrupt then fetches the next byte out of the buffer when it is available and puts it into the UDR register to send it.

You need to trigger the start of the transmission - otherwise, the TX USART interrupt will not fire for the first time and nothing will happen.

I suggest you download my MyUSB project (http://www.fourwalledcubicle.com...) and take a look at the "USBtoSerial" demo in the demos folder; you can ignore all the USB code and just focus on the buffering and serial transmission/reception. It implements the proper way to make buffered USART communications.

- Dean :twisted:

PS: Please excuse any incoherency in the above due to my slight inebriation. If something is unclear ask again - in an hour or two.

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

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

Personally I've often found it sufficient to just use interrupts and a ring buffer for Rx then do the Tx sychronously

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

Great tutorial, thanks! I implemented in the 90S8515, cannot wait to program it into STK500, I need to get a USB to RS232, first,

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

the code in the begining of this tutorial without the interruptions worked on my atmega16, but the one with the interruptions seems to be sending random numbers.
I dont know why...

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

I can not complie the simple code that is placed in this tutorials.

can anyone tell me what is wrong.

#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 << RXCIE); // 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) //SIG_USART_RECV
{ //linie 25
   char ReceivedByte; 
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
   UDR = ReceivedByte; // Echo back the received byte back to the computer 


}

warnings in studio 4

../interupt6.c:25: warning: return type defaults to `int'
../interupt6.c: In function `ISR':
../interupt6.c:25: warning: type of "USART_RXC_vect" defaults to "int"
../interupt6.c:31: warning: control reaches end of non-void function

[/b][b]

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

Looks like your version of avr-libc is out of date. What version of WinAVR do you have installed? If it's not the latest version from the WinAVR website, you need to update.

- Dean :twisted:

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

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

I have version AVR Studio 4.14.589, but I really dont know about the avr-libc.
Will it not be updated when the studio is updated???

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

Quote:

Will it not be updated when the studio is updated???

No. AVR Studio is something separate from the avr-gcc/avrlibc toolchain. The latter is easily updated on a Windows system by installing/upgrading WinAVR.

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:
but I really dont know about the avr-libc.
Will it not be updated when the studio is updated???

No, it gets updated when you manually download and install the latest WinAVR (which is 20080610 at present):

http://sourceforge.net/projects/...

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

yeeeeeeeeees......your guys are the best...thanks

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

now I allmost got it.

I cant figure out what to do with the

void check_RS232(void)

I know the name should not be Buffer_GetElement. but what should it be. see my code below. and what is the error releated to.??

compiler errors and warnings
Build started 5.11.2008 at 15:49:54
../ring1.c: In function 'check_RS232':
../ring1.c:112: warning: implicit declaration of function 'Buffer_GetElement'
../ring1.c:115: error: expected ';' before 'if'
make: *** [ring1.o] Error 1
Build failed with 1 errors and 1 warnings...

/*
                  Simple Ringbuffer Library
                  -------------------------
						  (c) Dean Camera, 2005
						-------------------------
						 dean_camera@hotmail.com

          
 This library allows you to implement a ringbuffer into your code
 (useful for buffering FIFO data while the processor is busy)
 via easy-to-use functions.
 
 By changing the typedefs in RingBuff.h, you can change both the
 datatype stored and the size of the buffer.
 
 An error variable is exposed via extern to your program; if the
 buffer is full when you try to store data bit 1 of the error
 variable is set, and if you try to read an empty buffer bit 0 is
 set. Both bits are cleared after a sucessful data store or read.
 The error masks are avaliable via the defines BUFF_ERR_OVERFLOW
 and BUFF_ERR_EMPTY.

 Before it can be used, you must execute the "InitialiseBuffer"
 routine. To store data, use the "StoreBuffByte" routine and for
 reading data you use the "StoreBuffByte" routine.
 
 The extern BuffElements variable holds the number of elements
 in the buffer. This can be polled to check if the buffer is
 empty or not.
 
 The macro "ClearBuffError()" is defined in the RingBuff.h file
 so you can clear the error variable manually if you wish.
 
                [{ Feedback Appreciated }]
*/

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


// Includes:
#include 
#include "RingBuff.h"
#include 

// Global Variables:
volatile BuffType       *StoreLoc;
volatile BuffType       *RetrieveLoc;
volatile BuffType       RingBuffer[BuffLen];
volatile ElemType       BuffElements;
volatile unsigned char BuffError;


volatile uint8_t TotalRecLines; 


int main (void) 
{ 

  BUFF_InitialiseBuffer();


   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 << RXCIE); // 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) //SIG_USART_RECV
{ 
   char c;
    
   c = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
   //UDR = c; // Echo back the received byte back to the computer 
	
	if (c != '\r')    // Ignore the \r in the standard \r\n sequence 
      return; 

   if (c == '\n')    // Reached the \n in the \r\n sequence 
   { 
      TotalRecLines++; // Indicate that an entire line is ready 
      c = '\0'; // Null terminate 
    } 
	
	if (c>1)
	{
	BUFF_StoreBuffByte(c);
	}
}


void check_RS232(void) 
{ 
   char LineBuffer[100]; // Max line length is 100 bytes 
    
    if (TotalRecLines) // Wait for a whole line to be buffered before reading it out 
   { 
      char c; 
      uint8_t LineSize = 0; 
    
      do 
         LineBuffer[LineSize++] = Buffer_GetElement(&RingBuffer); 
      while ((c != '\0') && (LineSize != sizeof(LineBuffer))) 
       
      if (LineSize == LineBuffer) // Line too long//linie 115 for buffer 
         LineBuffer[sizeof(LineBuffer) - 1] = '\0'; // Terminate string 
       
      TotalRecLines--; 

      // LineBuffer now contains the next line from the USART - process it here 
   } 
} 




// Routines:
void BUFF_InitialiseBuffer(void)
{
	StoreLoc    = (BuffType*)&RingBuffer; // Set up the IN pointer to the start of the buffer
	RetrieveLoc = (BuffType*)&RingBuffer; // Set up the OUT pointer to the start of the buffer

	BuffElements = 0;           // Reset the buffer elements counter
}





void BUFF_StoreBuffByte(BuffType DataToStore)
{
	if(BuffElements == BuffLen) // Buffer full
	{
		BuffError |= BUFF_ERR_OVERFLOW;   // Set the "buffer full" error flag
		return;
	}
	else                       // Sucessfull operation
	{
		BuffError = 0;          // Clear the error variable
	}
		
	*StoreLoc = DataToStore;   // Store the data

	StoreLoc++;                // Increment the IN pointer to the next element
	BuffElements++;            // Increment the total elements variable

	if (StoreLoc == (BuffType*)&RingBuffer[BuffLen])
		StoreLoc = (BuffType*)&RingBuffer; // Wrap pointer if end of array reached
}	



BuffType BUFF_GetBuffByte(uint8_t Pop)
{
	if(!(BuffElements))        // No elements in the buffer
	{
		BuffError |=  BUFF_ERR_EMPTY;       // Set the "buffer empty" error flag
		return 0;
	}
	else                      // Sucessfull operation
	{
		BuffError = 0;         // Clear the error variable
	}

	BuffType RetrievedData = *RetrieveLoc; // Grab the stored byte into a temp variable

	if (Pop)
	{
		RetrieveLoc++;   // Increment the OUT pointer to the next element if flag set
		BuffElements--;  // Decrement the total elements variable
	}
	
	if (RetrieveLoc == (BuffType*)&RingBuffer[BuffLen])
		RetrieveLoc = (BuffType*)&RingBuffer; // Wrap pointer if end of array reached
		
	return RetrievedData;    // Return the retrieved data
}
[/code:1][code:1]
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I mean how do I read out from

BuffType BUFF_GetBuffByte(uint8_t Pop)

rutine......I dont get it

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

hallo all

where to finde

#include 

to use for the adv ring buffer???

BR

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

Try:

#include 

as described in the user manual:

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

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

Hi, I'm just a noob using AVR.. From what i know ISR do not allow any argument to be pass and do not return anything. How do you normally pass data receive by USART interrupt to be read by another function? I tried using structure but no luck.. Thanks in advance.

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

Well here's a mad, wild, whacky, off-the-wall idea - why not try reading this thread?

Did the "ReceivedByte" Dean uses not ring any bells as a mechanism for returning a value from an ISR (basically write something 'global' in the ISR, read it in the main() loop)?

The extension of this is then a ring buffer where rather than just ReceiveByte you keep a whole array and separate Write and Read pointers to it.

Cliff

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

Quote:

I tried using structure but no luck..

Did you declare the struct volatile? If not then read FAQ#1 in Cliff's footer above, and then move on to the avr-libc FAQ proper to read the explanation (also item #1).

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:

and then move on to the avr-libc FAQ proper to read the explanation (also item #1).

The quick route there is to click on my signature.

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

Hallo there. This was a great tutorial, and I had a great use of it.
But now I've made a communication, which behaves really strange. This is what I mean:
I have Atmega32 with 16MHz external crystal(I have set the fuse on the bottom of the list, i can't remember its name). I want to communicate with 9600bps and it should be interrupt driven.
I use a simple way of communication. I send a character from PC, use the Rx ISR to handle it, and send back a character('!' in my case) by Tx ISR.
I use MATLAB in my PC to connect to the MCU. There I have a loop which is waiting for the '!' and when it receives it I send another character.
This is a breaf description of my idea.
Now the problem. The communication starts, but after I send some characters (1,2,3 different all the time) the communication hangs up. Matlab says 'A Timeout occured...'. The MCU goes on working properly though.

Can the problem be caused by the errors in the baud rates? I placed the code on an ATMEGA16 board with 7.3728MHz and it is working perfect, no timeouts.

This is the code, but the comments are not written in an english language:):

#include "avr/io.h"
#include "avr/interrupt.h"
#include "avr/eeprom.h"

//1. Inicializaciq na EEPROM
#define EEMEM __attribute__((section(".eeprom")))

unsigned char symbols[159][5] EEMEM=
{0x00,0x00,0x00,0x00,0x00, // sp sh indeks 0
0x00,0x30,0x7d,0x30,0x00, // ! sh 1
0x00,0x70,0x00,0x70,0x00, // " sh 2
0x14,0x7f,0x14,0x7f,0x14, // # sh 3
0x12,0x2a,0x7f,0x2a,0x24, // $ sh 4
0x62,0x64,0x08,0x13,0x23, // % sh 5
0x36,0x49,0x55,0x22,0x05, // & sh 6
0x00,0x50,0x60,0x00,0x00, // ' sh 7
0x00,0x1c,0x22,0x41,0x00, // ( sh 8
0x00,0x41,0x22,0x1c,0x00, // ) sh 9
0x14,0x08,0x3e,0x08,0x14, // * sh 10
0x08,0x08,0x3e,0x08,0x08, // + sh 11
0x00,0x05,0x06,0x00,0x00, // , sh 12
0x04,0x04,0x04,0x04,0x04, // - sh 13
0x00,0x00,0x03,0x00,0x00, // . sh 14
0x02,0x04,0x08,0x10,0x20, // / sh 15
0x3e,0x45,0x49,0x51,0x3e, // 0 sh 16
0x00,0x21,0x7f,0x01,0x00, // 1 sh 17
0x21,0x43,0x45,0x49,0x31, // 2 sh 18
0x42,0x42,0x51,0x69,0x46, // 3 sh 19
0x0c,0x14,0x24,0x7f,0x04, // 4 sh 20
0x72,0x51,0x51,0x51,0x4e, // 5 sh 21
0x1e,0x29,0x49,0x49,0x06, // 6 sh 22
0x40,0x47,0x48,0x50,0x60, // 7 sh 23
0x36,0x49,0x49,0x49,0x36, // 8 sh 24
0x30,0x49,0x49,0x4a,0x3c, // 9 sh 25
0x00,0x36,0x36,0x00,0x00, // : sh 26
0x00,0x35,0x36,0x00,0x00, // ; sh 27
0x08,0x14,0x22,0x41,0x00, // < sh 28
0x14,0x14,0x14,0x14,0x14, // = sh 29
0x00,0x41,0x22,0x14,0x08, // > sh 30
0x20,0x40,0x45,0x48,0x30, // ? sh 31
0x26,0x49,0x4f,0x41,0x3e, // @ sh 32
0x3f,0x44,0x44,0x44,0x3f, // A sh 33
0x7f,0x49,0x49,0x49,0x36, // B sh 34
0x3e,0x41,0x41,0x41,0x22, // C sh 35
0x7f,0x41,0x41,0x22,0x1c, // D sh 36
0x7f,0x49,0x49,0x49,0x41, // E sh 37
0x7f,0x48,0x48,0x48,0x40, // F sh 38
0x3e,0x41,0x49,0x49,0x2f, // G sh 39
0x7f,0x08,0x08,0x08,0x7f, // H sh 40
0x00,0x41,0x7f,0x41,0x00, // I sh 41
0x02,0x01,0x41,0x7e,0x40, // J sh 42
0x7f,0x08,0x14,0x22,0x41, // K sh 43
0x7f,0x01,0x01,0x01,0x01, // L sh 44
0x7f,0x20,0x18,0x20,0x7f, // M sh 45
0x7f,0x10,0x08,0x04,0x7f, // N sh 46
0x3e,0x41,0x41,0x41,0x3e, // O sh 47
0x7f,0x48,0x48,0x48,0x30, // P sh 48
0x3e,0x41,0x45,0x41,0x3e, // Q sh 49
0x7f,0x48,0x4c,0x4a,0x31, // R sh 50
0x31,0x49,0x49,0x49,0x46, // S sh 51
0x40,0x40,0x7f,0x40,0x40, // T sh 52
0x7f,0x01,0x01,0x01,0x7f, // U sh 53
0x7c,0x02,0x01,0x02,0x7c, // V sh 54
0x7f,0x01,0x0e,0x01,0x7f, // W sh 55
0x63,0x14,0x08,0x14,0x63, // X sh 56
0x70,0x08,0x70,0x08,0x70, // Y sh 57
0x43,0x45,0x49,0x51,0x61, // Z sh 58
0x00,0x7f,0x41,0x41,0x00, // [ ok 59
0x20,0x10,0x08,0x04,0x02, // \ ok 60
0x00,0x41,0x41,0x7f,0x00, // ] sh 61
0x10,0x20,0x40,0x20,0x10, // ` sh 62
0x01,0x01,0x01,0x01,0x01, // _ sh 63
0x00,0x40,0x20,0x10,0x00, // ` sh 64
0x02,0x15,0x15,0x15,0x0f, // a sh 65
0x7f,0x09,0x11,0x11,0x0e, // b sh 66
0x0e,0x11,0x11,0x11,0x02, // c sh 67
0x0e,0x11,0x11,0x09,0x7f, // d sh 68
0x0e,0x15,0x15,0x15,0x0c, // e sh 69
0x08,0x3f,0x48,0x40,0x20, // f sh 70
0x18,0x25,0x25,0x25,0x3e, // g sh 71
0x7f,0x08,0x10,0x10,0x0f, // h sh 72
0x00,0x11,0x5f,0x01,0x00, // i sh 73
0x02,0x01,0x11,0x5e,0x00, // j sh 74
0x7f,0x04,0x0a,0x11,0x00, // k sh 75
0x00,0x41,0x7f,0x01,0x00, // l sh 76
0x1f,0x10,0x0C,0x10,0x0f, // m sh 77
0x1f,0x08,0x10,0x10,0x0f, // n sh 78
0x0e,0x11,0x11,0x11,0x0e, // o sh 79
0x1f,0x14,0x14,0x14,0x08, // p sh 80
0x08,0x14,0x14,0x0c,0x1f, // q sh 81
0x1f,0x08,0x10,0x10,0x08, // r sh 82
0x09,0x15,0x15,0x15,0x02, // s sh 83
0x10,0x7f,0x11,0x01,0x02, // t sh 84
0x1e,0x01,0x01,0x02,0x1f, // u sh 85
0x1c,0x02,0x01,0x02,0x1c, // v sh 86
0x1e,0x01,0x06,0x01,0x1e, // w sh 87
0x11,0x0a,0x04,0x0a,0x11, // x sh 88
0x18,0x05,0x05,0x05,0x1e, // y sh 89
0x11,0x13,0x15,0x19,0x11, // z sh 90
0x00,0x08,0x36,0x41,0x00, // { sh 91
0x00,0x00,0x7f,0x00,0x00, // | sh 92
0x00,0x41,0x36,0x08,0x00, // } sh 93
0x20,0x40,0x20,0x10,0x20, // ~ sh index 94
//Kirilica Glavni
0x3f,0x44,0x44,0x44,0x3f,// A sh index 95
0x7f,0x49,0x49,0x49,0x06,// Á sh 96
0x7f,0x49,0x49,0x49,0x36,// Â sh 97
0x7f,0x40,0x40,0x40,0x40,// Ã sh 98
0x03,0x7f,0x42,0x42,0x7f,// Ä sh 99
0x7f,0x49,0x49,0x49,0x41,// E sh 100
0x63,0x14,0x7f,0x14,0x63,// Æ sh 101
0x42,0x41,0x51,0x69,0x46,// Ç sh 102
0x7f,0x04,0x08,0x10,0x7f,// È sh 103
0x7f,0x04,0x48,0x10,0x7f,// É sh 104
0x7f,0x08,0x14,0x22,0x41,// Ê sh 105
0x1f,0x20,0x40,0x20,0x1f,// Ë sh 106
0x7f,0x20,0x18,0x20,0x7f,// M sh 107
0x7f,0x08,0x08,0x08,0x7f,// H sh 108
0x3e,0x41,0x41,0x41,0x3e,// O sh 109
0x7f,0x40,0x40,0x40,0x7f,// Ï sh 110
0x7f,0x48,0x48,0x48,0x30,// Ð sh 111
0x3e,0x41,0x41,0x41,0x22,// Ñ sh 112
0x40,0x40,0x7f,0x40,0x40,// T sh 113
0x7f,0x09,0x09,0x09,0x7f,// Ó sh 114
0x1c,0x14,0x7f,0x14,0x1c,// Ô sh 115
0x63,0x14,0x08,0x14,0x63,// X sh 116
0x7f,0x02,0x02,0x7f,0x03,// Ö sh 117
0x78,0x08,0x08,0x08,0x7f,// × sh 118
0x7f,0x01,0x7f,0x01,0x7f,// Ø sh 119
0x7e,0x02,0x7e,0x02,0x7f,// Ù sh 120
0x40,0x7f,0x11,0x11,0x0e,// Ú sh 121
0x7f,0x11,0x11,0x0e,0x7f,// û sh 122
0x7f,0x11,0x11,0x11,0x0e,// Ü sh 123
0x22,0x41,0x49,0x49,0x3e,// Ý sh 124
0x7f,0x08,0x3e,0x41,0x3e,// Þ sh 125
0x39,0x46,0x44,0x44,0x7f,// ß sh 126

//Kirilica malki
0x02,0x15,0x15,0x15,0x0f,// a sh 127
0x66,0x59,0x49,0x49,0x46,// á sh 128
0x3e,0x49,0x49,0x39,0x06,// â sh 129
0x02,0x15,0x15,0x15,0x09,// ã sh 130
0x26,0x49,0x49,0x49,0x3e,// ä sh 131
0x0e,0x15,0x15,0x15,0x0c,// å sh 132
0x1b,0x04,0x1f,0x04,0x1b,// æ sh 133
0x11,0x15,0x15,0x15,0x0a,// ç sh 134
0x1e,0x01,0x01,0x02,0x1f,// è sh 135
0x1e,0x41,0x21,0x41,0x1f,// é sh 136
0x1f,0x04,0x0a,0x11,0x00,// ê sh 137
0x01,0x1e,0x10,0x10,0x1f,// ë sh 138
0x0f,0x10,0x0c,0x10,0x0f,// ì sh 139
0x1f,0x04,0x04,0x04,0x1f,// í sh 140
0x0e,0x11,0x11,0x11,0x0e,// î sh 141
0x1f,0x08,0x10,0x10,0x0f,// ï sh 142
0x1f,0x14,0x14,0x14,0x08,// ð sh 143
0x0e,0x11,0x11,0x11,0x02,// ñ sh 144
0x10,0x10,0x1f,0x10,0x10,// ò sh 145
0x18,0x05,0x05,0x05,0x1e,// ó sh 146
0x0c,0x12,0x7f,0x12,0x0c,// ô sh 147
0x11,0x0a,0x04,0x0a,0x11,// õ sh 148
0x1c,0x02,0x02,0x1c,0x03,// ö sh 149
0x1c,0x02,0x02,0x04,0x1f,// ÷ sh 150
0x1e,0x01,0x1f,0x01,0x1f,// ø sh 151
0x1c,0x02,0x1e,0x02,0x1f,// ù sh 152
0x10,0x1f,0x05,0x05,0x02,// ú sh 153
0x1f,0x05,0x05,0x02,0x1f,// û sh 154
0x1f,0x05,0x05,0x02,0x00,// ü sh 155
0x02,0x11,0x15,0x15,0x0e,// ý sh 156
0x1f,0x04,0x0e,0x11,0x0e,// þ sh 157
0x09,0x16,0x14,0x1f,0x00// ÿ sh index 158
};

#define CLOCK 0x35//zadavam clock kam hc595
#define SERIAL 0x05//zadavam vreme za podavane na serien signal kam hc595
#define PWM 0x05//tazi stoinost otgovarq na vremeto v koeto 6te sveti 1 led.
#define SPEED 0x0000a000//opredelq skorostta na dvigenie. Za iz4islqvane na velocity
#define STAND 0x00100000//opredelq vremeto na nepodvigno sastoqnie na nadpisa

#define ROWS_passed 0x30//tova e broqt na redovete, koito trbva da se sledi a da se obnovi ekrana s nepodvigno saob6tenie

//RAZMERI NA SAOB6TENIETO KOETO SAHRANQVAM V MCU
#define ROW 0x0a//saob6tenie ot 10 reda
#define COL 0x19//25 bukvi na red

//Upravlenie na 74hc595 i portovete
unsigned char clocks=0x00;//broi kolko clock-a sa pusnati kam clock vhodovete na hc595
unsigned char write=0x00;//sledi dvigenieto na impulsa podaden kam hc595, koito obhogda kolonite na ekrana
unsigned char next595=0x00;//pokazva koga nastapva prehoda megdu dva sasedni hc595
unsigned char light_on=0x00;//pokazva koga trqbva da pusnem funkciqta PORT_ctrl

//SAOB6TENIE
unsigned char message[ROW][COL];//tova e saob6tenieto sahraneno kato char stoinosti
unsigned char mess_y=0x00;
unsigned char mess_x=0x00;
unsigned char mess_ind_x=0x00;//pokazva poziciqta do koqto sme stignali pri zapisvaneto v message po horizontala
unsigned char mess_ind_y=0x00;//pokazva poziciqta do koqto sme stignali pri zapisvaneto v message po vretikala

long int repeat=0x00000000;//pokazva kolko pati 6te se izpi6e vseki ot ekranite display_1/2 predi da se prehvarlim kam drugiq
unsigned char mode=0x01;//tazi promenliva opredelq regima na rabota (dvigenie mode=0x00 nagore, mode=0x01 nadolu, mode=0x02 nalqvo i mode=0x00 nadqsno)

unsigned char disp=0x01;//kogato disp=1, zna4i display_1 e popalnen
//kogato disp=2, zna4i display_2 e popalnen
unsigned char display_1[0x06][0x7d];//tova sa dvata masiva koito sadargat obraza na ekrana
unsigned char display_2[0x06][0x7d];

unsigned char ctrl=0x00;//pokazva dali po serijniq port sledva da se podade komanda za upravlenie na displeq
unsigned char brightness=0x00;//pokazva kakva e qrkostta na izobragenieto

//promenlivi za kontrol na skorostta na dvigenie i za zadargane na obraza
//unsigned int velosity=SPEED;//pokazva kakva e skorostta na dvigenie na izobragenieto po ekrana
long int still=0x00;//pokazva kolko vreme nadpisat 6te stoi nepodvigen kogato se izpolzva regimat za zadargane na obraza
long int velosity=SPEED;
long int stat=STAND;
unsigned char to_go=0x00;//broi kolko reda sme preminali pri dvigenieto po vertikala predi za zadargim obraza

void init(void)
{
unsigned char i;
unsigned char j;

for(i=0x00;i {
for(j=0x00;j {
message[i][j]=0x00;
//message[i][j]=0x00;
}
}

//inicializiram display_1 i display_2
for(i=0x00;i<0x06;i++)
{
for(j=0x00;j<0x7d;j++)
{
//display_1[i][j]=0b01010101;
//display_2[i][j]=0b01010101;
display_1[i][j]=0x00;
display_2[i][j]=0x00;
}
}

//izhodni portove
DDRB=0xff;
PORTB=0x00;
DDRD=0xff;
PORTD=0b00100000;
DDRA=0xff;
PORTA=0x00;
//DDRC=0xff;
//PORTC=0x00;

//puskam taimer 0 na prescaler /8. Izpolzva se za 6IM na didoite.
TCCR0=0b00000010;
//nastroivam taimer 2 za funkciqta delay
TCCR2=0b00000010; //8
//Taimer 1 se nastroiva da dava clock kam 595ta i data send kam 595.
//Nastroivam TIMER1 v regim NORMAL
TCCR1A=0x00;
TCCR1B=0b00000010;//x8 prescaler
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x01;
OCR1AL=CLOCK;
//tozi registyr e ob6t za trite taimera
TIMSK=0b00010000;

//razre6avam zapis v EEPROM
EECR=0b00000011;

//RS232 setting
//1. nastroivame boad rate 9600 pri 16MHz
UBRRL=0x67;
//2.
UCSRA=0x00;
//3. nastroivame recieve, i interrupt pri receive, transmit disable i ne razre6avame prekasvane pri izprazvane na UDR
UCSRB=0b10010000;
//4. nastroivame 8bit duma, asinhronen regim, 1 stop bit,
UCSRC=0b10000110;

/* //TWI nastroiki
TWBR=0xf2;//4estotata na clock-a za predavbane na danni e CPU_frequency/(16+2*TWBR*4^0)=16*10^6/500=46666Hz
TWSR=0b00000000;//bez prescaler
TWAR=0b00000011;//adresa na MCU. LSB pokazva 4e e pozvolen regima na GENERAL CALL
TWCR=0b00000101;//tova e kontrolniq registar. Dvata setnati bita pokazvat 4e sme
//pozvolili rabotata na interfeisa i sme razre6ili prekasvaneto. Tova e master regim
//TWCR=0b01000101;//tova sa nastroikite za slave regim
*/

sei();
}

//tazi funkciq puska taimer2 za da zadava vremeto, v koeto seriiniqt signal e v 1
void delay(unsigned int time)
{
TCNT2=0x00;
while(TCNT2 {}
TCNT2=0x00;
}

//paramteri za funkciqta sa kolonite ot display_x masivite i led_on_x masivite
void PORT_ctrl(unsigned char b1, unsigned char a1, unsigned char cd1, unsigned char b2, unsigned char a2, unsigned char cd2)
{
unsigned char c=0x00;
unsigned char d=0x00;
unsigned char hold_SREG;

hold_SREG=SREG;//zapazvam status registara
cli();//zabranqvam prekasvaniqta

//c=cd1;
//d=cd1;

//c = cd1 & 0b11111100;
//c = cd1 | c;
//d = cd1 & 0b00000011;
//d = cd1 | d;

PORTB=b1;
PORTA=a1;
//PORTC=c;
//PORTD=d;

SREG=hold_SREG;
sei();
}

void leds_on(unsigned char content[0x06][0x7d])
{
PORT_ctrl(content[0x00][write],content[0x01][write],content[0x02][write],content[0x03][write],content[0x04][write],content[0x05][write]);
light_on=0x00;
if(write==0x40)
{
write=0x00;
}
}

ISR(TIMER1_COMPA_vect)
{
unsigned char hold_SREG;
unsigned char temp=0x00;

hold_SREG=SREG;//zapazvam status registara
cli();//zabranqvam prekasvaniqta

//1. Proverqvam sastoqnieto na PORTD 5
temp=PORTD;
temp=temp & 0b00100000;

if(temp==0x00)//ako do momenta e bil v nisko nivo podavam impuls i go slagam vav visoko nivo
{
clocks++;

if(clocks>=2 && clocks<=65)
{
write++;
//light_on=0x01;
}

if(clocks==66)
{
//vdigam bit na DATA SEND
PORTD = PORTD & 0b11101111;
PORTD = PORTD | 0b00010000;
//4akam
delay(SERIAL);
//vdigam bit na CLOCK
PORTD=PORTD & 0b11011111;
PORTD=PORTD | 0b00100000;
//4akam
delay(SERIAL);
//svalqm bit na DATA SEND
PORTD = PORTD & 0b11101111;
PORTD = PORTD | 0b00000000;

clocks=0x00;
}
else
{
//PORTA=0x00;
//PORTB=0x00;

PORTD=PORTD & 0b11011111;
PORTD=PORTD | 0b00100000;

PORTA=0x00;
PORTB=0x00;

if(disp==0x01)
{
leds_on(display_1);
}
else
{
leds_on(display_2);
}
}
}
else//ako do momenta sam bil vav visoko nivo, minavam v nisko
{
PORTD=PORTD & 0b11011111;
PORTD=PORTD | 0b00000000;
}

TCNT1H=0x00;
TCNT1L=0x00;

SREG=hold_SREG;
sei();
}

unsigned char shift(unsigned char in1, unsigned char in2, unsigned char direction)
{
unsigned char temp=0x00;
unsigned char temp1=0x00;
switch(direction)
{
case 0x00:
//2. poplvam display_1 - obhogdam po koloni, vzimam element i shift nagore
temp=in1;//premestvam sadarganieto na byta
temp=temp<<0x01;//s edna poziciq
temp1=in2;//vzimam sledva6tiq byte
temp1=temp1>>0x07;//shift na MSB na mqstoto na LSB
temp=temp & 0b11111110;//promenqm sadarganieto na LSB ot byta, koito premestvame
temp=temp | temp1;
break;
case 0x01:
//2. poplvam display_1 - obhogdam po koloni, vzimam element i shift nagore
temp=in1;//premestvam sadarganieto na byta
temp=temp>>0x01;//s edna poziciq
temp1=in2;//vzimam sledva6tiq byte
temp1=temp1<<0x07;//shift na LSB na mqstoto na MSB
temp=temp & 0b01111111;//promenqm sadarganieto na MSB ot byta, koito premestvame
temp=temp | temp1;
break;
}
return temp;
}

unsigned char row49(unsigned char addr, unsigned char mask, unsigned char in, unsigned char direction)
{
unsigned char temp,temp1;

switch(direction)
{
case 0x00:
temp=eeprom_read_byte((uint8_t*)addr);//tova e kolonata ot bukvata
temp=temp >> mask;//premestvam sadarganieto na temp bita koito 6te vliza na poziciq 0
temp=temp & 0b00000001;
temp=temp | 0b00000000;
temp1=in;
temp1=temp1 & 0b11111110;//6te promenqm samo bit 0 ot kolonata v display_2
temp1=temp1 | temp;//promenqm bita
break;
case 0x01:
temp=eeprom_read_byte((uint8_t*)addr);//tova e kolonata ot bukvata
temp=temp << mask;//premestvam sadarganieto na temp bita koito 6te vliza na poziciq 7
temp=temp & 0b10000000;
temp=temp | 0b00000000;
temp1=in;
temp1=temp1 & 0b01111111;//6te promenqm samo bit 0 ot kolonata v display_2
temp1=temp1 | temp;//promenqm bita
break;
}
return temp1;
}

//iztrivame saob6tenieto
void clear_mess(void)
{
unsigned char i,j;

for(i=0x00;i {
for(j=0x00;j {
message[i][j]=0x00;
}
}
mess_ind_x=0x00;
mess_ind_y=0x00;
}

//tazi funkciq opredelq dali po RS232 idva komanda ili bukva
void is_ctrl(unsigned char in)
{
if(ctrl!=0x00)
{
switch(ctrl)
{
case 0x06://skorost
velosity=in;
ctrl=0x00;
break;
case 0x07://qrkost
brightness=in;
ctrl=0x00;
break;
case 0x08://zadragane
stat=in;
ctrl=0x00;
break;
}
}
}

//funkciqta se izpolzva za popalvane na bukvite
void get_char(unsigned char in)
{
if(mess_ind_y {
if(mess_ind_x {
if(in>=0x20 || in<=0x7e)//ako podavam bukva na latinica
{
message[mess_ind_y][mess_ind_x]=in-0x20;
}
else//ako podavam bukva na kirilica
{
message[mess_ind_y][mess_ind_x]=in;
}
mess_ind_x++;
}
else//ako reda svar6i
{
mess_ind_y++;
if(in>=0x20 || in<=0x7e)//ako podavam bukva na latinica
{
message[mess_ind_y][0x00]=in-0x20;
}
else//ako podavam bukva na kirilica
{
message[mess_ind_y][0x00]=in;
}
mess_ind_x=0x01;
}
}
else
{
message[0x00][0x00]=in;
mess_ind_x=0x01;
mess_ind_y=0x00;
}
}

//funkciqta se izpolzva za zapisvane na novoto saob6tenie.
void load(unsigned char in)
{
switch(in)
{
case 0x1c://ako e izprateno 28, zna4i sme stignali do kraq na saob6tenieto, prekratqvame komunikaciqta
break;

default:
get_char(in);
break;
}
}

//prekasvaneto za seriniq interfeis
ISR(USART_RXC_vect)
{
unsigned char temp;
unsigned char stat_reg=0x00;

stat_reg=SREG;
cli();

temp=0x00;
temp=UDR;

is_ctrl(temp);//ako ctrl=0x00, ne pravim ni6to. Ina4e promenqm skorostta, qrkostta ili zadarganeto

switch(temp)
{
case 0x01://mode 0x01 - dvigenie nagore
mode=0x01;
break;

case 0x02://mode 0x02 - dvigenie nadolu
mode=0x02;
break;

case 0x03://mode 0x03 - dvigenie nalqvo
mode=0x03;
break;

case 0x04://mode 0x04 - dvigenie nadqsno
mode=0x04;
break;

case 0x05://mode 0x05 - stati4en regim
mode=0x05;
break;

case 0x1b://ako e izprateno 27, zna4i iskame da iztriem saob6tenieto
clear_mess();
ctrl=0x00;
break;

case 0x06://upravlenie na skorostta
ctrl=0x06;
break;

case 0x07://upravlenie na qrkostta
ctrl=0x07;
break;

case 0x08://upravlenie na zadarganeto na teksta v neopdvigno sastoqnie
ctrl=0x08;
break;

default://default se izpolzva kogato podavame bukvi
if(temp!=0x0a)//ako e podaden0 10, zna4i e inicializirana komunikaciqta
{
load(temp);//ako e podadeno ne6to razli4no ot 10, zna4i trbva da zapi6em bukvata
}
break;
}

//razre6avam 'transmit' i 'transmit interrupt', a zabranqvam 'receive' i 'receive interrupt'
UCSRB=0b01001000;
temp=0x21;
UDR=temp;
SREG=stat_reg;
sei();
}

ISR(USART_TXC_vect)
{
unsigned char stat_reg=0x00;

stat_reg=SREG;
cli();
//zabranqvam 'transmit' i 'transmit interrupt', a pozvolqvam 'receive' i 'receive interrupt'
UCSRB=0b10010000;
SREG=stat_reg;
sei();
}

void main(void)
{
unsigned char i;
unsigned char offset=0x00;//tova e promenlivata koqto obhogda elementa ot tablicata v EEPROM PO KOLONI
unsigned char mask=0x07;//tazi promenliva sledi bita koito 6te vliza kam ekrana
unsigned char buffer_ready=0x00;//kogato display_1 ili display_2 se popalnqt, setvame tazi promenliva
unsigned char column=0x00;//tazi promenliva se izpolzva pri popalvane na display_x, za opredelqne na kolonata varhu koqto rabotim

init();

while(1)
{
switch(mode)
{
case 0x01:
PORT_ctrl(0x01,0x01,0x01,0x01,0x01,0x01);
break;
case 0x02:
PORT_ctrl(0x02,0x02,0x02,0x02,0x02,0x02);
break;
case 0x03:
PORT_ctrl(0x04,0x04,0x04,0x04,0x04,0x04);
break;
case 0x04:
PORT_ctrl(0x08,0x08,0x08,0x08,0x08,0x08);
break;
}
}
}

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

i followed ur tutorial and wrote thos code...to switch on a led when i send a from hyperterminal and switch off the led when i send d from hyper terminal but no matter wat i send iam not able to control the led coz it keeps on blinking as given in the default program bfore any serial commands are sent

plzz check my code...iam running my cpu at 8mhz internal oscillator

#include  
#include  
#include 


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

volatile int f=0;

void portinitialize();
void uartinitialize();
void handleleft();
void handleright();
void bytedecision(volatile unsigned char);


void portinitialize()
 {
  DDRD|=(1<<4);
  TCCR1B|=(1<<CS12);
  }

void uartinitialize()
 {
   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 << RXCIE); // Enable the USART Recieve Complete interrupt (USART_RXC) 
   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed 
 }
void handleleft()
 {
  int m=0;
  PORTD&=~(1<<4);
  
  for(m=0;m<=100;m++)
  _delay_ms(10);
 }

void handleright()
 {
  int m=0;
  PORTD|=(1<<4);

  for(m=0;m<=100;m++)
  _delay_ms(10);
  }

void bytedecision(volatile unsigned char a)
 { 
  if(a=='a' || a=='A')
   {
    handleleft();
    }
  if(a=='d' || a=='D')
   {
    handleright();
   }
 }

int main (void) 
{ 
   portinitialize();
   uartinitialize();
   
   for(;;) // Loop forever 
   { 
     if(f==0)
	   
	    
     {
  
    if(TCNT1>=31250)
	 
	 {
	  PORTD^=(1<<4);  // run test program blinking- echoing is handled by the ISR instead of in the main loop 
	  TCNT1=0;
	 }
	 }
 }
       
      
} 

ISR(USART_RXC_vect) 
{ 
   f=1;
   volatile unsigned char ReceivedByte; 
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
   //UDR = ReceivedByte; // Echo back the received byte back to the computer 
   bytedecision(ReceivedByte);
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i followed ur tutorial and wrote thos code...to switch on a led when i send a from hyperterminal and switch off the led when i send d from hyper terminal but no matter wat i send iam not able to control the led coz it keeps on blinking as given in the default program bfore any serial commands are sent

plzz check my code...iam running my cpu at 8mhz internal oscillator

#include  
#include  
#include 


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

volatile int f=0;

void portinitialize();
void uartinitialize();
void handleleft();
void handleright();
void bytedecision(volatile unsigned char);


void portinitialize()
 {
  DDRD|=(1<<4);
  TCCR1B|=(1<<CS12);
  }

void uartinitialize()
 {
   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 << RXCIE); // Enable the USART Recieve Complete interrupt (USART_RXC) 
   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed 
 }
void handleleft()
 {
  int m=0;
  PORTD&=~(1<<4);
  
  for(m=0;m<=100;m++)
  _delay_ms(10);
 }

void handleright()
 {
  int m=0;
  PORTD|=(1<<4);

  for(m=0;m<=100;m++)
  _delay_ms(10);
  }

void bytedecision(volatile unsigned char a)
 { 
  if(a=='a' || a=='A')
   {
    handleleft();
    }
  if(a=='d' || a=='D')
   {
    handleright();
   }
 }

int main (void) 
{ 
   portinitialize();
   uartinitialize();
   
   for(;;) // Loop forever 
   { 
     if(f==0)
	   
	    
     {
  
    if(TCNT1>=31250)
	 
	 {
	  PORTD^=(1<<4);  // run test program blinking- echoing is handled by the ISR instead of in the main loop 
	  TCNT1=0;
	 }
	 }
 }
       
      
} 

ISR(USART_RXC_vect) 
{ 
   f=1;
   volatile unsigned char ReceivedByte; 
   ReceivedByte = UDR; // Fetch the recieved byte value into the variable "ByteReceived" 
   //UDR = ReceivedByte; // Echo back the received byte back to the computer 
   bytedecision(ReceivedByte);
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,
I am using an atmega128. I have copied the program to avr but does anybody know how I can use 2 USART's at the same time. I want to connect a compas to UART0 and my pc on UART1. The meaning is that I can read the input on UART0(compas) via UART1(pc).
You can find my program in an attachement.

Attachment(s): 

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

nilswinkelmans,

You need to append the USART number to the end of the register names (before any suffixes):

UCSRB

Becomes:

UCSR0B

For the first USART for example, or:

UCSR1B

For the second. You also need to change the ISR vector name to include the USART you are referencing:

ISR(USART_RXC_vect)

Becomes:

ISR(USART0_RXC_vect)

For the first USART. You need to initialise and control each USART separately in the same way as the tutorial.

- Dean :twisted:

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

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

nice tutorial...
i liked the idead of having 2 buffers for line processing.. if you want to implement help/configure menu...

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

I am trying to create a program that will receive a command from user via RS-232 port (eg. 'B1' ended with a carriage return). I want to store that command in a variable so that I can compare it to a predefined list of commands and output the correct response. I am not sure how to read in the command so that I can do my comparison.

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

Start by setting up an RXC interrupt that populates a circular buffer, then you'll also have a getchar() style routine that just pulls characters after the buffer. As you strings are terminated then just loop doing getchar()s until you get '/r' (or possibly '/n') then strstr() the received string against each command.

Cliff

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

Hello Dean,
Would it be easy to make a version of your USART interrupts tutorial in PDF form, like your USART intro?

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

Sure, I've attached a PDF version to the original post. Enjoy!

- Dean :twisted:

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

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

abcminiuser wrote:
Sure, I've attached a PDF version to the original post. Enjoy!

- Dean :twisted:


Thanks Dean, for both tutorials. Something good to read while the boy is watching endless Spongebob Squarepants :D

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

First of all great tutorial ;) but I've managed to get here when I got "should-working" code ;-) Anyway I still have problem with my ATmega48. USART on polling works perfectly (4MHz external quartz enabled through fuse bits), but interrupts doesn't.

here is my code :

#define FOSC 4000000 // Clock Speed
#define BAUD 9600
#define MYUBRR ((unsigned int) (FOSC/16/BAUD-1))
#include 
#include 

volatile unsigned char data;

void PORTC_Init(void) {
	DDRC=0xff; // Port C as output
	PORTC=0x01; // first LED on, second off
}

void USART_Init( unsigned int ubrr ) {
	PRR = ~_BV(PRUSART0);
	/* Set baud rate */
	UBRR0H = (unsigned char) (ubrr>>8);
	UBRR0L = (unsigned char) ubrr;
	/* Set frame format: 8data no parity 1stop bit */
	UCSR0C = (0<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01);
	UCSR0B |= (1<<UCSZ02);
	/* Enable receiver and transmitter */
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	/* Enable receiver interrupt */
	UCSR0B |= (1<<RXCIE0);
}

ISR(USART_RX_vect) {

	PORTC ^= _BV(0);
	PORTC ^= _BV(1);

	while ( !( UCSR0A & (1<<UDRE0)) );
	UDR0 = 0x61;
}

int main (void) {
	PORTC_Init();
	USART_Init(MYUBRR);

	while ( !( UCSR0A & (1<<UDRE0)) );
	UDR0 = 0x4E;
	while ( !( UCSR0A & (1<<UDRE0)) );
	UDR0 = 0x61;
	while ( !( UCSR0A & (1<<UDRE0)) );
	UDR0 = 0x4E;
	//send NaN on USART

	sei();

	while(1);
	return 0;
}

I've got two LEDs on portC and I want them to blink when interrupt is invoked and send something back to terminal.

As for now I just can't get this working. The first 3 letters are send ("NaN") and then when I press anything on keyboard I get nothing. Well sometimes I get frame error on realterm.

I'm using ubuntu 9.04 amd64 as my main system, so I'm compiling under it. After going through all pages here I think it's a compiler problem, but I may be wrong. Anyway I'm compiling it this way :

avr-gcc easy.c -mmcu=atmega48 -o easy.hex -Wall -Wstrict-prototypes -Werror -mcall-prologues -g2 -O1

Everything loads up fine... but still no luck. I would be glad if anyone could help me here a little ;-)

EDIT :
If anyone has similar problem just copy makefile from avrstudio and run it... vuala, it works :D

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

@abcminiuser: the tutorial was very useful. By the way when i check my circuit by send for example 001 in decimal i get the response 255 .
Input Output
002 253
003 251
004 251

What does this mean? this doesn't have a pattern.. Can you tell me why I get some random values?

PS:I used the software Hterm for checking(I connected to the computer by a COM port at 9600bps 8 bit no parity just as was in the tutorial)

Thanks a lot,
Bala

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

Thanks Dean!
It was so useful for me :)

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

Hi
how to program modbus in gcc and could you tell me how to make a quary to tx and how to get rx respons from modbus through uart Smile

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

Ganapathy wrote:
how to program modbus in gcc and could you tell me how to make a quary to tx and how to get rx respons from modbus through uart Smile

GCC: http://www.freemodbus.org/index....
ICC: https://www.avrfreaks.net/index.p...

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

Thank u
I have another problem now. my program to transmit data of query but modbus couldn't response

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

hi
could you tell me. modbus are synchronous or asynchronous data transmission? plz

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

Have you heard of google? Do your homework. Enter "modbus asynchronous" into google and you will have an answer.

These are the tools that will help you with modbus troubleshooting:
http://www.modbusdriver.com/modp...
http://www.modbusdriver.com/diag...

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

Is there any way in which we can change the priorities of the interrupts?

Bittu Sarkar
Dept. of Computer Science & Engg.
Indian Institute of Technology, Kharagpur

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

No, the interrupt priority (on the regular AVR8) is fixed and cannot be changed. The best you can do would be either to selectively disable certain interrupts for short periods, or make your low priority interrupts themselves interruptable (which is dangerous).

- Dean :twisted:

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

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

Hello all.
I just wondering as newbie, witch great pottencial have programing atmel product.
So maybe can you help me with this problem.
I just copy the program and made some changes.
When I open Windows Hyperterminal and send "a" or "b" everything is working, just to situatiation when I disconnect the programing LPT cable. Till LPT programing cable is connected then all is working, but when I disconnect cable the communication is not working (but hyperterminal says that is connected).

Here is Code

#define F_CPU 8000000UL

#include 
#include 

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

volatile unsigned char LED1;
int main (void)
{  
	DDRC=0xff;
    LED1=0x00;

   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 << RXCIE); // 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"
   	if (ReceivedByte==0x61) LED1=LED1^0b00000001;
	if (ReceivedByte==0x62) LED1=LED1^0b00000010;
	if (ReceivedByte==0x63) LED1=LED1^0b00000100;
	if (ReceivedByte==0x64) LED1=LED1^0b00001000;
	if (ReceivedByte==0x65) LED1=LED1^0b00010000;
	if (ReceivedByte==0x66) LED1=LED1^0b00100000;
    PORTC=LED1;
	UDR = ReceivedByte;// Echo back the received byte back to the computer

}

And schematics is in file.
Thanks you for help, maybe you kick my ass to next stair step
:)

Attachment(s): 

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

I forgot to write that I use internal 8Mhz oscilator
thanks

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

DragonSoul wrote:
I forgot to write that I use internal 8Mhz oscilator
thanks
That's asking for trouble with the serial interface. Please use the forum search function to find out why. It is an FAQ.

Stealing Proteus doesn't make you an engineer.

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

Quote:
but when I disconnect cable the communication is not working

Either I'm totally missing something or the obvios reply to that is "Yes, what did you expect?".
Quote:
(but hyperterminal says that is connected).

Hypertermial is probably not set up to detect if there is a physical connection. For RS232 communications this is handled by separate signal lines, typically DSR and DTR (not TxD and RxD). And something needs to keep those signals on the required levels. This can be done by the AVR (conuming two IO pins, and needing a external level adjustment arrangement). You could also arrange for a simple "loopback" of DTR to DSR at the PC side of the physical connection. And then you need to set up Hyperterminal to detect existence of connection with DTR-DSR.

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:
Quote:
but when I disconnect cable the communication is not working

Either I'm totally missing something or the obvios reply to that is "Yes, what did you expect?".


Sorry I forgot to write when I disconnect LPT communication cable, then RS232 communication stop working.

I develop, that when I just connect GND to GND LPT cable the communication start working and when I disconnect the GND from GND LPT cable that communication stop working. Maybe the GND from adapter witch generate 12 Volts is not real GND and of course the LPT ground is grounded to PC, but I cant develop, how to ground this system without computer.

Thank for you time

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

Where does the LPT cable go? To the AVR? Is it the LPT cable that is supplying power to the AVR perhaps?

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

The LPT cable is painted on schematic as 'To PC LPT'. Is connected as explained on http://www.scienceprog.com/simplest-128-atmega-programmer/ and is used for programing ATMega8. Normally I disconect the cable and ATmega is feed with 5V through 7805 as showed on my schematics. For another application as flashing LED i disconnect programing LPT (printer) cable and procesor is working. But I develop, that when LPT cable is connected then RS232 communication is working, when I disconnect LPT cable, then communication is not working. But processor is still running. When I connect any GND to GND of LPT cable, then RS232 communication start working. Now I dont know, how I can ground GND in my room without computer.

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

On your serial port cable, do you have all three of Tx, Rx and GND connected? You have to have the serial cable's ground pin connected to your circuit ground, or the two circuits (PC and your board) will be floating in regards to one-another and the communications won't work.

- Dean :twisted:

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

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

You have no common ground for the AVR and the device you are communicating with? If so: Bad. You need that.

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

Dean.
Yes. I have all three cable Rx, Tx and ground connected, RS232 ground is connected to my circuit ground (middle pin of 7805 see schematic).
JehanEkdalh
So you mean, that what is writen on my 12V adapter as GND is not ground, but just 0V potencial?

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

Quote:

So you mean, that what is writen on my 12V adapter as GND is not ground, but just 0V potencial?

There is no universal ground. If two devices are to interpret signals from eah other they have to share a ground, which is the "zero reference" for them.

Disconnect the LPT cable. Have the RS232 cable connected. Now measure the voltage between GND on your AVR circuit and some good, known GND on your PC. Not zero Volts? Then something in the GND circuit between the AVR and the PC is broken. Do a continuity check on the RS232 cable to make sure the GND is wired correctly to both connectors (pin 7 on a DB-25 connector, pin 5 on a DE-9 connector).

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

Hi,

A question perturbs me :
I understand the interest to use interrupts and ring buffer for Rx because we cannot really control it but which is the interest to use interrupts and rint buffer for Tx ?
What can be the problems to do the Tx synchronously ?

Thank you

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

No problems doing Tx synchronously -- some people just like to buffer data before sending. This is useful in some cases where the serial data has a timeout on the receiver's end, so you buffer the data and send it as a single chunk to ensure that the receiver's timeout period doesn't expire prematurely.

- Dean :twisted:

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

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

Hello.
Thanks very much to JohanEkdahl and abcminiuser for help with problem with RS232 communication.
Problem was, that on the 9-pin connector witch lead to MAX232 pin 5 haved cold connection. So after measurement i develop, that GND was not in same level, but I dont know why. After resolder all connection, now all is working. Very good job with help Thanks

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

Ha! My suspicions about bad grounding was well grounded! :D

Happy that it worked out for you!

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

Thanks Dean, this is another clean tutorial. This has possibly been mentioned by others: The interrupt vector table (Attiny2313) gives a source of "USART0, RX" which would be thought to be converted to "USART0_RX_vect" for use in ISR(), however it must be specified as "USART_RX_vect" as stated here:

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

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

hello guys! i'm jericho. i'm trying to learn avr micros, i'm studying it for about 3 weeks now and this site help me a lot!

now i'm having a hard time doing my code. i'm using atmega8 to be interfaced with a GPS module. i already made a code displaying GPS data sent to the MCU then the MCU sending the gps data to hyperterminal..

but now, i'm trying to display this in hyperterminal


time: (current GPS time)

unfortunately, i can't do it. it seems like my code is not working.. here it is..


//	atmega8	 //


#include 
#include 
#include 
#include 


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


volatile uint8_t data, parsing_state, state;
volatile int8_t ReceivedByte[5], time[13], latitude[12];
volatile int8_t longitude[13], speed[6], date[9] ;


void init_uart()
{
	// enable Tx/Rx circuitry
	UCSRB |= (1<<RXEN) | (1<<TXEN);

	// 4800bps, 8-bit data, no parity, 1 stop bit
	UCSRC |= (1<<URSEL) | (1<<UCSZ0) | (1<<UCSZ1);

	UBRRL = BAUD_PRESCALE;
	UBRRH = (BAUD_PRESCALE>>8);
}


void gprmc_only()
{
	int8_t GPRMC[] = "$PSTMNMEACONFIG,0,4800,64,1\r\n";

	while (GPRMC[data] != 0x00)
	{
		while ((UCSRA & (1<<UDRE)) == 0) {};
		UDR = GPRMC[data++];
	}
}


void time_menu()
{	
	data = 0;

	int8_t real_time[] = "time: ";
	
	while (real_time[data] != 0x00)
	{
		while ((UCSRA & (1<<UDRE)) == 0) {};
		UDR = real_time[data++];
	}
	
	data = 0;
	
	while (time[data] != ',')
	{
		while ((UCSRA & (1<<UDRE)) == 0) {};
		UDR = time[data++];
	}

	state = 0;	
}					

int main (void)
{
	init_uart();

	state = 0;
	parsing_state = 0;
	data = 0;
	
	UCSRB |= (1<<RXCIE);	// enable Rx complete interrupt

	_delay_ms(1000);
	_delay_ms(1000);
	_delay_ms(1000);

	gprmc_only();

	sei();	// enable all interrupt

	while (1)
	{
		if (state == 1)
		{
			UCSRB |= (0<<RXCIE); // disable Rx interrupt
			
			time_menu();
	
			UCSRB |= (1<<RXCIE); // enable Tx interrupt
		}

	}
}


ISR (USART_RXC_vect)
{
	switch (parsing_state)
	{
		case 0:

			data = 0;

			ReceivedByte[data] = UDR;
			
			if (ReceivedByte[data] == '$')
				parsing_state++;
			
			else
			{
				parsing_state = 0;
				state = 0;
			}

			break;


		case 1:
	
			ReceivedByte[data] = UDR;
			
			if (ReceivedByte[data] == ',')
				parsing_state++;
			
			else 
			{
				parsing_state = 1;
				state = 0;
			}
				
			break;	


		case 2:

			data = 0;

			time[data] = UDR;

			if (time[data] == ',')
				parsing_state++;
			
			else
			{
				data++;
				parsing_state = 2;
				state = 0;
			}

			break;


		case 3:
			
			data = 0;

			ReceivedByte[data] = UDR;
			
			if (ReceivedByte[data] == ',')
				parsing_state++;

			else 
			{
				parsing_state = 3;
				state =0;
			}

			break;

		case 4:
			

			data = 0;

			latitude[data] = UDR;

			if (latitude[data] == ',')
				parsing_state++;

			else
			{
				parsing_state = 4;
				data++;
				state = 0;
			}
				
			break;

		case 5:


			data = 0;

			ReceivedByte[data] = UDR;

			if (ReceivedByte[data] == ',')
				parsing_state++;

			else 
			{
				parsing_state = 5;
				state = 0;
			}

			break;


		case 6:
			
			data = 0;

			longitude[data] = UDR;

			if (latitude[data] == ',')
				parsing_state++;

			else 
			{
				parsing_state = 6;
				data++;
				state = 0;
			}

			break;


		case 7:
	
			data = 0;
			
			ReceivedByte[data] = UDR;
			
			if (ReceivedByte[data] == ',')
				parsing_state++;
			
			else
			{ 
				parsing_state = 7;
				state = 0;
			}
				
			break;

						
		case 8:
			
			data = 0 ;

			speed[data] = UDR;

			if (speed[data] == ',')
				parsing_state++;

			else
			{
				parsing_state = 8;
				data++;
				state = 0;
			}

			break;


		case 9:
			
			data = 0;

			ReceivedByte[data] = UDR;

			if (ReceivedByte[data] == ',')
				parsing_state++;

			else 
			{
				parsing_state = 9;
				state = 0;
			}

			break;

								
		case 10:
			
			data = 0;

			date[data] = UDR;

			if (date[data] == ',')
				parsing_state++;

			else 
			{
				parsing_state = 10;
				data++;
				state = 0;
			}
			
			break;


		case 11:

			data = 0;
			
			ReceivedByte[data] = UDR;

			if (ReceivedByte[data] == 0x00)
			{
				parsing_state = 0;
				state = 1;
			}
				
			else 
			{
				parsing_state = 11;
				state = 0;
			}
			break;
		
	}

}

i hope you can tell me what's wrong with my code.. thanks!

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

Forget the interrupts and the GPS parsing to start with. Are the basics working? If you simply:

int main(void) {
  init_uart();
  while(1) {
     while ((UCSRA & (1<<UDRE)) == 0) {}; 
     UDR = 'A'; 
  }
}

do you see a stream of 'A's at 4,800 baud on your PC terminal?

If you then modify that to just have a single character RXC interrupt handler that main() echoes back does that then work?

Continue adding the program complexity back in and retesting until you find any flaw in the logic but don't expect all of such a complex program to all work right from the start.

Make a lot of use of the PC terminal for debugging. Remember that if the AVR only RX's from the GPS then as long as you stick to 4800 you can split TX/RX so TX goes to the PC terminal as a debug output and RX is the connection from the GPS

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

hi clawson! thanks for the reply!

i already did what you've said before doing this. and it worked fine. i also finished writing a code that will display the GPS data sent to the MCU then the MCU sending the data to hyperterminal. but after inserting the parsing routine, it seems stopped working..

:(

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

Quote:

but after inserting the parsing routine, it seems stopped working..

In which case you have identified the bit that requires the work - now break that into small implementation steps and try to find the point where it stops behaving as expected.

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

Hello all,
How i can extract only #GPRMC sentence from all nmea sentences ? Jericho wrote code isn't universal function for taking only gprmc. Im thinking to use data from "$" to "*" but how ?

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

Quote:
How i can extract only #GPRMC sentence

http://www.maartenlamers.com/nmea/

(it's C++ for Arduino but you should be able to convert if you need it in C)

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

How i should convert it ? i never worked with Arduino :\
Any other suggestions in c language ?

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

Quote:

Any other suggestions in c language ?

I found that after 2 minutes with Google. If I'd spent the whole 5 minutes I'm sure I could have found C code - it's not like you are the first person who wants to parse NMEA. Try "parse NEMA GPRMC C source" or similar.

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

Need some TUTorials about avr interfacing with gps, like TUT using usart.. :?