atmega328P serial communication with interrupt

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

hy can someone help i need to receive  value 0-1000 via serial communication on 115200 8 data 1 stop bit in interrpt. Code pass verification on arduino IDE but doesnt echoing back :S

#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 16000000
#define USART_BAUDRATE 115200
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
char ReceivedByte;

int main (void)
{
   UCSR0B = (1 << RXEN0) | (1 << TXEN0);   // Turn on the transmission and reception circuitry
   UCSR0C = (1<<USBS0)|(3<<UCSZ00);
 // Use 8-bit character sizes

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

   UCSR0B |= (1 << RXCIE0); // Enable the USART Recieve Complete interrupt (USART_RXC)
   sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed

   for (;;) // Loop forever
   {
         // Do nothing - echoing is handled by the ISR instead of in the main loop
   }   
}

ISR(USART_RXC_vect)
{
   ReceivedByte;
   ReceivedByte = UDR0; // Fetch the received byte value into the variable "ByteReceived"
   UDR0 = ReceivedByte; // Echo back the received byte back to the computer
}

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

There is a bit in one of the USART control registers that enables the RXC interrupt, I don't see where you have enable it.

Never mind,I see it now.

Are you using an Arduino board, or is this on a bread board?

If on a bread board, how do you interface the serial pins to your pc?

 

 

Jim

 

Last Edited: Sat. Aug 5, 2017 - 10:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The variable definition in the ISR is not valid? 

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

And you can't get 115200 baud with a 16MHz F_CPU unless you use U2X bit.
.
Actually the ReceivedByte; statement in ISR() is perfectly legal. It reads the global variable and discards it.
Since the variable is not declared as volatile, the Optimiser might remove it anyway.
.
David.

Last Edited: Sun. Aug 6, 2017 - 07:44 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Missed the fact it was global. 

(am I the only one who finds Freaks almost impossible using a mobile phone? (even a 1920x1080 one!)) 

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

I use arduino nano board and in arduino IDE 

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

Is there something that does work?

Can you make your uC blink a led for every byte it receives?

Does there come any data out of the TxD pin?

Even with the wrong baudrate, etc. This is vey easy to check with a logic analyser & Sigrok

If you want to use ReceivedByte outside of the interrupt later, you must adhere to Clawsin's signatrue FAQ#1. Declare it volatile

And you don't have to write to the UBRR0 registers in bytes.

The compiler knows how to handle this (I think):

UBRR = BAUD_PRESCALE

Have fun.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

i have already try to turn a led when it receive anything but it doesnt work

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

My uart knowledge is a bit rusty.

Wrote my own lib about 10 year ago and it "just works" and after that I forgot most details.

I do however initialise RxD as input and TxD as output before any uart initialisation.

(But I think that is not mandatory?)

 

Try to think of small steps which can help you get some results.

For example you can remove the ISR completely and write a for loop like this:

for (;;) {

    Udr = UDR;      // Read once.
    
    if( Udr != adsf) {
        asdf = Udr;
        PORTTB ^= LED;  // Toggle a led if UDR changed.
    }
}

How much time have you spent at other (presumably working) uart lib's?

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

i dont want library to use because its very time consuming and  i making flightcontroller for drone, its my final work on college. I run loop on 250hz calculating pid and i now want to make joysticks with bluetooth communicatio HC05(master and slave configurated on 115200 and 1 stop bit  and no parity bits ) and this blueotooh modules i will connect to ardino hardwers tx and rx. 

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

i can make this with arduino serial  but i want to learn something a bit deeper in avr because arduino code is for easy prototip projects.

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

mkule wrote:
i dont want library to use because its very time consuming

LOL -- and next, an ASM program will run your UART faster than a C program.

 

Why would any pre-written code be more time-consuming than what you wrote?

 

mkule wrote:
ReceivedByte;

That is an interesting line -- it looks quite time-consuming to me.

 

How do you expect to get a value 0-1000 into 8 bits?

 

How is the information being transmitted?  LSB first?  MSB first?  Binary?  Ascii?  "ASCII hex"?

 

No terminators or other framing?  How will you maintain synchronization?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

I have managed to work on 115200 baud without any library this is the code below. Only need read datasheet very carefully hehe :D :D

 

 

#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 16000000
#define USART_BAUDRATE 115200
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 8UL)))-1)

void setup(){
USART_INIT();

}
void loop(){
  char b;
  b=USART_Receive();
  
   USART_send(b);
   USART_send('\n');
  
}
void USART_INIT(){
  UBRR0 = BAUD_PRESCALE;
  UCSR0C =((0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00));
  UCSR0B = ((1<<RXEN0)|(1<<TXEN0));
  UCSR0A =(1<<U2X0);
}
void USART_send( unsigned char data)
{
    //while the transmit buffer is not empty loop
    while(!(UCSR0A & (1<<UDRE0)));
 
    //when the buffer is empty write data to the transmitted
    UDR0 = data;
}
unsigned char USART_Receive( void )
{
/* Wait for data to be received */
while (!(UCSR0A & (1<<RXC0)));
/* Get and return received data from buffer */
return UDR0;
}

Last Edited: Thu. Aug 10, 2017 - 11:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The formula you use for BAUD_PRESCALE fails for 115200;  Gives 7 instead of the correct 8.

Here is code that works for 115200 with 2x.

 

#include<avr/io.h>
#include<avr/interrupt.h>
#define F_CPU 16000000
#define USART_BAUDRATE 115200
//#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL)))-1)

void setup(){
	USART_INIT();

}
void loop(){
	unsigned char b;
	b=USART_Receive();	
	USART_send(b);
	USART_send('\r');
	USART_send('\n');
	
}
void USART_INIT(){
	UBRR0 = 8;  NOTE FORMULA FOR BAUD_PRESSCALE FAILS FOR 115200.  GIVES 7 INSTEAD OF 8
	UCSR0B = ((1<<RXEN0)|(1<<TXEN0));
}
void USART_send( unsigned char data)
{
	//while the transmit buffer is not empty loop
	while(!(UCSR0A & (1<<UDRE0)));
	
	//when the buffer is empty write data to the transmitted
	UDR0 = data;
}
unsigned char USART_Receive( void )
{
	/* Wait for data to be received */
	while (!(UCSR0A & (1<<RXC0)));
	/* Get and return received data from buffer */
	return UDR0;
}
main(void)
{
	setup();
	while(1)
	{
		loop();
	}
}

 

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

The formula that you used in #13 is correct. i.e. UBRR=16 with U2X
jstampfl gives 8 but with U2X=0 in #14.   This will give a large error for both UBRR=7 and UBRR=8

 

Edit.  Oops.  I have corrected my message

Last Edited: Fri. Aug 11, 2017 - 11:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

no its not wrong  look in datasheet for atmega 328/p, code is tested and everything works well now i have managed and interrupt routine 

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

http://www.atmel.com/Images/Atme... page 243 U2XN =1 says that UBBRn must be 16. When UBBRN was 8 in code i have echo back from chip wrong character.

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

Sorry.  I have corrected #15 now.

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

i was answering jstampfl :).  you says that my code is correct but it was little mistaken in your i.e. ubrrn 

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

The point is that you don't need the 2x, just the correct value for UBRR, which according the datasheet for 115200 with 16Mhz.

 

You can see that the formula

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

gives the wrong value of 7 instead of 8.

 

You can see this using the debugger.

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

You might want to read Dean Camera's tutorial "Using the USART in AVR-GCC" at http://www.fourwalledcubicle.com....

 

"# define USART_BAUDRATE 9600
// Naive Version - has rounding bugs !
//# define BAUD_PRESCALE ((( F_CPU / ( USART_BAUDRATE * 16 UL))) - 1)
// Better Version - see text below

# define BAUD_PRESCALE (((( F_CPU / 16) + ( USART_BAUDRATE / 2)) / ( USART_BAUDRATE )) - 1)"
 

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

jstampfl wrote:
You can see this using the debugger.
or simply a disassembly:

C:\SysGCC\avr\bin>avr-objdump -S avr.o

avr.o:     file format elf32-avr


Disassembly of section .text:

00000000 <USART_INIT>:
   0:   87 e0           ldi     r24, 0x07       ; 7
   2:   90 e0           ldi     r25, 0x00       ; 0
   4:   90 93 c5 00     sts     0x00C5, r25
   8:   80 93 c4 00     sts     0x00C4, r24
   c:   86 e0           ldi     r24, 0x06       ; 6
   e:   80 93 c2 00     sts     0x00C2, r24
  12:   88 e1           ldi     r24, 0x18       ; 24
  14:   80 93 c1 00     sts     0x00C1, r24
  18:   82 e0           ldi     r24, 0x02       ; 2
  1a:   80 93 c0 00     sts     0x00C0, r24
  1e:   08 95           ret

Note however:

#include <avr/io.h>

#define F_CPU 16000000
#define BAUD 115200
#include <util/setbaud.h>

void USART_INIT(){
  UBRR0 = UBRR_VALUE;
  UCSR0C =((0<<USBS0)|(1<<UCSZ01)|(1<<UCSZ00));
  UCSR0B = ((1<<RXEN0)|(1<<TXEN0));
  UCSR0A =(1<<U2X0);
}

Initially this gives:

C:\SysGCC\avr\bin>avr-gcc -c -mmcu=atmega328p -O -save-temps avr.c -o avr.o
In file included from avr.c:6:0:
c:\sysgcc\avr\avr\include\util\setbaud.h:222:4: warning: #warning "Baud rate achieved is higher than allowed" [-Wcpp]
 #  warning "Baud rate achieved is higher than allowed"

because the error is > 2% but using:

#define F_CPU 16000000
#define BAUD 115200
#define BAUD_TOL 4
#include <util/setbaud.h>

allowing for up to a 4% error gives:

C:\SysGCC\avr\bin>avr-gcc -c -mmcu=atmega328p -O -save-temps avr.c -o avr.o

C:\SysGCC\avr\bin>avr-objdump -S avr.o

avr.o:     file format elf32-avr


Disassembly of section .text:

00000000 <USART_INIT>:
   0:   88 e0           ldi     r24, 0x08       ; 8
   2:   90 e0           ldi     r25, 0x00       ; 0
   4:   90 93 c5 00     sts     0x00C5, r25

 

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

Depending on what device is on the other end.  ie.  a PC with a terminal emulator, GPS module, etc.  I prefer 250K BAUD or 76.8k baud. 19.2K & 9.6K also have low error rates at 16MHz.

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

its wireless communication with two bluetooth module hc 05 (master/slave ). i have made flightcontroller for quadcopter (almost done i need find good PID values and wireless connect drone and remote  via bluetooth). I choose bluetooth because i dont need to flight far from remote, purpose of remote is just for switch drone on and off beause main task to drone je to hold altitude(hovering) and this is problematic which i must to cover in my final work on college. 

Last Edited: Sat. Aug 12, 2017 - 11:27 AM