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

Go To Last Post
490 posts / 0 new

Pages

  • 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

Pages

Topic locked