I am trying to create a C program which receives a char via UART, "prints" the correspondent binary by turning on 8 leds in my breadboard and send the char back to the transmitter.
Here is the code I am using:
//CPU clock
#define F_CPU 1000000UL
//Baud
#define BAUD 9600
//Baud rate
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
#include <avr/io.h>
#include <util/delay.h>
#include <util/setbaud.h>
#include <avr/interrupt.h>
#include <stdint.h>
//Communication Parameters:
//8 bits of data
//1 bit stop
//No parity
void uart_init(void){
//Bit 7 - RXCIEn: RX complete interrupt enable
//Bit 6 - TXCIEn: TX complete interrupt enable
//Bit 5 - UDRIE: USART data register empty interrupt enable
//Bit 4 - RXENn: Receiver enable
//Bit 3 - TXENn: Transmitter enable
UCSR0B = 0b10011000;
//Bit 7 - RXCn: USART receive complete.
//Bit 6 - TXCn: USART transmit complete
//Bit 5 - UDREn: USART data register empty
UCSR0A = 0b00000000;
//Bit 11:0 – UBRR11:0: USART baud rate register
//Whereas H are the higher bits and L the lower bits
//It comes from the setbaud.h
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
//Bit 7:6 - UMSELn1:0: USART mode select
//00 Asynchronous USART
//01 Synchronous USART
//11 Master SPI
//Bit 5:3 - Reserved bits in MSPI mode
//Bit 2 - UDORDn: Data order
//Bit 1 - UCPHAn: Clock phase
//Bit 0 - UCPOLn: Clock polarity
UCSR0C = 0b10000110;
}
// function to send data
void uart_transmit (uint8_t data)
{
while (!( UCSR0A & (1<<UDRE0))); // wait while register is free
UDR0 = data; // load data in the register
}
int main (void)
{
//Starts UART
uart_init();
//All led GPIOs as output
DDRB = 0xFF;
DDRC = 0x01;
//Enabling interrupts
sei();
while(1)
{
;
}
return 0;
}
ISR(USART_RX_vect)
{
//Variable to hold the incoming char
uint8_t received_bit = UDR0;
PORTC ^= 0x01;
PORTB = 0x00;
PORTB = received_bit;
uart_transmit(received_bit);
}
When I flash it to the chip and start using it, I get a weird behaviour. I am sending a "U" which is a nice binary 01010101 to compare with. However I am getting weird answers back from my chip:
My questions regarding UART under an ATMEGA168a are the following:
F_CPU
am I supposed to stay with the 1MHZ used by the ATMEGA168a or do I have to use the one of my transmitter (Intel i7)? Could it be the problem?In the function uart_init()
you set bits 7:6
to 10
which is a reserved state according to the ATMega 168A manual. To get the desired asynchronous UART functionality, set them to 00
:
UCSR0C = 0b00000110;
The other reason why your example was not working was the baudrate settings, as explained in my comment below.
You already included the <util/setbaud.h>
header file, which contains macros to make UART setup easier. Look here for the documentation. These macros take the input provided by you in F_CPU
and BAUDRATE
and calculate the settings for the UART configuration registers (UBRRH_VALUE
and UBRRL_VALUE
).
You used it almost correctly, however to take advantage of the UART baudrate doubling feature of the ATmega, add the following code after setting the UBRR0H/L value:
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
This sets or clears the U2X0
bit dependent on the calculations of the setbaud macros.
Also, I believe you can remove the line
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1)
because that's exactly what setbaud.h does.