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

串口读取整数异常排查:客户端无法识别ATmega2560发送的数值

串口通信数据匹配问题排查与解决

初始代码与问题

客户端代码

int key=0;
while (1) {
  int n_read=read(fd, &key, 4);
  printf("%d\n",key);
  fflush(stdout);
  if(key==1){
      printf("in loop\n");
      }   
}

ATmega2560服务端初始代码

while(1){
  int key=1;
  printf("%d", key);
}

服务端printf底层实现

void usart_putchar(char data) {
    // 等待发送缓冲区为空
    while ( !(UCSR0A & (_BV(UDRE0))) );
    // 开始发送
    UDR0 = data; 
}

// printf调用的流处理函数
int usart_putchar_printf(char var, FILE *stream) {
    // 把\n转成\r适配终端
    if (var == '\n') usart_putchar('\r');
    usart_putchar(var);
    return 0;
}

初始问题

客户端始终无法打印"in loop",读取到的key值固定为825307441,从未等于1。怀疑是串口字节转整数的方式或read函数使用有问题。


修改后代码与新问题

修改服务端代码为直接按字节发送整数:

for(int j=0; j<4;j++){
        while ( !(UCSR0A & (_BV(UDRE0))) );
        UDR0=(key >> (8*j)) & 0xff;;
}

客户端输出出现异常:

1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
16777216
16777216
16777216
16777216
16777216
65536
65536
65536
65536
65536
256
256
256
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1

疑问:这是不是大小端问题?有没有解决方法?如果无法解决将采用@the busybee的建议。


问题分析与解决

1. 初始问题根源

初始服务端用printf("%d", key)发送的是字符串形式的"1"(ASCII码0x31),而客户端直接把读取的4个字节当作int类型解析。4个连续的0x31组成的整数是0x31313131,转换成十进制正好是825307441,这就是初始问题的核心原因。

2. 修改后的大小端与丢包问题

修改后服务端按j从0到3的顺序发送key的每个字节,也就是先发送低字节(小端模式)。如果客户端所在系统是大端模式,就会把字节顺序反过来解析,导致出现16777216(0x01000000)、65536(0x00010000)、256(0x00000100)这类值——这些都是单个字节被解析到不同高位导致的。

另外,客户端的read调用可能没有每次都完整读取4个字节,字节错位也会导致解析出异常数值。

解决方法

方法一:统一字节序,固定发送接收顺序

约定两端使用统一的字节序(比如大端):

  • 服务端按高字节到低字节发送:
for(int j=3; j>=0;j--){ // 从最高位字节开始发送
    while ( !(UCSR0A & (_BV(UDRE0))) );
    UDR0=(key >> (8*j)) & 0xff;
}
  • 客户端按约定的字节序手动拼接整数,避免系统字节序影响:
uint8_t buf[4];
while (1) {
    int n_read = read(fd, buf, 4);
    if(n_read !=4){
        // 跳过不完整的读取,避免字节错位
        continue;
    }
    // 按大端规则拼接成int
    int key = (buf[0] << 24) | (buf[1] << 16) | (buf[2] <<8) | buf[3];
    printf("%d\n",key);
    fflush(stdout);
    if(key==1){
        printf("in loop\n");
    }   
}

方法二:校验读取完整性

如果客户端和服务端都是小端系统(比如x86架构),只需确保每次读取到完整的4字节:

int key=0;
while (1) {
    int n_read=read(fd, &key, 4);
    if(n_read !=4){
        continue;
    }
    printf("%d\n",key);
    fflush(stdout);
    if(key==1){
        printf("in loop\n");
        }   
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:43:29