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
相关产品推荐
相关产品推荐

