ATxmega128A1用fwrite写stdout发二进制数据0x0a前自动加0x0d如何解决
根本原因说明
avr-libc的标准IO库没有实现文本/二进制模式的区分,你遇到的0x0a自动转0x0d0x0a是默认串口输出回调里硬编码的换行转换逻辑,所以通用桌面系统的freopen、fdopen加wb参数的方法完全不兼容,底层没有对应的实现逻辑。
可行解决方案
方案1:修改stdout绑定的串口输出回调(最推荐,可保留标准IO调用习惯)
avr-gcc环境下的stdout本质是通过FDEV_SETUP_STREAM宏绑定用户自定义的字符输出回调实现的,你现有代码里的回调肯定包含了换行转换的逻辑,删除对应判断即可:
// 原串口输出回调示例,删除换行转换逻辑即可 static int uart_putchar(char c, FILE *stream) { // --- 删除下面这行代码即可消除自动加\r的逻辑 --- // if (c == '\n') uart_putchar('\r', stream); // 原有串口发送逻辑保留 loop_until_bit_is_set(UCSR0A, UDRE0); UDR0 = c; return 0; } // 绑定stdout的逻辑不需要修改 static FILE uart_stdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); int main(void) { stdout = &uart_stdout; // 后续初始化、业务逻辑 uint8_t data[10] = {1,2,3,10,/*其余值*/3,5}; fwrite(data, 1, 10, stdout); // 此时输出完全为原始二进制,无转换 }
如果后续需要同时支持文本换行输出和二进制传输,可以定义两个不同的FILE流,分别绑定带换行转换和不带转换的回调,按需选择使用即可。
方案2:绕过标准IO直接操作串口寄存器发数据
如果不想修改现有stdout的逻辑,可直接写串口外设寄存器批量发送二进制数据,完全跳过标准IO的转换逻辑:
void uart_send_binary(const uint8_t *buf, size_t len) { for (size_t i = 0; i < len; i++) { // 等待串口发送缓冲区为空 loop_until_bit_is_set(UCSR0A, UDRE0); // 直接写入字节到串口数据寄存器 UDR0 = buf[i]; } } // 调用示例 uint8_t data[10] = {1,2,3,10,/*其余值*/3,5}; uart_send_binary(data, 10);
这个方法不会影响现有printf等文本输出的换行逻辑,适合仅部分场景需要传输二进制数据的情况。
内容的提问来源于stack exchange,提问作者WPFGermany
相关产品推荐
相关产品推荐

