[TUT] [SOFT] Using the USART - Serial communications

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

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

Using the USART with AVR-GCC

Freaks,

I've had this three-quarters finished and sitting on my hard drive since mid-last year, so I decided to finish it and post here for the benefit of others. I'm the first to admit it's not very clearly written, so I may re-write it in the future. Comment away.

This tutorial will focus on setting up the serial USART on the AVR platform. Although other hardware AVR interfaces (eg, USI) can be configured for limited RS-232 serial transmission and reception such alternatives will not be covered.

What is the USART?

The vast majority of devices in the current AVR family lineup contain a USART hardware subsystem. The USART hardware allows the AVR to transmit and receive data serially to and from other devices - such as a computer or another AVR.

The USART transmission system differs to most other digital busses in that it does not utilize a separate pin for the serial clock. An agreed clock rate is preset into both devices, which is then used to sample the Rx/Tx lines at regular intervals. Because of this, the USART requires only three wires for bi-directional communication (Rx, Tx and GND).

The RS-232 Specification

The serial USART is frequently referred to as RS-232, which is a reference to the RS-232 specification which mandates the logic levels and control signals. While the AVR's normal logic levels are about 3-5V, RS-232 communication uses a low of +3V to +25V for a digital '0', and -3V to -25V for a digital '1'.

If the two USART devices are running at AVR logic levels, the Tx and Rx pins can be connected together directly. If the devices are using RS-232 spec. voltages, a level converter is needed.

This tutorial will assume the user is attempting to interface with a computer RS-232 port, which uses the proper RS-232 specification logic levels.

First things first - Setting up the Hardware

To connect your AVR to a computer via the USART port, you will need to add a level converter to your existing circuit. The most common/popular serial level converter is the Maxim MAX232 (datasheet avaliable here). This small and relatively inexpensive IC will convert your AVR's 5V logic levels to 10V RS-232 and vice versa.

Before you can hook up your MAX232, you need to first identify which pins of your AVR are responsible for serial communication. Looking in your AVR's datasheet, you should be able to identify the two serial port pins (named as alternative pin functions TX and RX).

You should wire up your MAX232 to reflect the schematic here. This will enable your AVR's USART hardware to interface with the computer's USART hardware.

Deciding on your AVR's system clock frequency

As mentioned above, the USART does not use an external clock. To allow the two interfaced devices to communicate together, you need to decide on a baud rate for communication. Also due to the timing-critical nature of the USART, your system's clock should be stable and of a known frequency. The AVR's system clock frequency is very important. The USART clock is derived from the system clock, and it is used to sample the Rx line and set the Tx line at precise intervals in order to maintain the communication.

If the system clock cannot be precisely divided down to a "magic" frequency for perfect communications, it will have a percentage error (where a byte fails to be read or written inside designated time frame). System clocks for perfect USART communications should be multiples of 1.8432MHz which when used will give a 0.00% error.

Other frequencies for the main AVR clock can be used, but as the frequency drifts from the "perfect" multiples of 1.8432MHz, the greater the percentage error will be (and thus the less reliable the serial communication will be). It is generally accepted that error percentages of less than +/- 2% are acceptable.

Looking in your AVR's datasheet in the USART section you should see a table of common baud rates, system clocks and error percentages. You should find a combination which suits your project's constraints and has the lowest possible error percentage.

I will be basing the rest of this tutorial on an example setup; a MEGA16 running at 7.3728MHz and a baud rate of 9600bps (bits per second). This combination, because it uses a system clock which is a multiple of the magic 1.8432MHz, has an error percentage of 0.00%).

Initializing the USART

Now you should have selected a baud rate, system clock and have your AVR set up with a RS-232 level converter - you're all set to go! All you need is the firmware to drive it.

First off, you need to enable both the USART's transmission and reception circuitry. For the MEGA16, these are bits named RXEN and TXEN, and they are located in the control register UCSRB. When set, these two bits turn on the serial buffers to allow for serial communications:

#include 

int main (void)
{
	UCSRB = (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
}

Next, we need to tell the AVR what type of serial format we're using. The USART can receive bytes of various sizes (from 5 to 9 bits) but for simplicity's sake we'll use the standard 8-bits (normal byte size for the AVR). Looking again at the MEGA16 datasheet, we can see that the bits responsible for the serial format are named UCSZ0 to UCSZ2, and are located in the USART control register C named UCSRC.

The datasheet very handily gives us a table showing which bits to set for each format. The standard 8-bit format is chosen by setting the UCSZ0 and UCSZ1 bits. Before we write to the UCSRC register however, note a curious peculiarity in our chosen AVR, the MEGA16. To save on register addresses, the UCSRC and UBRRH registers (the latter being explained later in this text) share the same address. To select between the two, you must also write the URSEL bit when writing to UCSRC:

#include 

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 - URSEL bit set to select the UCRSC register
}

The URSEL bit does not exist in all AVR models; check your chosen AVR's datasheet.

There, we're almost done setting up the USART! The last thing to set for basic serial communications is the baud rate register. This register sets the clock divider for the USART which is used as a timebase to sample the incoming data at the correct frequency. It also gives the timebase for sending data, so it's vital for RS-232 serial communications.

The baud rate register is 16-bit, split into two 8-bit registers as is the case with all 16-bit registers in the AVR device family. To set our baud rate prescaler value, we first need to determine it. Note that the baud rate register value is NOT the same as the baud rate you wish to use - this is a common point of failure amongst those new to the serial subsystem. Instead, the value must be derived from the following formula:

    BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)

Where F_CPU is your AVR's system clock frequency (in Hz), and USART_BAUDRATE is the desired communication baud rate.

Given my example project using a system clock of 7372800Hz and a baud rate of 9600, our formula gives:

    BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) BaudValue = (7372800 / (9600 * 16) - 1)
    BaudValue = (7372800 / 153600 - 1)
    BaudValue = (48 - 1)
    BaudValue = 47

To make our life easier, we can turn this formula into a set of handy macros. F_CPU is automatically defined in AVR-GCC via your makefile, so all that is needed is the baud rate:

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

This avoids "magic numbers" (unexplained constants) in our source code, and makes changing the baud rate later on very easy - just change the BAUD_RATE macro value. Now, we need to load this into the baud rate registers, named UBRRH (for the high byte) and UBRRL (for the low byte). This is simple via a simple bitshift to grab the upper eight bits of the BAUD_PRESCALE constant:

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

Now we're ready to rock and roll!

Sending and receiving data

Once initialized, we're ready to send and receive data. We do this by the special register named UDR - short for "USART I/O Data Register". This is special for two reasons; it behaves differently when it is read or written to, and it is double buffered.

By assigning a byte to the UDR register, that byte is sent out via the AVR's Tx line. This process is automatic - just assign a value and wait for the transmission to complete. We can tell when the transmission is complete by looking at the transmission completion flag inside the USART control registers.

On the MEGA16, the Transmission Complete flag is located in the control register UCSRA, and it is named TXC. Using this information we can construct a simple wait loop which will prevent data from being written to the UDR register until the current transmission is complete:

UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"
while ((UCSRA & (1 << TXC)) == 0) {}; // Do nothing until transmission complete flag set

However this is non-optimal. We spend time waiting after each byte which could be better spent performing other tasks - better to check before a transmission to see if the UDR register is ready for data. We can do this by checking the USART Data Register Empty flag instead (called UDRE), also located in the UCSRA control register of the MEGA16:

while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = ByteToSend; // Send out the byte value in the variable "ByteToSend"

This is much better, as now time is only wasted before a transmission if the UDR register is full. After a transmission we can immediately continue program execution while the UDR byte is sent, saving time.

Now we can move on to receiving data. As mentioned before, the UDR register behaves differently between read and write operations. If data is written to it it is sent out via the AVR's Tx pin, however when data is received by the RX pin of the AVR, it may be read out of the UDR register. Before reading the UDR register however, we need to check to see if we have received a byte.

To do this, we can check the USART Receive Complete (RXC) flag to see if it is set. Again, this is located in the UCSRA control register of the MEGA16:

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 "ReceivedByte"

Putting it all together

Right! Now it's time to put everything together! Let's make a simple program that echoes the received characters back to the computer. First, the basic program structure:

#include 

int main (void)
{

}

Next, our USART initializing sequence:

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

Now, an infinite loop to contain our echo code:

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

	}
}

And some echo code to complete our example. We'll add in a local variable "ReceivedByte", which will always hold the last received character from the computer:

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

And voila, we have a working serial example! Connect to this project via a serial terminal on your computer, using 8-bit, no parity 9600 baud communication settings and it will echo back anything you send to it.

Potential Pitfalls

There are several "gotchas" when dealing with the USART. First, make sure your AVR is running of a reliable, known clock source with a low error percentage at your chosen baud rate. New AVRs default to their internal oscillators until their fuses are changed. The internal RC oscillator is of too low a tolerance for use with the USART without external calibration.

Check your datasheet to check for the locations of the different flags. Different AVRs have the control flags located in different control registers (UCSRA, UCSRB and UCSRC).

Make sure your computer terminal is connected at the exact settings your AVR application is designed for. Different settings will cause corrupt data.

Cross your Rx and Tx wires. Your PC's Rx line should be connected to your AVR's Tx line and vice-versa. This is because the Rx/Tx lines are labeled relative to the device they are marked on.

Some AVRs do not have the URSEL bit to differentiate between the UCSRC and UBRRH registers - check your datasheet.

Advanced serial communication

A more advanced method of serial communication involves the use of the USART interrupts and is not covered here. I may cover it in a later tutorial if so desired.

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:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I read it rather quickly, and it seems like a good introduction to serial comms! Check out this one though:

Quote:
RS-232 communication uses a low of +3V to +25V for a digital '1', and -3V to -25V for a digital '0'.
+3V to +25V is used for signalling LOW, shouldn't that be digital '0'....

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

Quote:
Check out this one though:

Fixed, thanks.

- Dean :twisted:

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

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

Dunno if it's worth mentioning, but a newbie should probably be encouraged to look at the power-on default settings of the USART control registers as noted in the datasheet. (And all the registers they work with for that matter.)

For typical 8N1 asynchronous communications, UCSRC can usually be totally ignored (at least, in every AVR I've ever used) because the appropriate bits are automatically preset whenever the chip powers up or comes out of reset.

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

hey which software do you use to recieve the data on the comp...hmm and ya UCSRC and UBRR hav the same memory addr..the first bit wil decide which one is to be written ...i tried simulating it in avr studio..its not working ...any suggestions...??

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

use windows terminal (start-programs-accessories-communications-hyper terminal

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

Quote:
BaudValue = (((F_CPU / (USART_BAUDRATE * 16))) - 1)

Where F_CPU is your AVR's system clock frequency (in Hz), and USART_BAUDRATE is the desired communication baud rate.

Given my example project using a system clock of 7372800Hz and a baud rate of 9600, our formula gives:

BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
BaudValue = (7372800 / (9600 * 16) - 1)
BaudValue = (7372800 / 153600 - 1)
BaudValue = (48 - 1)
BaudValue = 47

The only thing I would like to add is that, unless the microcontroller XTAL1, XTAL2 frequency is one of those "Magic Numbers", the final BaudValue will be a mixed number and be rounded down as, the final value of BaudValue must be an integer - the remainder will be lost.

If an XTAL value is used that produces a value of say, 48.1, the error produced by the trunkation of the fractional part, I.E. 0.1, will produce a Baud rate error just slightly greater then 2%. This error may well work without USART timing issues.

But, an XTAL frequency producing a final BaudValue of say, 48.2 or greater, will produce a BAUD rate timing error of more then 4%, which is outside of the +/-3% error margin specified by Atmel.

You can avoid reality, for a while.  But you can't avoid the consequences of reality! - C.W. Livingston

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

:arrow:

Last Edited: Wed. Feb 14, 2007 - 02:19 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL)))

should actually be

#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))))

took me a few to figure out it was missing a closing )

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

Thanks Night'. Actually, it should be:

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

As previously stated in the tutorial, I just missed the last part when I copy-pasted it. Fixed now, I've updated the PDF too.

- Dean :twisted:

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

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

And if you add the half if the divisor, then the formula will not only truncate , but round up or down

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

Weiterstadt, Germany

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

Hi!

I'm not sure if I should post this here but I have a question regarding those capacitors around max232. Do their values have anything to do with the baudrate you are using or are always those values?

If they are a function of the baudrate what is the equation to calculate their capacity?

Thanks a lot.

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

the capacity is given in the datasheet. it has absolutely nothing to do with BAUD rates nor anything with the serial data...
It's to create 10V for PC USART side and nothing more. read the MAX232 datasheet man!

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

After compiling and writing to the ATmega16, and switching the serial cable to the "RS232 SPARE" connection, I set up a connection in Hyperterminal;

Baud 9600
8 bits, no parity, 2 stop bits

However, when I type text in the terminal, the echo is only exotic ASCII characters, not the a-z 0-9 I'm typing... I've tried 1 stop bit, and also 1.5 - same thing. Any clues as to why this is happening?
Btw, great tutorial, Dean! :)

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

joakimk wrote:
Any clues as to why this is happening?

What is the AVR clock source? The fact that you get some response suggests you are close so maybe you're using the internal oscillator and it needs calibrating?

Cliff

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

Quote:
...maybe you're using the internal oscillator and it needs calibrating?

Yes, I am using the internal oscillator;
Int. RC Osc. 1 MHz; Start-tp time: 6CK + 4ms ...

I tried modifying Dean's C code to run at 1MHz like this:

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

How does one calibrate? Am I calculating the BAUD correctly? I couldn't get the F_CPU macro working, so I hard-coded 1MHz in the above formula...

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

Try setting your terminal program for one stop bit, instead of two - that's what my code is expecting.

- 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 2 projects at the same time, an AVR (presently in an 8535, but that will probably change) and Windows desktop using wxWidgets. The projects talk to each other via RS-232C.

The AVR info in this forum looks very useful. If someone needs help at the other end of the cable, drop me a personal msg. and I will see if anything I have is applicable. It took me a while to get my own desktop program talking correctly on COM1.

I use an SDK500 for my prototyping and the "Spare Serial" port works with a standard cable directly to a desktop/laptop without 'twisting' it. You just have to remember to connect the 2 pins near the switches to D0 and D1. If you need to 'twist' the connections, there is a good place to do it for RX and TX. I use a 4.000 MHZ crystal, so I have to choose my baud rate settings carefully.

Another suggestion relative to serial ports is that it is quite useful to output debug statements to the serial port, but when you declare strings in printf statements, they fill up your data space. You can easily put them into EEPROM with a few simple functions.

I also have some AVR software for LCD displays and debouncing matrices of switches, such as keypads, that utilize timer interrupts to work in the background. PM me if this is something you are interested in.

The only thing more dangerous than a software engineer with a soldering iron is a hardware engineer with a compiler.

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

joakimk, 9600 baud with 1MHz clock is not going to work well (-7% error even if the 1MHz was exact). Try 4800 baud or use a higher frequency internal RC oscillator setting. You can also try the U2X bit in the UCSRA register (but reception is more sensitve to errors when using it so this might be less useful when running from the internal oscillator). Note that Dean writes above:

Quote:
Looking in your AVR's datasheet in the USART section you should see a table of common baud rates, system clocks and error percentages. You should find a combination which suits your project's constraints and has the lowest possible error percentage.
/Lars

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

Hi all!

Beeing a newbie to avr's, I've worked a while with serial data-transmission and the dmx-standard (rs 485) on fpga's. Now I'm trying to get it into an AVR..

Will the UDR-register will be empty after one transmission?
Is the data in UDR only being transmitted once?
Is it possible to assign a vector to UDR, or is the UDR a one-byte-protocol?

What I want to do is to send 512bytes in a everlasting
loop (of cource with the possibility to manipulate the register).

Thnx,
- Bernt.

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

I can't believe the amount of material I've learned in the last few days of experimenting with these AVRs. Thank you Dean for such a detailed tutorial on communicating over a serial port.

I received two MAX233ACPP chips a few years ago but I had no idea how to use them. Using your tutorial, modifying it for both the MAX233 and ATtiny2313, I've managed to implement your echo program running at 1200 baud using the 2313 internal oscillator.

Thanks!

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

Great svenasse! I'm glad my efforts weren't in vain. Good to also know that my code works - I wrote it "blind", without testing it thoroughly.

Hope you read my other tutorials also, as they cover what I believe to be interesting topics.

Cheers!
- Dean :twisted:

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

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

I couldn't understand why I was able to communicate with my chip at 1200 baud when it doesn't even show up on the list in the manual. It wasn't until I started to review the fuse did I realise the clock was being divided by 8 (9600/8 = 1200). Once I unchecked that option I was able to get to 9600 baud and then 38400 baud all while using the internal oscillator at 8MHz.

One point which wasn't in your tutorial was to disable hardware flow control since the DTR/RTS pins are not used. My eyes kept missing that option in Hyperterm until I had to play with the baud rate on the original code.

I will certainly be going through all the tutorials here... this site is absolutely awesome! I applied the tricks and tips in your "Setting up a WinAVR Project" and it shaved off more bytes off the compiled code.

Thanks,
Seamus

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

Very nice tutorial! This was my first AVR-GCC trial and it went pretty smoothly. Would love to know how to get this done with interrupts, I could really use that for my upcoming project! Keep up the good work!

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

thnx dean. i was really looking for this for a long. nice work

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

i copy n paste your code in avr studio with WINavr installed and set F_CPU+ 8000000 because i m using 8 MHz crystal oscillator. The code compiled successfully

Quote:

Build started 2.4.2007 at 17:15:36
avr-gcc.exe -mmcu=atmega8535 -Wall -gdwarf-2 -O0 -MD -MP -MT testgcc.o -MF dep/testgcc.o.d -c ../testgcc.c
avr-gcc.exe -mmcu=atmega8535 testgcc.o -o testgcc.elf
avr-objcopy -O ihex -R .eeprom testgcc.elf testgcc.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex testgcc.elf testgcc.eep
d:\WinAVR\bin\avr-objcopy.exe: there are no sections to be copied!
d:\WinAVR\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
make: *** [testgcc.eep] Error 1
Build succeeded with 0 Warnings...

But then when i execute this code i got a runtime error and the avr studio gets terminated. how can i resolve this problem???

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

Sounds like you have an out of date Studio then - your problem will almost certainly be resolved when you upgrade to 4.13.528 which IS compatible with the output files from WinAVR20070122

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

thnx clawson thnx very much my prob is solved u were correct

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

I am using a atmega8535 and the echo is not correct. For example, an 'm' returns a '[' every time. I measured the baud rate on the scope and it is perfect. The signal seems to be inverted between the Tx and Rx...Any ideas folks???

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

Are you using a MAX-232 level conversion chip? Without one the signal will be inverted, but also far too low for correct communication with true RS232 voltage devices. Not to mention that the computer's ~10V signal will destroy the AVR...

- Dean :twisted:

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

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

'm' = 0x6D = b01101101
'[' = 0x5B = b01011011

So it isn't inverted signals.

I usually see something like this with mismatched baudrates. Are you certain about the PC COM port baudrate? You need to check in the device manager to be sure.

Smiley

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

Thanks Dean and Joe,
I am using a board we had lying around and I assumed the level conversion hardware was inplace. What is that they say about assumptions? I was wrong and I have a MAX232 coming so I am sure it will work fine. Thanks for the turorial and the help...

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

hey freaks !

i get some errors when trying to compile my program.

this is the way the program starts:

#include
#include
#include
#include
#include

though, i get the message:

can't open #include file or
can't open #include file
end so on...
my program doesn't work from the start...and i can't even debug the rest of it..
please help!

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

IF YOU USE WINAVR:
Did you use the default WinAVR installation directories? If not you have to modify the makefile so that the includes can be found. It is easier to uninstall WinAVR then reinstall it allowing the default path.

Smiley

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

well this time I will try the avr studio compiler. but first I need to understand some things like what is this makefile. I am totally new to these compilers.
thank you for such a quick answer.

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

Hi all, i am using the GCC instead of winavr,
it comes out the error of define F_CPU..how do i know what is the value ? or how can i define it ?
i am using Atmega8515L ! thks

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

GCC *is* WinAVR, or specifically the former is a component of the latter (which is just a package of AVR tools).

You should define F_CPU in your makefile, and pass it along to each C file that is compiled via the -D option. That's how the WinAVR makefile template works, as it gives a common place to set the value for all C files in a project.

As an alternative, you can just #define it yourself at the top of the C files which use F_CPU.

- Dean :twisted:

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

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

Hi, I pretty much don't know anything, all i did so far was blink some LEDs and push some switches. This tutorial seems interesting. I'm using stk500, atmega16L, with avr studio. My questions are:

Do i need the max232 ship separately from the stk500? On the stk500 i can see max2c2.
Do i need to set anything up on the stk500?
How can i make my atmega16L run at 7.3728MHz, or any other frequency that will work for baud rate ? From the data sheet i read that the default is 1.0MHz.

Please explain in detail.

Thanks in advance.

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

The STK500 is a great platform to experiment with - you'd be hard pressed to manage to do something irreversable with it (with the exception of actually blowing something up!).

Yes, the SKT500 has a MAX232 on board already, but it's used for the "control" section of the board (for programming and such). Thankfully the MAX232 is dual channel in both directions, and so the designers have linked the second channel with the second serial connector (named "RS-232 Spare" on the board).

Setup is easy. If you look near the LEDs on the STK500, you'll notice a small two pin connector also named "RS-232 Spare". You need to use one of the STK500's two-wire jumpers to bridge those two pins to the correct pins for TX/RX on the port headers.

I *think* the correct pins are PD0/PD1 for your AVR, but do check the datasheet. Just connect your AVR's Tx and Rx to the Tx/Rx pins of that small header and it'll do the level conversions for you.

To communicate with your AVR once it's programmed, you'll need to swap over your serial connector from the "RS232 Control" socket to the "RS232 Spare".

As for running the AVR at a different clock rate, that's easy as well. The newer AVRs come running at a clock rate of about 1Mhz, via the onboard RC oscillator. However, you can change this to use an external __*CLOCK*__ (not crystal!) via the "fuses" tab in your programming window. Set the clock to external, any starup time.

Next, from the "board" tab of the STK500 programming screen, there should be a box for setting the clock speed of the STK500's target clock. Change that to the 3.XXX MHz one (it's half your wanted 7.3XXX MHz, but will work fine if you adjust your F_CPU value in your code).

Once you set the AVR to use the external clock, and have set the STK500 to give a nice magic frequency, the last thing to do is to set the STK500's jumpers to route the clock signal to the XTAL pins of your AVR. I'm not at home at the moment so I can't help you with that, but the STK500 entry in the Tools manual section of the help menu should give the details -- and if memory serves it's also listed on the underside of the STK500 board as well (OSC jumper I think).

Hope that helps!

- Dean :twisted:

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

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

Thanks :)
I got it to work.
Great tutorial, great help

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

Thank You for the great Tutorial and the follow up replies.

It made my first venture into the serial world painless.

I'm not a cartoon character but I play one in real life.

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

Great tutorial! Good work! However, it said the things I expected, but not the answer to my problem.

I have many years experience in embedded design, but this is my first trip with AVR.

I am trying to port a simple monitor routine I wrote 30 years ago and have used on many families of processor. Everything works as expected except that after writing the second byte to UDR, the UDRE flag never goes true again.

This was true in the AVR Studio simulator and I assumed that the simulation was not complete in this respect. However, after writing an endless loop to spit the same character and downloading to my mega8 chip, it sends exactly two characters after every reset and that's it.

I saw a note in the data sheet that says, "Note
that the TXC Flag must be cleared before each transmission (before UDR is written) if it
is used for this purpose." Does "cleared" require a set of the bit or a clear? I tried inserting sbi UCSRA,TXC and cbi UCSRA,TXC before writing to UDR, but neither made any difference.

Here is the code:

SendHex: ;Send a hex byte to the UART
sbis UCSRA,UDRE ;Wait for output register empty
rjmp SendHex
sbi UCSRA,TXC ;Set UART busy flag
out UDR,Temp0
rjmp SendHex ;Test loop
ret

Here is the initialization code:
;Set up USART
ldi Temp0,00 ;Select asynch mode
out UBRRH,Temp0
ldi Temp0,BR ;Select 9600 baud at 16 MHz
out UBRRL,Temp0
ldi Temp0,$18 ;Enable Rx and Tx
out UCSRB,Temp0
ldi Temp0,$86 ;Select 8 data bits
out UCSRC,Temp0
ldi Temp0,0 ;Disable double baud rate for 8
; MHz internal clock
out UCSRA,Temp0

Thanks for taking a look. I am very impressed by the degree of enthusiasm shown by the members of this forum. Perhaps I can submit something useful later.

Howard Speegle
howard@divaauto.com

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

You shouldn't need to play with TXC at all - just check that UDRE is set (so that the transmit buffer is not full) then write to UDR. If you do that each time, the transmission will halt until the UDR send buffer has space, then will send the byte for you.

Is there a specific reason you want to play with the TXC bit?

- 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 a strange problem in UART communication on ATMEGA8. I'm using external 11.0592MHz quartz oscillator. Using abcminiuser's example uC communicates with terminal only at 1/16 of declared speed in uC, i.e. when I set 19200 baud rate in uC, I must set 1200 in terminal to see the echo result. Same problem at 38400 and other speeds.
At the same speeds i don't see any results.
Maybe that is the reason of bad fuses configuration.
Below I attached screen from PonyProg with fuses config from my microprocessor.

Cheers!

Attachment(s): 

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

maros,

I'm not sure which way up Ponyprog displays the fuse bits (in the hardware 0=programmed and 1=unprogrammed in fact) but assuming a tick means =0 - that is programmed then your fuses seem to be in the default state which would mean that the mega8 is still operating at 1MHz from it's internal osciallator. (but that doesn't explain the factor of 16 you are seeing - what value are you actually putting in UBRR?)

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

Edit: Problem solved by setting proper CKSEL fuse bits.

Last Edited: Sun. Jun 10, 2007 - 11:22 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the USART tutorial, it's been a great tutorial for a newbie like me ;)

Anyway, just wondering, what is the correct echo result shown in hyperterminal window?
would the echo result display just once or several times ??
because in my case, when i type "A" once, the result in hyperterminal will show "AAAA" and sometimes "AAAAA"
so when i typed in "abc" it will echo back to me "aaaaabbbbccccc"

I just copy and pasted the code in this tutorial to my AVRSTUDIO then remove the URSEL part since I'm using tiny2313 chip with 4MHz external crystal clock.

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

Hi Guys,

I've used atmels a few times at uni and have a fairly good understanding of how they work. HOWEVER I have no idea with regards to serial communication! This tute looks pretty awesome, however, i'm not using the Atmega16 - instead i'm using the Atmega64 on the STK500 with the STK501 expansion board - however this doesnt matter at the moment, because I cant get the code to compile. I'm unsure as to what the "16UL" is in the following code snippet - as I think this may be where my problem is? Does the 16UL have anything to do with the mega16?

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

All i'm getting is a Syntax error before '=' token

 UBRR1L = BAUD_PRESCALE;

(and yes, I Do have a semi-colon on the previous line :wink: )

Thanks in advance for your help

Matt

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

Thanks for this USART tutorial Mr.Dean.
Could u please write a tutorial on Interrupts (how to use interrupts Efficiently)...

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

Sorry for the backlog everyone - I've been busy!

coolleo: Each character should only be displaying once. Is anyone else experiencing that phenomenon? I'll try this week to build the code and re-test myself as a sanity check.

mafroew: The 16UL isn't to do with the MEGA16, it's due to the way RS232 communication works. What you need to do is change the FCPU value in your makefile (or AVRStudio's project settings) to reflect the speed of the clock you're feeding into your MEGA64. As for the syntax error I can't see why that is, as the UBRR1L does exist on the MEGA64. I'd need to see the rest of your code.

prabu: See my follow up tutorial on Interrupt Driven Serial Communications, also in the tutorials forum.

- Dean :twisted:

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

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

well.. i figured out where I was wrong... I was tired and my code was extremly sloppy! Was using AVR studio to write the code, so the syntax highlighting (in particular brackets!) wasnt the greatest!

One quick question is, if I wanted to send a whole string to the hyperterminal, what would be involved? Also if I wanted to read in a string.. ie, if i typed "yes" or "no" and wasnt interested in the first letter, but wanted to compare the whole thing?

Actually, better yet, where would be the best place to look? I am keen to learn, and just having trouble finding the info on such things?

Cheers
Matt

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

Strings are nothing more than arrays of characters. Specifically, a string in C is just:

char SomeString[] = "Test!");

The array "SomeString" is now the characters that comprise the phrase "Test!", with a 0x00 (NULL) character at the end to act as a terminator.

You can use this fact and create your own SendString function:

void SendString(char* StringPtr)
{
   while (*StringPtr)
   {
      USART_SendChar(*StringPtr);
      StringPtr++;
   }
}

Assuming that you've got a USART_SendChar already made, of course. What that routine does is loop through each of the characters in a passed string, and if the character is non-zero (not end of the string) it sends the character, then increments the string pointer by one and repeats the process.

As for your other question, that's a little bit more involved. You need to create a buffer of characters, then create a routine to fetch in bytes from the USART into the buffer until the CR character is found (which ends a line). Upon receiving the CR character, you need to place a 0x00 terminator at the end of the loaded string, then use the functions in string.h to compare it against a known string you supply.

The best way to learn about this is via a good C book - any C book should cover strings quite extensively.

- Dean :twisted:

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

Last Edited: Tue. Jun 19, 2007 - 02:12 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How exactly do I connect the USART1 to hyperterminal if I'm using an ATMEGA128 in an STK501, on top of an STK500? Do I connect COM1 to "RS232 SPARE#2"? BTW I'm programming with a JTAG mkII. Do I connect to the device and click program to run the program on the chip?

I can't figure out why my code isn't working (see attached). My UDR1 register is always empty, even though the transmit complete register is flagged when something is stored to UDR.

Attachment(s): 

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

Several problems here. First get rid of the returns on lines 12 & 16. You
can't return from main, there's no where to go! Instead use a loop to self:

Done: rjmp Done

I realize in your example it's not really a factor since you stick in the send
routine, but it's a good practice to get into.

In your send routine you're not waiting for the transmission to complete before
sending the next byte. You do this by monitoring the udre bit in ucsr1a.

;****************************************************************
;       SendChar - Send the character in r16 to usart1          *
;****************************************************************
SendChar:
        push    r16                     ;save data
SC1:
        lds     r16,ucsr1a
        sbrs    r16,udre
        rjmp    SC1                     ;wait for xmit buffer empty
        pop     r16                     ;restore data
        sts     udr1,r16                ;send data
        ret
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am programming a Atmega644 using a STK500 board. I've tried to get the USART to work for about a week now when I found this tutorial (I've used Atmels PDF so far). It's a great tutorial. I can't find anything that I've done differently but I have a problem, the processor isn't transmitting anything!

My transmit-code looks like this:

void Transmit( unsigned char data)
{
if (UCSR0A & (1<<UDRE0)) /*if the buffert is empty*/
	{
		UDR0 = data;
		while( !(UCSR0A & (1<<UDRE0)))/*wait until transmitted*/
			}
}

I've connected the board's leds to the A-ports and discovered that the processor waits forever in the while-loop. I've looked at the A,B and C statusregisters in the loop and gotten these values:

USCR0A = 0b00000000;
USCR0B = 0b00011000;
USCR0C = 0b01001110;

My usart-init contains:

UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	UCSR0C = (1<<USBS0)|(3<<UCSZ00|1<<UMSEL00); 

and baudrate settings. I use the internal clock at 8 MHz. I know that I might get some problems in the future regarding the baudrate and all that, but right now I just want it to start talking...

Any idea why it doesn't transmit?

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

On a Mega16 I just use the following (working!) code:

void send_char(
	uint8_t 	c
){
        while (!(UCSRA & (1<<UDRE))); // wait till transmit Data register is empty
        UDR = c; // send the character
}

I don't see any reason to both top it and tail it. Either check for being ready to Tx before you load UDR or after but not both before and after.

Cliff

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

I tried to make an equivalent program for the mega 128, but it doesn't work. This is my first time using WinAVR so maybe I'm not running it correctly or something. Can someone please go through my code and offer some critique? thanks

Attachment(s): 

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

afit_intern,

In my universe 0x2F is 47. When I look at the mega128 datasheet and "Examples of baud rate setting" then the table for 1MHz and 2400 baud tells me UBRR should be 25. So where did your 0x2F value come from?

Also is this 1MHz the internal RC oscillator or a crystal? If the latter then good news, the AVR *will* be running at almost exactly 1MHz and, as that datasheet table tells us, you can expect 0.2% which is well within the allowable -2% to +2% range.

If the former then all the guarantee you have is that the speed is in a -10% (0.9MHz) to +10% (1.1MHz) range - which is a bit sad because UART comms only works in that -2% .. +2% range. So you may have a bit of a problem.

Luckily for you Atmel try to profile the internal oscillator in the factory (at 5V and 20degC) and put an OSCCAL adjustment value into the chip and this gets (in the case of the 1MHz oscillator) loaded into OSCCAL automatically. So you may be OK, but do bear in mind that the oscillator accuracy could be an issue for you. If UART use is your goal then buy a crystal (preferably one of the magic value ones)

Going back to your program - don't bother setting USR1C because 8-n-1 is the default in AVRs anyway.

Now it looks like your program is trying to read from one UART and write to another one (ReceivedByte = UDR0 and UDR1 = ReceivedByte) but you are only initialising UCSR1B and UBRR1 registers of UART1 - what happened to the setup of UART0 if you plan to read UDR0 into ReceivedByte ?

Also for the reception you are polling the RXC bit for UART1 but then reading the byte from UDR0. If the inbound channel really is UART0 then you want to be reading RXC for UART0

But otherwise it looks fine ;-)

Cliff

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

flexpeter,

Quote:

My usart-init contains:
Code:
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (1<<USBS0)|(3<<UCSZ00|1<<UMSEL00);

Are these correct? The 3 in the last statement looks suspect and shouldn't you use |= instead of = when setting or clearing multiple bits?

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

davef wrote:
flexpeter,
Quote:

My usart-init contains:
Code:
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
UCSR0C = (1<<USBS0)|(3<<UCSZ00|1<<UMSEL00);

Are these correct? The 3 in the last statement looks suspect and shouldn't you use |= instead of = when setting or clearing multiple bits?

The 3 tells it to set UCSZ00 and UCSZ01.

Since you don't care what the register previously contained and you want it to contain exactly the value shown, you use "=".

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

Dave,

Nope (3<<something) is perfectly valid. In fact it's a very useful technique. Usually when you use (1<<something) that's because you are just trying to set the state of a single bit. But in a lot of CPU control registers (and not just the AVR) the implementor will maybe have inclued a 2/3/4/or more bit field within the 8 bits. In that case, rather than setting each of the 4 bits (say) individually it would make sense to shift a number between 0 and 15 to the lowest bit position of the four.

Take timer clock prescalers for example, this normally consists of a 3 bit field with CS0, CS1 and CS2 bits. Say these bits were at bit position 4 (then 5 and 6) and you wanted to set the 101 (ie 5) bit pattern. It'd be far better to use (5<<CS0) than (1<<CS2)|(1<<CS0) I think.

A classic example I always quote is an LCD controller I programmed in an ARM. This had 16 bit wide control registers. The setup of the X pixel width was at bit position 5 or something. I thought (320<<5) to set the X width and (240<<5) to set the Y height made it far clearer that I was setting up for a 320x240 display panel than the setting of individual bits would have looked.

Also if you are setting all 8 bits in a register (and by implication any bits that you don't explicitly set wil be 0) then it's quite valid to use = rather than |=

(oh and it is = or |= when setting bits but to clear bits it would be =~ or &=~)

Cliff

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

dksmall,

Thanks for clearing that up, so you use |= when you do care.

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

Cliff,
Ah, using a bit pattern.

I had just got my head around using:

GIFR = 1<<INTF1; // clear any pending interrupts

ie clear by setting, and now here is another way to set up registers!

Thanks for the clarification.

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

Cliff, you're right, I just need to check once.
But that's not the reason why it isn't working, the second check doesn't prevent the USART from transmitting.

I've changed back and forth between internal and external clocking, could there be a problem with the DDR_XCK signal? The PDF mentions it but when I include it in the code (with and without index 0) the compiler has never heard of it.

Peter

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

cliff,
I normally had 0x19 for the baud rate.. I'm not sure what I was doing at the time. With the appropriate changes I still am not getting anything on hyperterm.
Int RC Osc. 1MHz is selected on my fuses page so I guess I need to find myself an ext. crystal soon. Is there anyway to verify the clock? This is something that I've been wondering for some time.
Attached is code. thanks!

Attachment(s): 

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

hmmm had to move jumper to short RXD and TXD. works now

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

abcminiuser wrote:
Strings are nothing more than arrays of characters. Specifically, a string in C is just:

char SomeString[] = "Test!");

The array "SomeString" is now the characters that comprise the phrase "Test!", with a 0x00 (NULL) character at the end to act as a terminator.

You can use this fact and create your own SendString function:

void SendString(char* StringPtr)
{
   while (StringPtr)
      USART_SendChar(StringPtr++);
}

Assuming that you've got a USART_SendChar already made, of course. What that routine does is loop through each of the characters in a passed string, and if the character is non-zero (not end of the string) it sends the character, then increments the string pointer by one and repeats the process.

- Dean :twisted:

Excellent tutorial, made it very easy to get it working. One question, I know this is really basic C stuff, but that's about the level I am at. I have made a function SendChar like this.

void SendChar(char data)
{
    while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
      UDR = data; // Send data to the computer
}

and when I send a character in the loop like this "SendChar(ReceivedByte);" it works fine. So now I want to use the SendString function that is shown above. But when I compile it I get a warning:-
../comms.c: In function `SendString':
../comms.c:15: warning: passing arg 1 of `SendChar' makes integer from pointer without a cast
and I tried to send a string like this

   char StringToSend[] = "Test";
   SendString(StringToSend);

I just get a continual string of unrelated characters being sent to the terminal. Can someone please help me get this basic function working?

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

I think it should be

void SendString(char* StringPtr)
{
   while (*StringPtr)
      USART_SendChar(*StringPtr);
   StringPtr++;
}

In order to send USART_SendChar the actual character and not a pounter to it... I think. Haven't done much with pointers yet.

Edward

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

Whoops! Quite right Edward, although you need braces around the while loop contents or you'll get an infinite loop. Working sample:

void USART_TxString(const char StringPtr[])
{
	while (*StringPtr != 0x00)
	{
		USART_Tx(*StringPtr);
		StringPtr++;
	}
}

Will correct 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

Thanks guys, that go it.

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

Problem solved, I just needed to change the init to:

  UCSR0A = 0x00; 
  	UCSR0B = 0x00;       
   	UCSR0C = 0b00000110; 
   	UBRR0L = 0x17;       
        UBRR0H = 0x00;        
    
   	UCSR0B = 0b10011000;

The change being double setting of the UCSR0B-reg. Now I'll use the code for sending strings, thanx!

Peter

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

actually, my mega128 program does not work. it only appeared to work on hyperterm when the RXD and TXD jumpers were shorted. This was only shorting the RXD to TXD so nothing was really being echo'd on the chip. I noticed this because I was unable to "erase" the echo program from the chip.

I think my Int. RC. Osc. @1Mhz is horribly off

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

i'm using atmega8535 and atmega16

i want to input character from computer
then it will execute led on,example in PORTA.0

if i input another character,it will execute another program,example led will off or whatever

i confuse for the C language code program....
anyone help me??

give me that code program....

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

ichwan_adhi wrote:
i'm using atmega8535 and atmega16

i want to input character from computer
then it will execute led on,example in PORTA.0

if i input another character,it will execute another program,example led will off or whatever

i confuse for the C language code program....
anyone help me??

give me that code program....

I am a beginner but maybe this will help. I am using an Atmega16. It waits for a single character command from the PC and then returns data to the PC. In this example it waits for an "S" from the computer.

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

void ConfigureDevice(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
}

int main (void)
{

   ConfigureDevice();

   char ReceivedByte;

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

      // if received an "S"
      if (ReceivedByte == 83) { 
           // do something here
           // turn on led or whatever you want

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

im very amateur with microcontroller

just want to ask
how to define RXEN,URSEL,RXC,TXEN
UCSZ0,UCSZ1 and FREQ_CPU??
because when i compile that source code,there an error with that symbol

is it true that i just write like this :

Quote:

#define RXEN 8
#define URSEL 8
#define RXC 8
char FREQ_CPU;
#define TXEN 8
#define UCSZ0 8
#define UCSZ1 8

when i write like that,it hasnt error
thanks...

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

Which C compiler are you using? And which AVR?

but to give you an idea here are the definitions of those things from one typical compiler for the mega16:

#define UCPOL   0
#define UCSZ0   1
#define UCSZ1   2
#define USBS    3
#define UPM0    4
#define UPM1    5
#define UMSEL   6
#define URSEL   7

#define MPCM    0
#define U2X     1
#define PE      2
#define DOR     3
#define FE      4
#define UDRE    5
#define TXC     6
#define RXC     7

#define TXB8    0
#define RXB8    1
#define UCSZ2   2
#define TXEN    3
#define RXEN    4
#define UDRIE   5
#define TXCIE   6
#define RXCIE   7

But note that this is for MEGA16 - it could well be different for the AVR you are using and you may find that your C compiler already defines all these things for you and it's just a matter of #include'ing the right .h file

Cliff

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

With the example I gave you I am using an Atmega16 and compiling with AVR GCC, I don't know anything about other compilers. I included these header files:-

#include 
#include 

The FREQ_CPU was defined in one of the header files as well but as it is shared with other projects that use a different clock speed I just defined it in my project.

#define FREQ_CPU 7372800
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hihi... i am a newbie here... thanks dean, i manage to build and connect the circuit as you written in the tutorial.. but one thing i not sure is how it is actually done? and wat i am supposed to expect out of the code that you write?
can u show me any examples to show that the pc and the ATMega 16 is able to communicate through MAX232???
thanks hope i asked something relenvant... correct me if i am wrong... not very sure how to express my problem...

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

The code should cause whatever you send through the USART to the microcontroller at the correct settings to be echoed back (repeated) to the PC.

You can check if your circuit is working by detatching the Tx/Rx pins of the AVR and shorting the MAX pins previously attached to those pins together. Shorting those two MAX232 pins should cause any data at any baud rate to be echoed back also, albeit without being received and re-transmitted by the microcontroller.

- Dean :twisted:

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

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

for clawson:
i'm using codeVision AVR
using AVR atmega16 and atmega8535..
is it same between atmega16 and atmega8535 to define allthings you write???

can i find that define in xxx.h in my compiler???

for Taipan :

do i have to write these header???

Quote:

#include
#include

what does this?

Quote:

#define FREQ_CPU 7372800

mean?

it must 7372800??

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

hi dean
jus to confirm, if i use ATmega 8 instead of ATmega 16, the code is also workable right? since the pins and controls are abt the same...
o and also to confirm 2nd thing, i have to add in some codes to transmit from the controller to the PC right? then how do i show it on the PC to confirm that the data send from my controller will be shown on the PC(computer i mean). izit must use a soft ware call basic stamp?

sorry to trouble u again... really enthu in this but dun really know where to start... :)

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

Well CV is unusual amngst the AVr C compilers in that the pre-written .h files supplied with it define the SFR register addresses but NOT the individual bit names. However all is not lost if you have AVR studio installed. It has a program call xmlconvert that can be used to generate a C .h file from the XML files in the Atmel tree.

C:\Program Files\Atmel\AVR Tools\AvrStudio4>xmlconvert
xmlconvert: No source file specified

Usage: xmlconvert [-f output-format] [-o outdir] [-1nbclV] infile ...
        Output formats: a[vrasm] | g[cc] | i[ar] | c[c] (generic c)
Options:
        -1  = Don't generate AVRASM2 #pragma's
        -n  = Don't warn about bad names
        -b  = use DISPLAY_BITS attribute to limit bit definitions
        -c  = Add some definitions for compatibility with old files
        -l  = Produce linker file (IAR only)
        -q  = Allow linked register quadruple (32-bit)
        -V  = print xmlconvert version number

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

ichwan_adhi wrote:

for Taipan :

do i have to write these header???

Quote:

#include
#include

what does this?

Quote:

#define FREQ_CPU 7372800

mean?

it must 7372800??


I have never worked with other compilers, only AVR GCC so I am not sure for your compiler. Those header files where part of the AVR GCC library. They should already be written for you. You may have to convert them as clawson has shown.

I defined my frequency to 7372800 because I am using a crystal of that frequency. You should change that to whatever frequency you are running.

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

Hi lewaltz,

First off, please don't use shorthand when writing your posts - it makes it difficult to read by non-native English speakers, as well as myself!

I checked and the MEGA8 is register-compatible with the MEGA16 at least, so chances are it'll work just fine. I can't see any real possible differences, apart from the URSEL bit which **MAY** not exist on the MEGA8.

The demo application just echoes back the sent bytes, so all you need is a terminal application on your computer which can send and receive serial data. HyperTerminal comes with Windows, but I'd suggest looking for Bray's Terminal, which is much nicer to use.

- Dean :twisted:

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

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

thanks dean, ok i will remember not to use shorthand when posting. i will do the research on your suggestion too...

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

Hello there, I'm new here and I'm not sure if this is the right place for this, but here goes:

I'm trying to make my ATmega32 talk to a HCMS-2922 LED display (datasheet here). Basically, it has a massive 320-bit shift register (one for each line!) that stores the state of each LED in the matrix.

Each character on the display consists of five columns of 8 LEDs each. Figure 2 on page 10 of the datasheet shows how the bits move through the display as they shift through the register. I have a table of characters, five sequential bytes per, that represent anything I would want to send to the display.

My problem is simple: stop bits. The data is sent via the USART in synchronous mode. It will insert at least one stop bit per character, knocking the whole register out of alignment. I'm pretty sure there's no way to disable them outright -- you can choose one or two, but not zero.

I was hoping one of you clever folks could help me to come up with a workaround -- preferably one that doesn't involve bitbanging a lonely pin somewhere :P

One idea I was toying with was kludging with 7-bit characters so that the stop bit always ends up on the unused 0th row of the matrix. What are your thoughts? Got any better solutions?

Also: if this post is offensively placed, feel free to move it to a more appropriate forum.

Thanks!

-Jarrett

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

Jarrett,

I think that application is ideally suited to the SPI interface instead of the USART.

- Luke

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

Doesn't the SPI have additional address bits that you have to worry about? Correct me if I'm wrong, of course... I haven't examined the SPI in quite as much detail as I have the USART.

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

TWI uses funky address bits. (It is actually a slightly imperfect replication of Phillips I2C bus.) I don't know enough about it to comment any further.

SPI, on the other hand, is a much simpler interface. In most ways, it's even simpler than the USART. The AVR implementation simply performs unframed synchronous transfers in 8-bit chunks.

I think this is too off-topic to go into very much more detail in this thread. I'd suggest taking this topic over to a new thread in the main AVR Forum if you have more questions.

- Luke

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

Ok, thanks. I will definitely look into that. I think I was getting the TWI and SPI mixed up (I haven't done a uC project since I was working on 68HC11s).

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

hi Dean

about your previous reply :"The demo application just echoes back the sent bytes, so all you need is a terminal application on your computer which can send and receive serial data."

to confirm with you, the sent bytes is it any data to be sent from micro controller to the computer?

after building the code that you have written, where should i add or write in your code to send or receive data? is it after this line?

while ((UCSRA & (1 << RXC)) == 0) {};
ReceivedByte = UDR;
//add function or data to send to computer?

i not really too sure what i have asked is it clear or not, but i guess i am confused by what i should write to send data to computer...

so can you help me with this, from your code, what else must i write or add, for an example to send and receive data, to your code?

#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

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

//???add or write code at this line to send data???

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

//???add or write code at theis line to receive data???
}
}

i hope to hear from you and learn more about it... so do correct me... thanks...

lewaltz

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

The microcontroller echoes back data sent from the PC - it's like a software crossover in the serial lines, in that anything sent from the PC is received by the AVR, then sent back to the computer. You can achieve the same result by shorting the Tx line of the serial cable with the Rx and vice-versa, but the point is to use the AVR's serial USART.

To receive data from the computer, you test the RXC bit in the UCSRA register - it's set when data has been received. You can then read in the byte sent from the computer from the UDR register.

To send data, you check to make sure there is space in the hardware transmit buffer, by seeing if UDRE is set in UCSRA. When it's set you can transmit a byte from the AVR to the computer by *writing* a byte to the same UDR register.

If you look at the application code, that's what it does - it loops, and when a character has been received it reads it into the temporary variable "ReceivedByte" and sends it back to the computer by writing it back to UDR when it is ready for more data.

- Dean :twisted:

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

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

hi Dean

sorry i was having my examinations during this few weeks and now i am focusing on the programming for my project...

i wanted to canofirm with you about the code that i have tried out but it turns out to be nothing... chould you help me to check if there is any error in my code?

i want transmit a char "S" from computer so that when (ReceivedByte == "S") it will turn off my LED (PORTC)

here is the code...

int main (void) 
{ 
   char ReceivedByte; 
   
   DDRC = 0xFF;  //	switch to output 
   PORTC = 0xFF; //     set to high, LED lights up

	//	Configure Device
   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


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

      //UDR = c; // send the character 
   
   }    
} 

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

Try this in your main, works for me

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

      // if received an "S"
      if (ReceivedByte == 83) {
           PORTC = 0x00;
      }
   }

I am not returning anything there, just receiving the character and switching the led's. If you need to return data to the PC you'll need to write something to UDR

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

lewaltz,

Your problem is the use of double quotes (") instead of single quotes (') around the letter S.

"S" means a string so the two bytes 0x53 (the actual letter S) followed by a 0x00 NULL string terminator will be placed in SRAm somewhere and the ADDRESS of those two characters will be used in the comparison. So only if the value in ReceivedByte happened to be the same as the SRAM address in memory where 0x53,0x00 were stored would the expression evaluate to be TRUE.

When you use 'S' on the other hand that just looks up the ASCII code for the symbol S (0x53 or 83) and checks if the value ReceivedByte is the same as this.

Similarly UDR="S" will not work. That too must be UDR='S'

Cliff

PS Of course the "== 83" in Taipan's solution is exactly equivalent to "== 'S'" - though the latter is more readable by the maintainer who later has to fix this code.

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

hi everyone...

thanks Taipan and Clawson... and i have learned my mistake... and the code is workable too... thanks a lot...

then Clawson, you said that if i want to return data to the PC i'll need to write something to UDR right?

you see if the code is alright or not...

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

}

second thing to confirm... "the special register named UDR" is this the one that is to wait for the computer to input the charater "S" in the previous code? i wanted to know more about this register UDR too...
thanks

:)
will*

hi wish to learn more about programming stuffs so do add me in msn for me to learn for you better... :)

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

Will,

I was merely noting that in the code you posted previously you had a line that said:

UDR="S";

and I was pointing out that you can't use a double-quoted string here (even if it is just apparently one character) but that you must use a quoted character:

UDR='S';

In your most recent post you had:

UDR="hello";

This most definitely will never work. If the intention is to send the 5 characters of "hello" then first you'll need a function that can send one character at a time:

void uart_send_char(uint8_t byte) {
  while ((UCSRA & (1 << UDRE)) == 0); 
  UDR = byte;
}

then you need a function that can send a string of characters:

void uart_send_string(char * str) {
  while (*str) { // keep going until NULL terminator found
    uart_send_char(*str++);
  }
}

and finally you would call that with:

uart_send_string("hello");

The compiler will arrange to put a copy of "hello" (followed by a 0) in SRAM somewhere and when it calls uart_send_string() it will pass it the address in RAM where that string is located. Inside uart_send_string the str variable is a POINTER to memory. It holds the address of bytes in memory. On entry to the function it will hold the address of the 'h' at the start of "hello". Using the pointer dereferencing operator (*) it will pick up whatever is in the location that str is currently pointing at (so the 'h') and pass this to uart_send_char() which will transmit the single character. The ++ will then increment 'str' to point at the next character in memory (so the 'e' now). Again this will be picked up (with *) and passed to uart_send_char(). And this process will continue for the "llo" that follows. After the 'o' the 'str' pointer will be incremented to the next memory address (that contains the NULL (0x00) that the C compiler will have added to the end of "hello") so this time the while(*str) will pick up a 0x00 value and while(0) terminates the loop and the uart_send_string function will return.

Cliff

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

In the MAX232 datasheet it says to use 1 uF caps. But the link you provided above (http://www.coolcircuit.com/circu...) says to use 10 uF caps. Which one should I use?

I'm assuming I should trust the data sheet and go with 1 uF caps.

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

datasheet has the correct info ofcourse!

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

I"m pretty new with the AVR
I basically just need to talk from one AVR to another using the USART. (atmega32)
Anyone can help?
Maybe sample code?

thanks

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

Quote:
Maybe sample code?

Am I missing something obvious or isn't sample USART code is what this tutorial is all about?

What do you think Smiley, is this a troll?

edit: Actually, on second thought, gotta be a troll, how could someone possibly post a question like that on this particular tutorial. Dean's tutorials are among the best anywhere. Jeez.

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

Hi! I'm a newbie and I'm trying tu run this piece of code on ATmega128 to understand USART utilization. It is based both on this tutorial and on the atmega128 datasheet.

#include 


/// Typedefs //////////
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;


#define FOSC 1843200// Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1


void USART_Init( unsigned int ubrr );
void USART_Transmit( unsigned char data );
void Delay (u32 count);

int main(void)
{
	int i;

	i = 10;

	USART_Init(MYUBRR);

	while (i)
	{
    	        USART_Transmit('a');
		Delay(20000);
		i--;
	} 
}

void USART_Init( unsigned int ubrr )
{
	/* Set baud rate */
	UBRR0H = (unsigned char)(ubrr>>8);
	UBRR0L = (unsigned char)ubrr;
	/* Enable receiver and transmitter */
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	/* Set frame format: 8data, 2stop bit */
	UCSR0C = (1<<USBS0)|(3<<UCSZ0);  
} 

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

void Delay(u32 count)
{
    while(count--);
} 

As you can see it is very simple, I only transmit the character 'a' for 10 times and then the program terminates. Though if I try to receive the transmitted characters with PComm I don't receive ten 'a' but ten 'ÿ'. Does someone see what I'm doing wrong?

Thanks in advance.

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

If the 128 isn't actually clocking at 1.843200MHz this would explain what you are seeing - so how sure of that are you?

(note that assuming you are building with optimisation turned on (and you should be!) then your Delay() loop will be optimised away - you are far better off using functions in fact)

By the way, personally, to set the baud rate I'd just use:

   /* Set baud rate */ 
   UBRR0L = 11; // datahseet value for 9600 at 1.8432

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

hi there, i have same problem with cgilson33 in using USART to communicate between each MCU (example atmega128 as master and 2 atmega8 as slave). i think this tutorial only communicate between MCU and PC, CMIIW. how to recognize each slave MCU? as i read the data sheet of atmega128 it can be handled by sending an address frame but i confuse how each slave MCU be addressed by master MCU?
it would be great if you can enlighten me by giving an example code.
thank in advanced

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

clawson wrote:
If the 128 isn't actually clocking at 1.843200MHz this would explain what you are seeing - so how sure of that are you?

(note that assuming you are building with optimisation turned on (and you should be!) then your Delay() loop will be optimised away - you are far better off using functions in fact)

By the way, personally, to set the baud rate I'd just use:

   /* Set baud rate */ 
   UBRR0L = 11; // datahseet value for 9600 at 1.8432

Thanks for your quick response...well, I set the clock frequency in the project configuration options, under the TAB "general", is that correct?
I don't know the functions...I started to use avrstudio only two weeks ago :oops: . I will have a look anyway...

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

Just configuring the project for 1.843200MHz is not sufficent. On the actual AVR you have to reprogram the fuses to say "stop using the internal ~1MHz and use this crystal I'm attaching instead" and then you have to wire up the 1.843200MHz crystal with some suitable capacitors. Otherwise your AVR is running at about 1MHz

(oh and because it's a 128 make sure you switch the state of the M103C fuse while you are at it otherwise it's not a meag128 it's a mega103 - maybe you already did this bit?)

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

clawson wrote:
Just configuring the project for 1.843200MHz is not sufficent. On the actual AVR you have to reprogram the fuses to say "stop using the internal ~1MHz and use this crystal I'm attaching instead" and then you have to wire up the 1.843200MHz crystal with some suitable capacitors. Otherwise your AVR is running at about 1MHz

Well, I admit this is a little too difficult for me...can you point out a link or something to explain how this must be correctly done?

clawson wrote:
(oh and because it's a 128 make sure you switch the state of the M103C fuse while you are at it otherwise it's not a meag128 it's a mega103 - maybe you already did this bit?)

If you are talking about the "Atmega103 compatibility Mode" fuse bit, it is not checked, therefore it should be an ATmega128 :) ! Anyway thank you very much for your help!

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

nice tutorial ..actually helped me knowing what may be the error in my atmega 8 uart communication

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

I have a question. Im working on initializing the serial port and simulating the program to make sure everything is working correctly. The odd thing that it isn't.

void serial_init(){
	//Enable transmitter and reciever
	UCSR1B|=UCSR1B|(1<<RXEN)|(1<<TXEN); 
	//Set to eight bit transmission
	UCSR1C|=UCSR1C|(1<<UCSZ1)|(1<<UCSZ0);
	//Set baud rate=9600 See chart in datasheet   for value. 
	UBRR1L=51;
	UBRR1H=(51 >> 8); 
}

The problem is that it appears UBRR1H is being written to regardless of the fact if Im doing it or not. It happens right as Im writing to UCSR1C. Im simulating it as an Atmega64 in AVR Studio.
EDIT: It's a bug in the simulator.

Quote:
When writing to UCSRnC, the value will be copied to UBRRnH unless bit 7 is set. This behaviour should not happen on devices that have separate locations for these registers. A workaround is to write UBRRnH after UCSRnC.

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

It's not a "bug" in the simulator it is a "known issue". It'd be a bug if you discovered some mis-behaviour that atmel HADN'T already documented in the user manual - but Atmel pre-empted you and the error here was you not reading the manual before using the product.

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

clawson wrote:
It's not a "bug" in the simulator it is a "known issue". It'd be a bug if you discovered some mis-behaviour that atmel HADN'T already documented in the user manual - but Atmel pre-empted you and the error here was you not reading the manual before using the product.

Known issue and bugs are the same thing. The only difference is that known issue sounds better. I hate semantic games.

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

Absolute rubbish. My car (even though it's a Porsche) cannot do 200 miles per hour. That is a "known issue" in the design. It is not a bug or a design flaw - the designers never intended that it should be able to do that. That's why they wrote a user manual and told me that it could do 0 to 161mph (one day I'll find out!)

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

i followed the tut and all i get is a bunch of squares and random symbols in hyper terminal.

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

Check your fuses. Most AVR's come with the fuses configured such that the AVR is running on its internal RC oscillator at approximately 1MHz.

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

Heh... I dont know what that means.. :D Im kinda new...

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

Hello?...

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

You waited almost 24 hours without bothering to search for the word "fuses" ?? Come on - show at least a modicum of effort to resolve it yourself.

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

I did search but i didn't find any relevant info or help that i needed...

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

http://electrons.psychogenic.com...

That was the first hit of a Google search using "AVR fuses" as the search term.

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

Is it possible to run the Internal Crystal at 3.686Mhz?
After reading that article, i am even more confused...

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

So is that the only article you read...even after I gave you the search terms to use ??? I won't be participating in this discussion any further.

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

Quote:

Is it possible to run the Internal Crystal at 3.686Mhz?
After reading that article, i am even more confused...

The AVR can accept a clock, crystal or resonator externally connected to the XTAL pins, at any frequency between the minimum and maximum rated clock frequency for the part (once the fuses have been set to use such an external clock source).

The internal oscillator will only run at whole number MHz, which may be selectable under your chosen AVR model via the fuses. However, many AVR models also has a tuning byte for the RC oscillator, which allows the frequency of the RC oscillator to be adjusted up to 10% IIRC higher or lower than the normal whole number frequency.

You can use a known external clock fed into an IO pin to perform such an adjustment. I've posted a code snippet here in the tutorials forum for calibrating the internal RC oscillator from 8Mhz to 7.37MHz via an external watch crystal for 115200 baud serial comms. If your AVR model has an option for a 4MHz internal RC oscillator, 3.68MHz is just inside the tolerance of the adjustment register.

- 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 have an Atmega8, so 4mhz is doable from the Internal Crystal.

Is there a tut here on this? Because I am still a little confused.

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

Possibly - you may need to fuse the CKSEL bits to pick a 4MHz internal oscillator and then use OSCCAL to fine tune it down to 3.6864. Or in more modern AVRs you can use CLKPR to switch between 1/2/4/8 and then fine tune the 4 down to it. But to calibrate the int. osc. for 3.6864MHz (or any of the "magic" frequencies) you will need an external timing reference and, if you have one of those, why not just make it a 3.6864MHz crystal anyway and set the fuses for using that?

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

hello guys. this is a useful site. :D
i am new to this world and i am really interested.
the problem is that i have small no of parts to do with.
(atmega162 - small ISP programmer and some small electric parts (R,C,..) - i programmed my first led program and i was happy. now im just reading over and cant do.
Is there a way to replace the MAX232 whith some sort of circuits.!!
i am sorry because i cant get any tools (LCD, MAX,..). :cry:

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

adbush,

This is a (very!) long shot but I know that one of the AVR dev boards that is for sale on the internet has its schematics online and just uses a couple of transistors for the inversion/voltage protection - you could borrow that part of their design - or rather you could if only I could remember which one it was. But if you Google around a bit "AVR development board schematic" (kind of thing) you may hit it.

Cliff

EDIT: Unbelievable! I found it - look to the lower left of this:

http://www.olimex.com/dev/images...

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

The butterfly does that, too. And the butterfly schematic is online, too. But unless you are doing huge volumes there is really no reason to skip the MAX232. It is cheap and easy to use. It also allows full duplex communication, while the "voltage-stealing" capacitor-transistor combination only allows for half-duplex communication.

Stealing Proteus doesn't make you an engineer.

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

thanks for reply..

Quote:
Unbelievable! I found it

i got the link. as you said it just use transistors, diodes C and R.
it may deserve a try but can take time. thanks..

Quote:
there is really no reason to skip the MAX232. It is cheap and easy to use

its not a matter of money , i just can't find it in my country ..

Quote:
The butterfly does that, too

i am seeking it from the net..
oh i get it from the user guide. thanks..

but really i hope i can find such a kit or board. finally i am software duy and i rarely like to touch with electronics. 8)

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

I just applied your code and source code in atmega8 datasheet. I wanna let the atmega8 control the logic probe in Proteus. Could anyone tell me? What is my mistake?

#include

#define FOSC 1843200// Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
int main (void)
{

UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRB |= (1 << RXEN) | (1 << TXEN); // Turn on the transmission and reception circuitry
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes - URSEL bit set to select the UCRSC register
UBRRH = (unsigned char)(MYUBRR>>8);
UBRRL = (unsigned char)MYUBRR;

while ((UCSRA & (1 << UDRE)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
UDR = 0b01010101; // Send out the byte value in the variable "ByteToSend"
}

[/img]

Attachment(s): 

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

It'd usually be this line:

#define FOSC 1843200// Clock Speed 

(your schematic shows no sign of a crystal on pins 9/10 and even if there is one have you programmed the fuses to use it?)

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

Hi!

A newbie question:
I would like to send numbers > 2^8 via USART
Is there some tricks to make this work when dealing with 8-bit data packets?

Lets say I would like to send the value 12500 to my computer. Do I have to split it into 5 and send '1', '2', '5', '0', '0' or is there a more fancy way

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

Helga wrote:
Hi!

A newbie question:
I would like to send numbers > 2^8 via USART
Is there some tricks to make this work when dealing with 8-bit data packets?
Lets say I would like to send the value 12500 to my computer. Do I have to split it into 5 and send '1', '2', '5', '0', '0' or is there a more fancy way

Each number you send via a UART is normally encoded in a sequence of 8-bit bytes. You can send 12500 as: ASCII: '1', '2', '5', '0', '0' or HEX: 30,d4 or any other number coding system your communication protocol wants to use. Its all 'code' for the number and it is all totally subjective. Many folks choose HEX for shorter transmissions, while other folks choose ASCII so they can more easily read the transmission themselves.

Smiley

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

hi

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

abcminiusers excellent tutorial: USART - Using interrupt...
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=48188

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

nice tutorial

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

Hi

My apologies for such a basic question but whenever I try to compile the code from the tutorial I get the following:

Quote:
Build started 9.3.2008 at 19:52:00
avr-gcc.exe -mmcu=atmega1281 -Wall -gdwarf-2 -Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT Test.o -MF dep/Test.o.d -c ../Test.c
../Test.c: In function 'main':
../Test.c:10: error: 'UCSRB' undeclared (first use in this function)
../Test.c:10: error: (Each undeclared identifier is reported only once
../Test.c:10: error: for each function it appears in.)
../Test.c:10: error: 'RXEN' undeclared (first use in this function)
../Test.c:10: error: 'TXEN' undeclared (first use in this function)
../Test.c:11: error: 'UCSRC' undeclared (first use in this function)
../Test.c:11: error: 'URSEL' undeclared (first use in this function)
../Test.c:11: error: 'UCSZ0' undeclared (first use in this function)
../Test.c:11: error: 'UCSZ1' undeclared (first use in this function)
../Test.c:13: error: 'UBRRL' undeclared (first use in this function)
../Test.c:13: error: 'F_CPU' undeclared (first use in this function)
../Test.c:14: error: 'UBRRH' undeclared (first use in this function)
../Test.c:18: error: 'UCSRA' undeclared (first use in this function)
../Test.c:18: error: 'RXC' undeclared (first use in this function)
../Test.c:19: error: 'UDR' undeclared (first use in this function)
../Test.c:21: error: 'UDRE' undeclared (first use in this function)
make: *** [Test.o] Error 1
Build failed with 16 errors and 0 warnings...


I am very new to WinAVR and AVR Studio and am trying to get the code to compile for the ATMega1281 – can someone help me out?

Thanks :D

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

Ah – yes that was a monumentally stupid question as the tutorial was written for the Mega16 not the 1281! Sorry

Does anyone know the equivalent for the 1281’s hardware perchance? Cheers :)

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

It should be all the same for just about every AVR flavour. The only differences you'll see would be the lack of the URSEL bit on some AVRs, the moving of some of the bits around to different control registers and the renaming of the registers to have the USART number after it on modern AVRs. For example, UCSRB would be named UCSR1B on modern AVRs.

Check the datasheet for the bit names and ensure they haven't moved to a different register on your AVR, and just add in the "1" postfix to all the USART register names.

- Dean :twisted:

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

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

Thanks Dean :)

If the URSEL bit is lacking from the 1281 (It seems to be) what do I use in its place?

UCSR0C |= (1 << URSEL) | (1 << UCSZ00) | (1 << UCSZ01); // Use 8-bit character sizes

The other two bits are now set correctly (I think) but I’m not sure what to change URSEL to…

FR

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

FR,

URSEL is maybe not obvious but in the older AVRs the UCSRC register and the UBRRH register were actually at the same IO address to that 7th bit had to be set to say you were writing to UCSRC and not UBRRH (the 7th bit would never be set in UBRRH as that would be a HUGE, useless baud divisor!). In later AVRs with more registers in their IO space Atmel have split UCSRC and UBRRH into two register.

Bottom line is you can ditch all mention of URSEL when programming UCSRC on your modern AVR.

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

Hi

Well I have modified the code to use the 1281 and it seems to receive and then echo back something! Hooray! Sadly all I get back is special characters (though its the same number of special characters as contained in the originally sent message)

Could someone tell me if there is anything screamingly obvious in my code that shouldn’t be there?

Thank you all very much – I’m so close to getting it working – but yet so far!

Quote:
#include

#define USART_BAUDRATE 4800

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

int main() {

char ReceivedByte;

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

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

for (;;) // Loop forever
{

leds_off(LED_RED);
leds_off(LED_YELLOW);

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

gpio_setState(TxRxSw,1);
while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Do nothing until UDR is ready for more data to be written to it
leds_on(LED_RED);
UDR0 = ReceivedByte; // Echo back the received byte back to the computer

}
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define BAUD_PRESCALE (((1000000 / (USART_BAUDRATE * 16UL))) - 1)

assumes the CPU is clocking at exactly 1MHz - is it?

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

ahh that’s a good point, its actually 4MHz – but it still comes through scrambled, as for if that number is exact I don’t know - what’s the best way to find out?

FR

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

Well if you are using a piece of quartz the chances are it is 4000000 with an inaccuracy of just something like 50 ppm. If you are using the internal oscillator then it's probably something between 3,600,000 to 4,400,000 while, for accurate UART, only 3,920,000 to 4,080,000 would have any hope of working (IOW the clock has a +/-10% inaccuracy but UART comms needs less than +/-2% inaccuracy)

The bottom line of all this is if you want accurate UART comms use a crystal (or find someway to calibrate the internal oscillator to a known timing reference)

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

Ok, I have scoped the CPU Clock and it comes out at 4000000 kHz :)

The CKDIV8 fuse bit is set and so I calculate the clock speed as 500000kHz – this combined with the alteration of:

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

To

#define BAUD_PRESCALE (((CPU_CKR / (USART_BAUDRATE * 8UL))) - 1) 

And hey presto I get something readable out of the USART :D

Thank you so much for all of the help you have given :D

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

I want to make a serial interface of ATmega8 with PC.
using the process given here.
What changes I have to make , as here ATmega16 is used?

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

im having a problem just compiling the first part of the walkthrough where you initialize the UART. says i must declare UCSRB first and TXEN and RXEN. Any Advise??

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

Quote:

I want to make a serial interface of ATmega8 with PC.
using the process given here.
What changes I have to make , as here ATmega16 is used?

Quote:

im having a problem just compiling the first part of the walkthrough where you initialize the UART. says i must declare UCSRB first and TXEN and RXEN. Any Advise??

In both cases I'll have to quote myself from the last page:

abcminiuser wrote:
It should be all the same for just about every AVR flavour. The only differences you'll see would be the lack of the URSEL bit on some AVRs, the moving of some of the bits around to different control registers and the renaming of the registers to have the USART number after it on modern AVRs. For example, UCSRB would be named UCSR1B on modern AVRs.

Check the datasheet for the bit names and ensure they haven't moved to a different register on your AVR, and just add in the "1" postfix to all the USART register names.

- 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 also need to display an array on a PC using 232 .So can I just use a for loop and say USART_Transmit(data[k])?
I tried doing that , but it gave me only 5 characters and that too random instead of the 20 I was expecting :(

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

You probably need to convert the data being passed over UART from binary (as held in data[]) to ASCII numeric strings that a human being can interpret. In C you'd use itoa(buffer, value, 10) or sprintf(buffer, "%u", value) or something and then have a UART_Send_String() routine that will send all the characters in the buffer[] string array.

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

Hey all, I need some help with the circuit it self. I am out of ideas. I have followed the directions for connecting the MAX232 exactly and checked it many time but cannot get serial comm. I am using the STK500 dev board and have it set up like this: Basic serial com through USART0 (PD0=Rx and PD1=TX) on my Atmega164p. That works perfectly. I then hook up my max232 compatible chip as described but get nothing. For reference, I am using the ST232A for the line driver. As far as I can tell, it is compatible with the standard MAX232. The only differences I can see is that it's datasheet specifies that .1uF caps will work and that +V has a cap between it and Vcc instead of ground (I have tried it both ways). Just to note, I am using ceramic disk caps instead of electrolytics. Can anyone think of a reason that this is not working assuming that it is at least wired exactly as described in this article? Please help, this is driving me nuts.

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

Does the RS232 spare port on the STK500 also use the voltage converter? I say this because there is a RXD and TXD header.

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

AVR Studio Help has a STK500 schematic.

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

Actually, I found out what was going on, even though every other schematic I have seen does not have it, the schematic on the STK500 shows a connection between pins 7 and 8 and a connection between ping 4 and 6 on the DB9 connector. Once I connected those, it worked. I also noticed that sometimes, when the MCU is connected to the SPI programming port, the comm does not work unless you press the reset once (well, at least with the comm circuit, the ST232 chip, on a separate breadboard). And, ya Salgat, the STK500 does you a MAX chip.

SteveN, although I found the schematic and learned about it before I saw your post, you were right on, so thank you!.

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

Here's a stupid question for you guys, what does the UL beside the 16 in the following line represent?

Quote:

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

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

Unsigned Long. It indicates that the "16" should be treated as 32 bits wide, rather than the normal 16 bits (by default constants are ints in size unless otherwise indicated). By expanding the size, it prevents overflows when performing the intermediate calculation of BAUDRATE * 16.

- Dean :twisted:

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

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

Wow, very speedy response. Greatly appreciated. Thank you very much. :)

Also, when I try to compile, the F_CPU part is giving me an error. Is that something I have to define manually?

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

I had to, but it was easy. 20MHz = #define F_CPU 20000000

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

Quote:
#define F_CPU 20000000

I guess you meant:

#define F_CPU 20000000UL

(though it may be better to use a -D in the Makefile so it can be seen across all the project files)

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

Hey, I was just wondering how you send out serial streams of data, for example an RS485 or RS232 Data stream has a start and stop bit, and delay frame before the data. So for example, lets say I have an array of 20 bytes, and I want to repeatedly send them out over USART, how would I do that?

Would I just load UDR with the first byte, and then the second and so on?

Thanks,
Dan

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

Dan,

Indeed, if you place the UDR in a loop and send it individual chars (checking that the UDR is ready for more data between chars you will get a stream of bytes over your chosen medium (assuming your chosen communication method is set up correctly)

void sendStream(char c[], int length) {

int i;

for (i = 0; i < length; i++) {
  while ((UCSR0A & (1 << UDRE)) == 0) {}; 
  UDR = c[i];
} // for

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

I have a question now: :)

What’s the best way to tell if a multiple byte message has been revived in its entirety if you don’t know the number of bytes contained within it, or the message’s end of packet character? – In fact is there a way?

I was thinking that if the UDR register is empty for a select period of time (a very small period of time) this would indicate that the reception has finished – if that is true how would you check this?

while ((UCSR0A & (1 << RXC0)) == 0) {}; // Do nothing until data have been received and is ready to be read from UDR

This surely only deals with singly bytes and not entire multi-byte messages. Or does it wait for a few milliseconds before releasing to ensure that the reception is indeed at the end of the message apposed to at the end of the current byte?

Many thanks

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

Quote:

What’s the best way to tell if a multiple byte message has been revived in its entirety if you don’t know the number of bytes contained within it, or the message’s end of packet character? – In fact is there a way?

Usually you'd design a protocol which sends the total message length at the start so that the receiver can keep count.

- Dean :twisted:

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

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

Indeed, sadly I have not designed the protocol I am receiving data in and for the time being cannot tell what it contains, any other suggestions for how to tell if the UDR has finished all Rx of a given stream?

Cheers :D

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

Can you calculate the elapsed time it takes to receive a character (function of BAUD rate)? I had a similar problem once and solved it by starting a timer upon receiving the first character. Each time a character was received I would reset the timer. If the timer overflowed then I said the transmitting device was finished. I allowed a little extra time for the transmitting device having to reload and discrepancies in BAUD rate and such. It worked quite well :-) .

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

Ah that’s a clever idea! Though I haven’t used timers before, how would one implement a timer?

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

Quote:

Ah that’s a clever idea! Though I haven’t used timers before, how would one implement a timer?

Me to the rescue!

http://www.avrfreaks.net/index.p...

- Dean :twisted:

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

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

Thx

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

Hi,

Thanks for the tutorial! Have a problem though. The only way to make the examples work I have to set the communication to bytesize=7. And then it works.

Wanted to get "normal" 8 bit bytes though so tried all combinations of comm settings, reading/writing signed/unsigned chars, no matter what I do (except for setting it to bytesize=7) the computer receives back from the avr the most significant bit set to one (I write 'a', I get '\xe1', I write 'b', I get '\xe2', etc.).

So is this how it is supposed to be or am I messing something up?

Thanks for your help!

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

The 7 bit mystery turned out to be quite interesting. Not that I have resolved it :cry: but setting the byte size to 7 on the PC side (on the avr side it is set to 8!) lets me send "flawlessly" data across at 460800bps without an external crystal.

Here is my setup - attiny2313 whose USART lines are connected to a FT232RL which is connected to the USB of the PC. The avr is running on its internal oscillator at 8MHz (the "divide clock by 8" fuse is unprogrammed, so it's 8MHz).

The avr is running:

#include 
#include 

int main(void) {
    UCSRB |= (1 << RXEN) | (1 << TXEN);   // Turn on Tx,Rx
    UCSRC |= (1 << UCSZ0) | (1 << UCSZ1); // 8-bit data !!!
    
    //UBRRL and UBRRH are 0, datasheet says - 0.5Mbps
    
    UCSRB |= (1 << RXCIE); // Enable USART_RXC
    sei();
}

ISR(USART_RX_vect) {
    char ReceivedByte;
    ReceivedByte = UDR; // Fetch 
    UDR = ReceivedByte; // Echo back
}

The PC is running a Python script which takes a file name as a single parameter:

#!/usr/bin/python

import sys
import serial

ser = serial.Serial()
ser.port = '/dev/ttyUSB0'
ser.bytesize=7
ser.baudrate = 460800
ser.parity='N'
ser.stopbits=1
ser.xonxoff=0
ser.rtscts=0
ser.open()

if len(sys.argv) < 2:
    print 'need existing file name'
    sys.exit()

my_file = file( sys.argv[1] )

while 1:
    line = my_file.readline()
    if line == "":
        my_file.close()
        break
    ser.write( line )
    sys.stdout.write( ser.readline() )

ser.close()

So this way I can send pretty big (>2MB) files of lower ascii text without a glitch with pretty high speed running on the avr's internal oscillator. And here is the interesting part. If in the Python script above I say:

ser.bytesize=8

(the way it should be and the way the avr is set) the maximum ser.baudrate could be is

ser.baudrate = 38400

and anything greater is messed up pretty bad. So I was able to run it with bytesize=8 after all :lol:

I guess this is some sort of undocumented corner case (who would want to run both ends of the connection with diff. bytesizes) but it is interesting that the avr could go stable at this high speed without a quartz and with the correct bytesize it would die at speed >10 times lower (which is the way how it should be according to the docs)...

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

pepper_bg wrote:
The 7 bit mystery turned out to be quite interesting.
Not really.
Quote:
The avr is running on its internal oscillator at 8MHz (the "divide clock by 8" fuse is unprogrammed, so it's 8MHz).
Use an external crystal.
Quote:
I guess this is some sort of undocumented corner case
I don't think so. See page 130 of the datasheet.

Stealing Proteus doesn't make you an engineer.

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

Wow, amazing how much people know in this forum... And how well Atmel documents their stuff (not that I got this one from first reading)... Thanks for pointing it out!

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

Hi!! I want to send a string of character, for example an AT Command "at+csca=". How can I do it? I have to send character by character? Thanks!!

I've tried to compile code and I gets this error:
"../serial.c:21: error: 'URSEL' undeclared (first use in this function)"

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

You also need to read the text that goes along with the code. Specifically, the part that mentions that the URSEL bit is not present on all AVRs, and should be omitted on those which do not have it.

- Dean :twisted:

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

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

I've already readed it. I'm using an ATMega32 wich have this bit. Igets a list of error and I only copy the firs. The errors:

Quote:
../serial.c:21: error: 'UCSRC' undeclared (first use in this function)
../serial.c:21: error: 'URSEL' undeclared (first use in this function)
../serial.c:22: error: 'UBRRL' undeclared (first use in this function)
../serial.c:22: error: 'F_CPU' undeclared (first use in this function)
../serial.c:23: error: 'UBRRH' undeclared (first use in this function)

Any idea?

I'll try to read all pages looking for sending strings, but my English is'nt very good. Thanks.

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

Ommit URSEL. The others require the USART number to be added:

UCSRC = UCSR0C
UBRRL = UBRR0L
UBRRH = UBRR0H

And F_CPU should be defined in your makefile.

- Dean :twisted:

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

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

-Ommit URSEL?? Sorry but I don't understand.

What doy you mean whit this?

Quote:

UCSRC = UCSR0C
UBRRL = UBRR0L
UBRRH = UBRR0H

Where can I find my make file??

THANK YOU very much. I'm so beginer...sorry.

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

Ommit = remove. Just remove the (1 << URSEL) from the code.

Quote:

What doy you mean whit this?

Quote:
UCSRC = UCSR0C
UBRRL = UBRR0L
UBRRH = UBRR0H

Those are the appropriate new names for those registers on your AVR.

The old Atmel naming scheme for AVRs with a single USART was [Register Name][Register Postfix]. That meant that the first control register was named UCSRA for example. Since then Atmel changed it so that the format is [Register Name][USART Number][Register Postfix], with the single-USART devices having one USART numbered USART 0.

That means that you need to add the "0" to the register name, before any postfix.

Chances are you're using AVRStudio. If so, FCPU can be set in the project options screen (first tab, down the bottom).

- Dean :twisted:

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

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

Thank you I'll try it.

What about sending strings of characters? I think thak can put all characters into a string an send it, one by one usig a bucle, is it rigth? Thanks again.

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

Quote:

I think thak can put all characters into a string an send it, one by one usig a bucle, is it rigth?

I've no idea what the last part of that sentence says. You can send strings with a loop, each time loading in the next character into the UDR (or UDR0) register and waiting for the transmission complete flag, OR by loading in the next character while the UDR Ready bit is set.

- Dean :twisted:

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

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

OK i want to say what you have written. Thanks

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

Hi

I am having a little trouble with my code with regards to sending chars using the UDR register. In this code I am using a GPIO pin to control whether I an sending or receiving (PE3):

int sendChar(char c) {

    // Set TxRx (GPIO8) Pin High (Send)
    PORTE = (1<<PE3);

    while ((UCSR0A & (1 << UDRE0)) == 0) {}; 
    UDR0 = c;
    while ((UCSR0A & (1 << UDRE0)) == 0) {}; 
    
    // Set TxRx (GPIO8) Pin Low (Recieve)
    PORTE = (0<<PE3);

    return 1;

} // tcBufferPutChar

The problem I am having (I believe) is that the program halts on one of the while loops and refuses to continue. I need two while loops in there as the URD register has to have finished sending it’s data before I turn the Tx pin off. Oddly it will execute this code once – but then wait forever on one of the while loops.

Does anyone have a better way of doing this or any suggestions to improve the above method? :)

Many thanks
FR

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

Thanks for the great tutorial, I do have a few questions,

It seems easy to send one or a few bytes out over USART, but lets say I have a 10 byte array and I want to continuously send that array to another micro-controller, I would send the first, second, third.... bytes and so on, and then when I was done sending them, repeat the process. How would the receiving controller know that the data is repeating. Is this done with idle time, or a break? and how would this be implemented?

I am trying to replicate a DMX512 signal, that looks like the signal on this page
http://www.dmx512-online.com/pac...

Thanks

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

hi guys how can i interface an avr studio to create an ohmeter

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

can any one try and explain to me hand assembly please.....

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

Hi there, I need help, I tried to write a program for communication between PC and ATMEGA8535. here is the code:

Quote:

#include
#include

/* Prototypes */
void USART0_Init( unsigned int baudrate );
unsigned char USART0_Receive( void );
void USART0_Transmit ( unsigned char data );

/* Initialize UART */
void USART0_Init(void)
{
/* Set the baud rate */
UBRRL = 0x19;
//I use 4 MHz crystal, and I want the baudrate to be
//9600, and then the UBRR should be 25, am I right?
UBRRH = 0x00;

/* Enable UART receiver and transmitter */
UCSRB = ( ( 1 << RXEN ) | ( 1 << TXEN ) );

/* Set frame format: 8 data 2stop */
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);

}

/* Read and write functions */
unsigned char USART0_Receive( void )
{
while ( !(UCSRA & (1<<RXC)) );
return UDR;
}

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

void port_init(void)
{
PORTA = 0x00;
DDRA = 0x00;
PORTB = 0x00;
DDRB = 0x00;
PORTC = 0x00;
DDRC = 0x00;
PORTD = 0x00;
DDRD = 0x02;
}

//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
USART0_Init();
MCUCR= 0x00;
TIMSK= 0x02; //timer interrupt sources
GICR= 0x00;
SEI(); //re-enable interrupts
//all peripherals are now initialized
}

//
void main(void)
{
init_devices();
for(;;)
{
USART0_Transmit ('a');
while(1);
}
}

from the code above, the problem is that the data received at the PC is wrong. what could possibly the the cause of this problem? I thought the MAX232 i used was damaged, so I've replaced it with a new one, and there are no mistakes with hardware connection. Thanks a lot..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
/* Set the baud rate */ 
UBRRL = 0x19; 
//I use 4 MHz crystal, and I want the baudrate to be 
//9600, and then the UBRR should be 25, am I right? 
UBRRH = 0x00;

You may well have a 4MHz crystal attached to the AVR but how sure are you that is is enabled? Have you set the relevant fuses?

(the value 0x19 is correct for 4MHz/9600)

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

Thanks Clawson for the reply, I use external crystal, not internal crystal.

how about the timer? should I enable the timer on the AVR when I want to use its serial?

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

When you say "I use external crystal" do you mean:

(a) I have wired an external crystal with capacitors to the XTAL1/XTAL2 pins

OR

(b) I have wired an external crystal with capacitors to the XTAL1/XTAL2 pins AND I have enabled the use of it by also setting the CLKSEL clock fuses and also making sure that CLKDIV8 is not set

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

btw, did you mean fuses bit that written on its datasheet? I never configure it, I burn the program into AVR using ponyprog, and there is an option to configure its fuse bit, but i never configured it. Because I think that without configure the fusebit, i wrote a few other programs on the AVR such as external interrupts, timer, etc, and it works out except for serial, does it affect?

Last Edited: Thu. May 29, 2008 - 12:06 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Then that's your problem. Just wiring a crystal to the pins has NO EFFECT whatsoever. The AVR continues to clock from the (inaccurate) internal oscillator at a default of about 1MHz. The crystal you have attached only gets used once the CLKSEL fuses are set and CLKDIV8 (if present and enabled) is cleared.

That's what makes this FAQ#3 below!

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

I see, here I attached a picture regarding these configuration bits, which one should I check and which one I shouldn't check? please help me out, thanks a lot Clawson

Attachment(s): 

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

OMG.. thank you very much Clawson, I configured its fuses bits with refer to its datasheet, and it works out, great job Clawson. :D FAQ #3 is true :P

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

Well personally I hate Ponyprog as it's never entirely clear whether a tick means "enable or disable this fuse function" and you have to be VERY careful when programming fuses as if you get it wrong you can lose contact with the AVR. I even think Ponyprog has an option to switch the interpretation of the ticks which makes it actually more confusing.

So I'd start by clicking the right hand [read] button on that. As you'll read in the datahseet (tables 98/99) the default fuse settings are:

S8535C unprogrammed
WDTON unprogrammed
SPIEN programmed
CKOPT unprogrammed
EESAVE unprogrammed
BOOTSZ1 programmed
BOOTSZ0 programmed
BOOTRST unprogrammed

BODLEVEL unprogrammed
BODEN unprogrammed
SUT1 unprogramed
SUT0 programmed
CKSEL3 programmed
CKSEL2 programmed
CKSEL1 programmed
CKSEL0 unprogrammed

Now if you consult tables 4 and 5 I'd say that for a 4MHz crystal oscillator and the slowest startup possible (always wisest) without BOD enabled (which is the default - though you may want to consider changing later) that what you are aiming for is

change SUT1 state
change CKSEL3 state
change CKSEL2 state

Cliff

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

Hi
i tried simulating my code in the AVR studio first. UCSRC and UBRRH always seem to contain the same values. I then copy-pasted the code u have provided in the tutorial and the same thing happened. Any comments? Please help me out on this.

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

Quote:
i tried simulating my code in the AVR studio first. UCSRC and UBRRH always seem to contain the same values. I then copy-pasted the code u have provided in the tutorial and the same thing happened. Any comments? Please help me out on this.

read your datasheet about URSEL and the special access requirement needed to read UCSRC. As you'll see there's NO WAY the simulator/debugger could show it's value. If you really don't trust the value that you have written to it then write a code seqeunce to do the double read into a variable then inspect that variable/register. But why don't you believer your write to UCSRC (with URSEL set) is working anyway?

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

hm...it seems I cant make this one work...
I have tried everything, changed clock speed, change tx/rx ports, but program just hangs here:

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

I have atmega16L, tried with f_cpu 1000000UL, tried with 7372800UL, but nothing, even hyperterminal hangs for couple seconds when I send something from it. On the other hand, I tried
http://www.nongnu.org/avr-libc/u...
and I got serial connection...so I suppose cables and connection is ok...
I am using atmega16l with AVRstudio4 and WinAVR-20080610

thank you for any response...

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

The key point is that your F_CPU needs to EXACTLY represent the speed at which the AVR is actually being clocked at. Just changing it to arbitrary values doesn't suddenly mean that the AVR is clocking at different speeds. You know from your fuse setting and the (possibly) attached clock source what speed it is actually clocking at (and don't forget CKDIV8!) then you set the F_CPU variable to that value. Based on that F_CPU the UBRR value will then be calculated but only reliably if F_CPU *is* set to the exact speed that the CPU is running at. (see FAQ#3 below)

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

yes...I changed fuses like it is described here
http://www.scienceprog.com/progr...

I even tried other demo and it didnt work with 1mhz, but only with 7.3 mhz, so I am quite sure that clock is ok...

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

hi,
since i am unable to find a 7.3mhz crystal. can i use a 8mhz or 16mhz crystal ?
also, beacuse these will produce a fractional BaudValue. will it make the data corrupt ?

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

Quote:
will it make the data corrupt ?

Not as long as the error% is within the 2% limit - see the tables in the datasheet which have the values precalculated for common CPU frequencies and baud rates

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

thanks for the reply.
i saw the table for 16mhz. can i use a more bitrate for more speed, i mean the error is very less at those speeds.

Attachment(s): 

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

The entries you have cricled there all show 0.2% error which is well within the bounds of -2%<=err%<=+2%

In fact in that table the only baud rates that are "suspicious" are 57K6 without U2X (though 2.1% is probaly OK in fact). 115K2 is not achievable (-3.5%) without using U2X which brings it back to the borderline 2.1%. 230K4 is not achieveable whatever you do.

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

i will try and let u know what are the results. thanks for the suggestions.
i think i will go for 38.4kbps baudrate.

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

hi,

nice nice tutorial well writen.
I have tried it on a AT90USB162. I have to change most stuff to include an 1 so the "right" uart is selected i assume, e.x UCSRC changed to UCSR1C BUT i can not get the line that sets 8n1 to work, keep getting errors on that one, anyone who can tell me how it should look on my avr ?

thanks

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

You don't need to do ANYTHING to select 8n1 - it's the default in all(*) the AVRs

To get the UART going in it's very most baic form it really shouldn't take anything more than setting UBRR and the TXEN bit in fact.

Cliff

(* unless anyone knows of one where it isn't?)

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

#include
#include

#ifndef F_CPU
#define F_CPU 8000000
#endif

#define BAUDRATE 9600
#define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1)

int main (void)
{
char ReceivedByte;

DDRD = 0b01111111; //7 0
PORTD = 0b00000000;

UCSR1B |= (1 << RXEN1) | (1 << TXEN1); // Turn on the transmission and reception circuitry

UBRR1L=UBRRVAL; //low byte
UBRR1H=(UBRRVAL>>8); //high byte

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

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

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

/*
ISR(USART_RXC_vect)
{
char ReceivedByte;
ReceivedByte = UDR1; // Fetch the recieved byte value into the variable "ByteReceived"

UDR1 = ReceivedByte; // Echo back the received byte back to the computer
}
*/

thatsthe code used atm, the reason i loop a 'U' out is simpel, clawson sugested use a 'U' becouse that will measure 2,5volt avg on the avrs TXD. Useing no codeline to set bits parity stopbits, im told skipping this leavs the default 8n1

i have connected the avrs TXD to a max232 pin 10, wich is TTL input, still measure 2.5volt
onmax 232 pin 7 i measure 0,14 volt wich is correct, its the avg of rs232 signal low and high (-9 and +9)

so it all seems to work, still when i connect it to my PCs serialport pin ground and RXD my hyperterminal set to 8n1 do not output 'U' endlesly, nutting att all happends

HELP!

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

ok, gues what ! the ground cable was broken inside the insulation! replaced it (the rs232 cable) and now something happends atleast, i get a wierd looking 'C' all the time, not a good looking 'U'