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

Go To Last Post
490 posts / 0 new

Pages

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

This tutorial is very clear, and I think I followed it correctly, but when I try to talk to the microcontroller it replies in Croatian...

I adapted the code to run in an ATTiny 2313 as this:

#define F_CPU 7372800
#include 

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

int main (void)
{

	char ReceivedByte; 
	UCSRB |= (1<<RXEN) | (1<<TXEN); // Enable USART Tx & Rx
	UCSRC |= (1<<UCSZ0) | (1<<UCSZ1); // Set serial mode as 8 bit, 1 data bits


	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 

	while(1)
	{
    	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"

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

Which is to say, pretty much a copy/paste of the code in the tutorial. I set the SUT_CKSEL (I'm using AVR Studio by the way) to use an external crystal oscilator, 3 to 8 Mhz, start up time 14CK + 4.1ms.
There's a 7.3728Mhz crystal in between pins 4 and 5, with two 22nF capacitors towards GND. Up to spec as far as I can see.

The problem is, when I try to get an echo using Br@y++ terminal, if I send "Hello", more often than not I get back something like "mlloÿ". Evidently something's got lost in translation here. By the way I'm using a FD232RL based DIY USB to serial thingy, it works just fine crossing the Tx and Rx lines so I don't think the problem is there.

A strange this is that I can't send single digit characters through the terminal, if I send "1" I get nothing, if I send "01" I get "1". Oddly, the binary echo from "01" is "00110001", "02" returns "00110010" and so on and so forth. Puzzling.

Any ideas where things may be getting screwy?

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

I suppose I should make clear that I think the problem I have is an spurious half byte, regardless of what I send out, I always get bytes as this xx11xxxx. If there would be a frequency mismatch I would be expecting (not that I'm an expert to diagnose such things!) that the errors wouldn't be so consistent.

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

Well, it is certainly not the code since all it does is send out what it receives.

Quote:
Oddly, the binary echo from "01" is "00110001"

Why is that odd? 0x00110001 is the ASCII representation of the character '1'. The only thing to figure out is what is happening to the '0'.

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Well, it is certainly not the code since all it does is send out what it receives.
Quote:
Oddly, the binary echo from "01" is "00110001"

Why is that odd? 0x00110001 is the ASCII representation of the character '1'. The only thing to figure out is what is happening to the '0'.

What's odd is that with any character I send out I get back xx11xxxx, as if doing "Byte |= 0b0011000;".

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

Can i transmit a temperature value using 'unsigned char' data type in the transmit function?Do i have to make it int?

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

Quote:
What's odd is that with any character I send out I get back xx11xxxx, as if doing "Byte |= 0b0011000;".

What Steve means is that "1" is 0x31 in hex, 49 in decimal, and 0b00110001 in binary. In other words, your terminal program is sending chars/strings, not bytes, hexidecimals, or decimals. So, the fact that you are getting back 0bxx11xxxx is expected, you're just missing the first byte for some reason.

Something I noticed. If you OR 'H' with 'e' you get 'm'.

0b01001000 'H'
0b01100101 'e'
0b01101101 'm'

why your code would generate that, I don't know, but that's what I see.

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

very useful,thanks!

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

more of an electrical question, but i get errors sending except for when i touch the pin that on the max chip thats sending(pin 14). touching any other pin doesnt do anything. ive tried a bunch of different grounds. any ideas?

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

drunkentiger, touching the pin likely adds a small amount of capacitance to the pin, stabilizing the signal (or clock, if your finger is near XTAL or the potted processor itself). What clock source are you using, and baud rate? UART communication requires precise timing -- often more precise than what the default internal 1MHz clock can provide.

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

14.7456 crystal. 20 pf caps. 2400 baud rate

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

just incase someone else has problems,
dont leave the capacitor off from Vs- to gnd

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

I know responding to make a correction to the original post is rather silly. Just something I noticed. Shouldn't when setting UBRR the high byte be written first instead of the other way around? I'm using AVR ATMEGA164P and 644P and (soon to be PA) and at least on those chips if you write the low bit first it immediately counts the whole register as being written and trying to write the high bit afterward will just cause problems. Is this just something that is true of the chips I'm using or is the guide wrong?

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

Quote:

Shouldn't when setting UBRR the high byte be written first instead of the other way around?

Nope, while some 16 bit registers on AVR have a specific read sequence to trigger a buffering mechanism there is no limit on writing most 16 bit register pairs. You can write UBRRH and UBRRL in whatever order you like. In fact it's pretty unusual for UBRRH to be anything but 0 so often it's simply a waste of time to rewrite the default 0 that it holds.

Cliff

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

This is taken from the Atmega88 datasheet,

#define FOSC 1843200 // Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1
void USART_Init( unsigned int ubrr)
{
    UBRR0H = (unsigned char)(ubrr>>8);
    UBRR0L = (unsigned char)ubrr;
    //UCSR0A = 0x00;
    /*Enable receiver and transmitter */
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    /* Set frame format: 8data, 2stop bit */
    UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit( unsigned char data )
{
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) )
    ;
    /* Put data into buffer, sends the data */
    UDR0= data;
}

In my main,

while(1)
{
     //PORTC=0x00;
     USART_Transmit('p');
}

I connect it to window's hyper terminal via the STK500...
The rx and tx are connected to PD0 and PD1 repestively...
I disconnect the CTRL rs232, connect it to the spare rs232.
Setting on hyperterminal is
9600 baud
8 data bit
2 stop bit
none parity bit
flow control none

I got nothing from this setup, whats wrong?

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

Quote:

I got nothing from this setup, whats wrong?

If you've read this or any of the other threads about using UART you will now know that 99.9% of the problems people have are because their AVR is not running at the clock speed they have calculated the UBRR value for. Your code above says:

#define FOSC 1843200 // Clock Speed 

so have you really setup your STK500/AVR to run at 1.8432MHz? Did that include changing CKSEL fuses and clearing the CKDIV8 fuse?

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

Quote:
so have you really setup your STK500/AVR to run at 1.8432MHz? Did that include changing CKSEL fuses and clearing the CKDIV8 fuse?

Hi clawson.
I have mine setup, default clock speed is 1000000...
Thats for Atmega88, that comes with a 8hz internal ocillator, by default, it is set to div8...
So I figure out that its 1mhz and it works sweet!
Cheers!

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

But technically 9600 baud does not work on 1MHz?!? If you find it does it's simply because the inaccuracy of your internal oscillator has an error so far in the right direction to allow it - not a great design!

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

I set it to 2400 baud rate...
Works fine, cheers!

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

Hello everyone,
I am using the atmega8515 and can open up brays terminal and I believe everything is working fine. My questions are when i send a phrase like hello, it echoes it back, but when i check the hex that is being sent it doesn't match up with the ascii? my second question is why can i only open it up in brays terminal and not in hyper terminal.

#include 
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE (((4000000 / (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<<UCSZ0); 	/* Set frame format: 8data, 1stop bit */

	UBRRL = BAUD_PRESCALE;

	UBRRH = (BAUD_PRESCALE >> 8);

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

		ReceivedByte = UDR;	// fetch back byte
		
		while ((UCSRA & (1 << UDRE)) == 0) {}; 	//Wait for UDR, when ready more data can be written

		UDR = ReceivedByte;	//echo back byte

	}



} 











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

"8data, 1stop bit" (and no parity) is what each transmitted packet will contain - ASCII code is within the 8 data bits. Is Hyperterminal setup to receive this type of packet? All the relevant options need to be set: 9600 baud, 8 data bits, 1 stop bit, no parity, and no handshaking. Also remember to verify the correct COM port is being used.

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

Yes I have all of those setup correctly. How can I ensure that my atmega is running at 4mhz, which is what i used for all the calculations.

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

I read this great tutorial several times, but am still having a strange problem. I am using a MAX232 in conjunction w/ Hyperterminal to try and receive some simple data from my AVR (MEGA168). The issue is that the ONLY thing I can get to show up in Hyperterminal, repeated over and over again, is the letter "p". The only values that appear to even generate this are when I load UDR0 with a byte of data containing some combination of F and 7 ONLY (i.e., 0xF7, 0x77, etc).

Settings:

#define FOSC 8000000 // Clock Speed
  #define BAUD 9600
  #define MYUBRR FOSC/16/BAUD-1
  
  UBRR0H = (unsigned char)(MYUBRR>>8);
  UBRR0L = (unsigned char)MYUBRR;
  //Enable receiver and transmitter */
  UCSR0B = 0x98;                                                                //Enable Rx/Tx, enable Rx interrupt
  /* Set frame format: 8data, 1stop bit */
  UCSR0C = 0x06;                                                                //8-bit, one stop, no parity, asynchronous

Is this some common ASCII characher for newline or something that's getting sent???

Hyperterminal is set for 9600 Baud, 8 data bits, no parity, one stop, and no Flow Control.

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

As it's a 168 have you cleared CKDIV8 or reprogrammed CLKPR to achieve the same effect?

Also how sure are you (apart from this) that the 8MHz clock source is enabled as the active clock source.

Finally, if you have a scope, if you sit in a loop attempting to send 'U' repeatedly does the scope show the bit widths to be 104us?

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

I should have clarified: I am using an older ICE50 to emulate the MEGA168 in Studio. In the ICE50 options screen, I have verified in the platform options that CKDIV8 is not checked and also that I am definitely running at 8MHz.

On the scope, sending a "U", I get periodic groups of five pulses, 500uS in width, separated by 500uS. The groups are 18mS apart, which makes sense as my code strobes the message w/ this period. Still getting "p" in Hyperterminal.

Tried sending some other string chars (i.e., "B", "S") and the bit pattern on the scope changes, but I no longer get anything in Hyperterminal.

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

Quote:
I get periodic groups of five pulses, 500uS in width, separated by 500uS.
That would seem to be 2000 baud, not 9600 baud.

Regards,
Steve A.

The Board helps those that help themselves.

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

You are exactly right, there was a mistake in my macro. I have fixed it now and its working great.

One last question: I am loading hex data into my UART, and I would prefer getting that raw data instead of its ASCII equivalent. Is there a setting in Hyperterminal to allow this?
Thanks!

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

Quote:

Is there a setting in Hyperterminal to allow this?

Not HT - but other terminal programs such as Teraterm, Realterm and Brays offer this.

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

Thank you ^^

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

hai,

i am working with stk600 with atmega2560.
i am trying for serial communication using usart.

hardware connections:
TXD pin is connected to PORT-E PIN1
RXD pin is connected to PORT-E PIN0

with the following code, we could manage to blink LEDs with the given input,but it is not possible to transmit it to HYPERTERMINAL.......it is displaying some junk garbage values on to the hyperterminal.

my code is:

#define baud 9600
#define ubrr F_CPU/(16*baud)-1
void main()
{
usart_init(ubrr);
while(1)
usart_transmit('A');
}
usart_inint(uint16_t ubr)
{
UBRR0H=(unsigned char)(ubr>>Cool;
UBRR0L=(unsigned char)ubr;
UCSR0B=(1<<TXEN0)|(1<<RXEN0);
UCSR0C=(1<<UCSZ00)|(1<<UCSZ01)|(0<<UCSZ02)|(0

real frequency is 16000000hertz........spare RS232 of stk600 has got 4pins.....

RTS,CTS,TXD,RXD.

RTS-CTS shorted
TXD connected to PE1
RXD connected to PE0.

in the programmer part::

advanced tab:calibrate for frequency is 8MHz(no option to select other frequency)

fuses:

CKDIV8,JTAGEN,SPIEN are enabled

extended - 0xFF, high - 0x99, low - 0x62;

HW SETTINGS::

clock generator is 16.01MHz

in the simulator part::

if we give ubrr=103 directly then UBRR0H - 0x00,UBRR0L- 0x67; and nothing(not even the garbage values) will be displayed in the hyperterminal

but if we give ubrr after calculating it with (F_CPU/((baud*16)-1)) then UBRR0H - 0X00,UBRR0L-0x05.
;and some garbage values are displayed in the hyperterminal
this is what actually happening.

[[code] tags added - couldn't do anything about the indentation]

sravani

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

why is the following code not transmitting any data through ATMEGA2560 - STK600......suggest me any changes

frequency : 16000000hz
baud :9600

PIN0 OF PORTE is connected to TXD pin of stk600
PIN1 OF PORTE is connected to RXD pin of stk600

suggest me any further changes required...

code:

Code:

//==================================================================================================//
//                 INCLUDING HEADER FILES & OTHER GLOBAL DECLARATIONS                               //
//==================================================================================================//

#include                   // including the input/output files of avr
#include            //including the interrupt files of avr
#include            //including the special function registers
#include                //including the delay function from util directory

#define FOSC 16000000L               //clock speed of 8MHz
#define BAUD 9600                   //baud rate
#define MYUBRR ((FOSC/(16*BAUD))-1)      //defnining the USART BAUD RATE REGISTER

void transmit(unsigned char );          // function for transmitting the at command to GSM for initialization
void start_commandat(); //declaration of the function which sends 'AT' command
void USART_Init(unsigned int); //declaration of the 'USART INITIALISATION' function
unsigned char m;
//unsigned char t;
int p=0;//declaration of the required variables

//**************************************************************************************************//
//                                       MAIN PROGRAM                                               //
//**************************************************************************************************//
int main( ) //start of the program
{
      

      USART_Init(MYUBRR);//function call for the USART initialisation
   //   sei();//set the global interrupt
   
for(;;)
{
m='A';
while ( !( UCSR0A & (1<<UDRE0)) )
;
/* Put data into buffer, sends the data */
UDR0 =m;
_delay_ms(1);
            //transmit(m);
}
     

}


//////////////////////////////////////////////////////////////////////////////////////////////////////
///                    USART INITILISATION FUNCTION                                                //
//////////////////////////////////////////////////////////////////////////////////////////////////////
void USART_Init(unsigned int ubrr)
{

      UBRR0H =(unsigned char)(ubrr>>8);//setting the baud rate

      UBRR0L =(unsigned char)ubrr;//setting the baud rate

      
      
      UCSR0B = (1<<RXEN0)|(1<<TXEN0);//ENABLING THE TRANSMITTER AND RECEIVER

      UCSR0C = (0<<UMSEL01)|(0<<UMSEL00)|(0<<USBS0)|(1<<UCSZ00)|(1<<UCSZ01)|(0<<UCSZ02);//SETTING THE FRAME FORMAT WITH 8 DATA AND 1 STOP BITS
      
      UCSR0A = (1<<UDRE0);
      

}



//////////////////////////////////////////////////////////////////////////////////////////////////////
///                             TRANSMIT FUNCTION                                                //
//////////////////////////////////////////////////////////////////////////////////////////////////////
/*void transmit( unsigned char data )
{

while ( !( UCSR0A & (1<<UDRE0)) )
;

UDR0 = data;
}*/

in the programmer part::

advanced tab:calibrate for frequency is 8MHz(no option to select other frequency)

fuses:

CKDIV8,JTAGEN,SPIEN are enabled

extended - 0xFF, high - 0x99, low - 0x62;

HW SETTINGS::

clock generator is 16.01MHz

in the simulator part::

if we give ubrr=103 directly then UBRR0H - 0x00,UBRR0L- 0x67; and nothing(not even the garbage values) will be displayed in the hyperterminal

but if we give ubrr after calculating it with (F_CPU/((baud*16)-1)) then UBRR0H - 0X00,UBRR0L-0x05.
;and some garbage values are displayed in the hyperterminal
this is what actually happening.
[[code] tags added]

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

You people obviously haven't read the other 21 pages of this thread. Almost without exception the AVR is not being clocked at the frequency you think. Suggest you flash an LED at 0.2Hz (say) using and measure it with your watch - is it really 5 seconds or not? A common "gotcha" on modern AVRs is the state of the CKDIV8 fuse (which is enabled by default and sets CLKPR so that the AVR runs at 1/8th of the applied clock frequency)

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

Is there a bug in the simulator (II) or could my code do this? I am using an ATmega88 and testing USART transmit assembly code with the data register empty interrupt on the simulator. Everything seems normal on the simulator except the data register is *always* 0x00.

When it runs it transfers data to a buffer and then quickly executes two interrupts and then indicates the data register is not empty. It runs a long time and then executes another interrupt when the data register is empty. It goes on until everything in the buffer has been (presumably) loaded to the data register. It all seems just what it should be except there is *never* (that I notice) any thing displayed in the simulator data register (UDR0) except 0x00 (I'm loading in an ASKII string and a value and they are correct in the register used to load UDR0).

John

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

Quote:
except the data register is *always* 0x00.
But reading the usart data register will give you the last received byte, not the last transmitted byte.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:

But reading the usart data register will give you the last received byte, not the last transmitted byte.

To add to that - the simulator does not normally have a mechanism to simulate receiving characters so it would be fixed at 0x00. If, however, you run Sim1 (not 2) and download "Hapsim" and run it alongside AVR Studio then it has a simulated terminal feature which will feed charactes into the simulated UDR.

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

Quote:
But reading the usart data register will give you the last received byte, not the last transmitted byte.

From my point of view, I'm not reading UDR0, I'm just watching it! I can understand that as bits are shifted out, what's left in there would be difficult to present, but it would be nice to see what's in the UDR0 buffer register while the bottom (sending) register is not empty. The simulator works pretty good, and I appreciate it, but I have been hung up on this for a long time.

Clawson, I'm just interested in transmit for now, but Hapsim looks like a good idea when I add receive capability. Thanks for the tip.

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

Quote:

I'm just watching it!

Which one? Remember that UDR0 is two separate registers. One (write) is your access to the transmission hold shift register and the other (read) is the receiver register. The AVR Studio simulation only shows one of these and that is the transmit register. When you write to it you should see the byte you wrote there for 1 cycle then it is transferred internally to the non-accessible shift register.

If you are beating yourself up over some UART routine that doesn't work it's got nothing to do with whether the half-baked similar is working or not. There's a 99.9% chance the clock speed of your AVR is wrong (I think I read that somewhere? ;-))

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

I posted a similar question somewhere else but I thought it might get more attention and possibly be helpful to others if I made it more generic and posted it here.

I am debugging a project in AVR Studio and I have a problem where random garbage gets sent out occasionally. It usually happens when I first load the project and then again when I stop the project. 90% of the time everything looks good but that other 10% of the time screws everything up. I can't settle for anything less than 100%. I am using an Xmega128a1 and everything is interrupt driven with RX and TX circular buffers so the code is quite long and slightly complicated but I would be happy to post it if someone thinks that would help OR if someone else would like to use it... even though it only works 90% of the time :-)

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

Hey all,

I have just started with AVR programming and was attempting to follow along with this tutorial and nearly went insane & bald trying to figure out what I was doing wrong. Then I sat down for a whole day and read through the entire datasheet from atmel and realized that the fuses are named in a different fashion from what is in the tut, eg: UCSRB in the tut == UCSRnB in the datasheet instead of the proposed UCSRBn.

Anyway, I thought I would share my code for a working USART Echo program so other developers may not experience the same hair pulling that I did. Below is my code, it is modified from the datasheet examples with additional comments and as of now, it works. :)

Oh, one issue that I did have with following along with the tut ( URSELn ) and the information in the datasheet ( UMSELn ). No matter which way I set it (async / sync), it would cause invalid characters to appear via ZTerm instead of the standard 'b' or 'bp'. All that would show up is a ',' and complete loss of terminal functionality.

Hardware:
-atmega168 from nerdkits.
-what i'm guessing is something like the max232 interface chip on an external board ( can't read the tiny writing ).
-USB to RS232 adapter from Prolific

Dev System:
-OS X 10.6.5 (MacBook13.1)
-CrossPack toolchain
-ZTerm terminal emulator
-vi

#include 
#include 	// only included "free()" functionality

#define F_CPU 14745600		// Clock speed
#define BAUD 115200		// expexted transfer rate
#define MUBRR F_CPU/16/BAUD-1		// set baud rate register

void UsartInit(unsigned int ubrr){
  UBRR0H = (unsigned char) (ubrr>>8);	// set High bit to second bit of ubrr
  UBRR0L = (unsigned char) ubrr;		// set Low bit to first bit of ubrr
  UCSR0B = (1<<RXEN0) | (1<<TXEN0);	// enable Receive & Transmit circuits
  UCSR0C = (1<<USBS0) | (3<<UCSZ00);// set 2bit stop, 8bit character size
}

void UsartSend(unsigned char data){
  while ( !(UCSR0A & (1<<UDRE0)));	// wait for send buffer to be empty
  UDR0 = data;					// send data
}

unsigned char UsartReceive(void){
  while ( !(UCSR0A &(1<<RXC0)));	// wait for data reception to be complete
  unsigned char data = UDR0;
  return data;					// return received data to main()
}

void UsartFlush(void){
  unsigned char dump;				// store temp data
  while (UCSR0A &(1<<RXC0))dump = UDR0;
	// drop all incoming data to temp store until incoming data is null
  free(&dump);		// drop anything thats left by releasing the memory
}

int main(void){
  UsartInit(MUBRR);		// initialize USART for data transfer
  unsigned char gigo;		// storage for i/o of data
  for(;;){					// never ending loop
    if(DOR0){				// check for data overflow
	UsartFlush();			// and flush it out
    }
    gigo = UsartReceive();	// put input to temp storage
    UsartSend(gigo);		// send output from storage
  }
  return 0;			// end of program
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

if(DOR0){ // check for data overflow

What's "DOR0" then? If I grep the header file used for mega168 it says:

iomx8.h:#define DOR0    3

so that line really says:

    if(3){            // check for data overflow 

the conditional test is therefore completely pointless as the condition is always true. So it always calls the flush function.

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

hrm... forgot to remove that. Sorry for the confusion, but it's supposed to do the following (from the datasheet):

Quote:
The Data OverRun (DORn) Flag indicates data loss due to a receiver buffer full condition. A Data OverRun occurs when the receive buffer is full (two characters), it is a new character waiting in the Receive Shift Register, and a new start bit is detected. If the DORn Flag is set there was one or more serial frame lost between the frame last read from UDRn, and the next frame read from UDRn. For compatibility with future devices, always write this bit to zero when writing to UCSRnA. The DORn Flag is cleared when the frame received was successfully moved from the Shift Register to the receive buffer.

I'm still working on figuring out exactly how I'm supposed to check if that flag is set though.

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

According to the datasheet DOR0 is a bit in the UCSR0A register. So you'd check it, as usual, with:

if (UCSR0A & (1<<DOR)) {

which checks if bit 3 (DOR0) in that register is set.

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

Thank you for the help and rapid responses! :)
I've seen elsewhere posted on this site something about a avrshell project, and am attempting something similar without stealing code as I'd rather learn just how everything works one piece at a time. Or in this case, quite literally one bit at a time. :D

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

Dean, I just started programming at a small business I'm at getting some hours done voluntarily, and your tutorials are the best man..I'm understanding things in the most simple ways, which is ultimately knowing things inside out..honestly brother...peace...

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

Can anybody tell me, if I have a non-pre-emptive scheduler with one of the timely scheduled process is Receiving operation from USART. It gets executed after say every 10ms. What is the best method by which I can receive a message frame e.g. MODBUS so that it can by further parsed and analyzed?

OR

How can I write an API read(char* buffer, size_t) like that in standard library, which can receive message in buffer of given 'size_t' over USART

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

If you are using an RTOS the UART RX stuff HAS to be in an ISR doesn't it? Otherwise how to you avoid possible over-run?

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

its not exactly an RTOS, its a customized non preemptive scheduler. ISR mode is the real problem, as each process/function gets executed completely, there is no context switching. If data is coming say @ 115200 bps, will it not hamper my other functionality as most time will be spent in ISR??

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

If you have a 115,200 baud in bound then the bit time is 8.7us and because 8N1 framing gives 10 bits per character you potentially have characters arriving every 87us. If you just poll RXC and collect UDR you would have to be sure of doing this every 87us and definitely every 174us or you could miss a character. If however you simply have an RXC ISR you just collect each arriving character and put it in a buffer. As long as the arrival of characters is not sustained you can then process the buffered characters at leisure, with the only constraint being that you clear the buffer before it is filled by the next burst of activity.

What do you see as the issue of running an RXC ISR alongside the non-prempting scheduler?

Cliff

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

Thanks for explaining so nicely. Actually my intension was to implement something like this-->

void Receive( uint8_t* a_ui8Data, uint16_t a_ui16Len )
{
uint8_t val;
do
{
while(!(UCSR0A & (1 << RXC0)));
val = UDR0;
*a_ui8Data = val;
a_ui8Data++;
}
while(--a_ui16Len);
}
but now it doesn't seem to b possible after ur explaination

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

Quote:

while(!(UCSR0A & (1 << RXC0)));

You can't do this as it will block. It will prevent control ever getting back to the main scheduler so it can give some time to the other "tasks" that are waiting to run.

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

ya..I mean there would certainly be some timeout mechanism like;

TIMER_TIMEOUT_START(TIMEOUT_INTERVAL);
while(!(UCSR0A & (1 << RXC0)) && CONDITION_TIMEOUT);
TIMER_TIMEOUT_STOP(errno);

but anyways... :cry:

Pages

Topic locked