0
\$\begingroup\$

I have been tinkering with an ATMega328P trying to figure out how to use the different functionalities because i need to use it for a school project. i'm currently trying to figure out the usart part. this is my setup on a breadboard.

breadboard setup

and I am trying to transmit data using this CH340 USB-ttl module.

usb-ttl front image usb-ttl back image

I'm quite new to programming bare metal microcontrollers but i followed the datasheet and several youtube videos and came up with this code.

#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#define BAUD 9600
#define MYUBRR F_CPU/16/BAUD-1

void USARTTransmit(char my_data) {//send data via uart0
    while (!(UCSR0A & (1 << UDRE0)));
    UDR0 = my_data;

}

void USARTInit(unsigned int ubrr) {//initialise uart0
    PRR &= ~(1 << PRUSART0); //disable power reduction mode
    UBRR0H = (unsigned char)(ubrr >> 8);
    UBRR0L = (unsigned char)ubrr;
    //set frame format: 8 data bits, 1 stop bit, no parity bit
    UCSR0C |= (3 << UCSZ00);
    UCSR0B |= (1 << TXEN0); //enable transmitter
}

void sendNumber(uint16_t number) {
    char buffer[6];
    itoa(number, buffer, 10); //convert the number to a string base 10
    for (char *ptr = buffer; *ptr != '\0'; ptr++) {
        USARTTransmit(*ptr);
    }
    USARTTransmit('\n');
    
    //blink led twice to show data is sent
    for (int i =0; i<2; i++) {
        PORTB |= (1 << PB1);
        _delay_ms(500);
        PORTB &= ~(1 << PB1);
        _delay_ms(500);
    }
}

int main(void) {

    DDRB |= (1 << PB1); //set pb1 as output

    USARTInit(MYUBRR);
    uint16_t my_number = 120;//sample number
    _delay_ms(5000);
    while (1){
        sendNumber(my_number);
        _delay_ms(1000);//send every second
    }

    return 0;
}

When i try to view the data using SSCOM, I am getting some but it's all garbled up.

data on sscom

I am using the internal 8MHz clock and the lfuse is set to 0xE2. the hfuse and efuse are both left at the default values. I'm not quite sure where the issue is. it would be great if anyone could help me out

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

There may be several problems.

First one could be the power supply of the MCU. You have no bypass or filter capacitors on the MCU power supply pins and neither at the regulator. For all we know, the regulator might have turned into an unstable oscillator at few MHz.

Another one is using the internal clock. Sure, almost everyone says their AVR worked fine out of the box when using the internal oscillator. But they might have used 1 AVR only. If you buy multiple AVRs, some may work and some may not. The point is that the internal oscillator of that AVR is not guaranteed by manufacturer to be accurate enough with factory calibration to work with UART, which in theory requires 2% tolerance, in practice you normally just put a crystal, or at least a ceramic resonator to have an accurate enough clocl for UART.

What you could do is a few things.

Add the capacitors as suggested by each and every data sheet, app note, getting started guide, eval board, Arduino board and engineer to put them like they should be.

For the UART, implement auto baud rate calibration, or use a for loop to see what oscillator tuning value is in the middle of working values, or simply add a crystal. Which might not work on a breadboard.

\$\endgroup\$
3
  • \$\begingroup\$ So i added all the capacitors i could find on various videos, guides and datasheets. i also got a 16MHz crystal and added that with a 22pf capacitor connected between each leg of the crystal and ground. i'm still getting garbled output however \$\endgroup\$ Commented Dec 19, 2024 at 21:08
  • \$\begingroup\$ @Uduak It's unknown which crystal you bought so it's unknown if the 22pF capacitors are correct. Also it's a breadboard which will have a lot of capacitance already. And just connecting the crystal itself does nothing. You need to set the Fuse Bits of the AVR to actually switch to use the crystal as a source. However the fuse bits must be set right or you can accidentally choose a clock source you don't have and further programming is not possible. You can also accidentally disable further programming, so be very careful with how you set the fuses. \$\endgroup\$ Commented Dec 19, 2024 at 21:36
  • \$\begingroup\$ thanks. i did set the fuse bits to use the crystal as a source but i just noticed i defined F_CPU as 1600000UL instead of 16000000UL. that seemed to fix the problem. thank you for your help \$\endgroup\$ Commented Dec 20, 2024 at 7:34

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.