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

AVR Mega2560中printf()与fgetc()无法工作的问题求助

问题解决方案

核心问题在于AVR工具链的标准IO(printf/fgetc)默认未绑定硬件串口,必须手动配置USART并实现底层读写函数才能正常使用。此外你的代码存在内存分配的潜在问题,以下是具体解决步骤:

1. 配置USART串口

Arduino Mega2560的USB转串口对应USART0(引脚RX0=PD0,TX0=PD1),需要初始化波特率、数据格式等。添加以下初始化函数:

void USART_Init(unsigned int baud) {
    unsigned int ubrr = F_CPU / 16 / baud - 1;
    UBRR0H = (unsigned char)(ubrr >> 8);
    UBRR0L = (unsigned char)ubrr;
    UCSR0B = (1 << RXEN0) | (1 << TXEN0); // 启用接收和发送
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); // 8位数据位,1停止位,无校验
}

注意:编译时必须通过-DF_CPU=16000000UL定义CPU频率(Mega2560默认是16MHz)。

2. 实现标准IO底层函数

AVR标准库需要你提供_putchar(支持printf输出)和_getchar(支持fgetc输入)函数,将标准IO绑定到USART:

int _putchar(char c) {
    while (!(UCSR0A & (1 << UDRE0))); // 等待发送缓冲区空闲
    UDR0 = c;
    return c;
}

int _getchar(void) {
    while (!(UCSR0A & (1 << RXC0))); // 等待接收完成
    return UDR0;
}

3. 修复内存分配问题

原代码中malloc((int)NULL)等价于malloc(0),属于未定义行为;且初始字符串无终止符,strncat会触发未定义操作。修正如下:

  • 初始分配1字节并初始化为空字符串
  • 每次重分配后手动维护字符串终止符
  • 添加内存分配失败的错误处理

完整修正代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <util/delay.h>

#define BAUD 9600

void USART_Init(unsigned int baud) {
    unsigned int ubrr = F_CPU / 16 / baud - 1;
    UBRR0H = (unsigned char)(ubrr >> 8);
    UBRR0L = (unsigned char)ubrr;
    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}

int _putchar(char c) {
    while (!(UCSR0A & (1 << UDRE0)));
    UDR0 = c;
    return c;
}

int _getchar(void) {
    while (!(UCSR0A & (1 << RXC0)));
    return UDR0;
}

int main(void) {
    char *name = malloc(1);
    if (!name) {
        // 内存分配失败:快速闪烁LED报错
        DDRB |= (1 << DDB7);
        while(1) {
            PORTB ^= (1 << PB7);
            _delay_ms(200);
        }
    }
    *name = '\0'; // 初始化为空字符串
    char c;
    int cnt = 1;
    int i;

    DDRB |= (1 << DDB7);
    USART_Init(BAUD); // 初始化串口

    printf("Enter your name: ");

    while ((c = fgetc(stdin)) != '\n') {
        cnt++;
        char *temp = realloc(name, cnt);
        if (!temp) {
            // 重分配失败:释放内存后快速闪烁报错
            free(name);
            while(1) {
                PORTB ^= (1 << PB7);
                _delay_ms(100);
            }
        }
        name = temp;
        name[cnt-2] = c; // 直接写入字符
        name[cnt-1] = '\0'; // 确保字符串终止
    }

    for (i = 0; i < strlen(name); ++i) {
        PORTB |= (1 << PB7);
        _delay_ms(1000);
        PORTB &= ~(1 << PB7);
        _delay_ms(500); // 添加熄灭延迟,闪烁更清晰
    }

    free(name); // 释放内存
    return 0;
}

编译与烧录命令示例

# 编译
avr-gcc -mmcu=atmega2560 -DF_CPU=16000000UL -Os -o main.elf main.c
# 转换为HEX格式
avr-objcopy -O ihex main.elf main.hex
# 烧录(根据你的串口设备调整路径,Windows为COMx)
avrdude -c stk500v2 -p m2560 -P /dev/ttyUSB0 -U flash:w:main.hex

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:40:28