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

Go To Last Post
490 posts / 0 new

Pages

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

Pages

Topic locked