You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AVR-C在ATmega328P Arduino Uno上UART串口打印乱码求助

解决ATmega328P裸机串口打印乱码问题

1. 修正波特率配置顺序

util/setbaud.h的宏依赖严格的定义顺序——必须先指定F_CPU,再包含该头文件。把F_CPU定义移到代码最顶部,避免编译时宏展开顺序错误:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>

#define BAUD 9600
#include <util/setbaud.h>

同时可以手动计算验证UBRR值:16MHz时钟、9600波特率下,UBRR应为(16000000/(16*9600))-1 = 103,直接替换代码中的UBRR赋值,跳过头文件自动计算:

UBRR0H = (103 >> 8);
UBRR0L = 103;

2. 修复Makefile链接参数

你的编译链接命令缺少-mmcu=atmega328p参数,会导致生成的二进制指令集与芯片不匹配,间接引发时序/波特率异常。修改链接行:

default:
    avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o serial-print.o serial-print.c 
    avr-gcc -mmcu=atmega328p -o serial-print.bin serial-print.o
    avr-objcopy -O ihex -R .eeprom serial-print.bin serial-print.hex
    sudo avrdude -F -V -c arduino -p ATMEGA328P -P /dev/ttyACM0 -b 115200 -U flash:w:serial-print.hex

3. 显式指定串口帧格式

明确配置帧格式,避免默认值歧义,确保与接收端(串口监视器、screen)一致:

UCSR0C = (1<<UCSZ01) | (1<<UCSZ00) | (0<<USBS0); // 8位数据,1位停止位,无校验

4. 确认芯片实际时钟频率

克隆版Arduino Uno常使用8MHz内部时钟代替16MHz晶振,这会直接导致波特率误差超出允许范围。用avrdude读取熔丝位确认:

sudo avrdude -c arduino -p atmega328p -P /dev/ttyACM0 -b 115200 -U lfuse:r:-:h
  • LFUSE值为0xFF:对应16MHz外部晶振(标准Uno配置)
  • LFUSE值为0xE2:对应8MHz内部时钟
    如果是8MHz时钟,需将代码和Makefile中的F_CPU改为8000000UL,同时UBRR值调整为51。

5. 排除printf的干扰

简化代码直接发送单字符,验证底层串口功能是否正常:

int main(void) {
    uart_init();
    while(1) {
        loop_until_bit_is_set(UCSR0A, UDRE0);
        UDR0 = 'A';
        _delay_ms(500);
    }
    return 0;
}

如果能正常接收字符'A',说明问题出在printf的流配置环节,检查stdout赋值是否在uart_init之后,且FDEV_SETUP_STREAM参数正确。

内容的提问来源于stack exchange,提问作者Troglobyte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:43:12