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

Windows下串口读取Arduino 16位数据异常的技术问询

串口通信异常问题排查

问题背景

基于Arduino类微控制器发送16位无符号原始字节数据,Linux环境下Python读取完全正常,但Windows 11虚拟机中使用C++读取时出现特定规律的异常。

Arduino发送代码

void sendTestData() {
    uint16_t *p16 = &bufferp[DATASTART];
    Serial.println( "TESTDATA" );
    for ( int n = 0; n < NPIXELS; n++ ) {
       p16[n] = n;
    }

    Serial.print( "BINARY16 " );
    Serial.println( NPIXELS );
    Serial.write( (byte *) p16, 2*NPIXELS );
    Serial.println( "END DATA" );
}

Linux Python读取代码(正常)

data = self.ser.read( ndata*2 )
data = struct.unpack( '<%dH'%(len(data)/2), data )
data = np.array(data)

Windows C++读取代码(异常)

int readBuffer( void *buffer, DWORD nbytes) 
{
    DWORD nread = 0;
    ReadFile(hSerial,buffer,nbytes,&nread, NULL);
    return nread;
}

if ((nread=readBuffer( rawbuffer, nbytes)))
{
    n = 0;
    m = 0;
    while( n<npixels)
    {
        hi = *b++;
        lo = *b++;
        u16 = hi;
        u16 <<= 8;
        u16 |= lo;
        rawbuffer[n++] = u16;
    }
}

异常数据示例

aberrant test value at 0 (0x0000): 2560 from read bytes 0x0a 0x00
aberrant test value at 256 (0x0100): 0 from read bytes 0x00 0x00
aberrant test value at 512 (0x0200): 256 from read bytes 0x01 0x00
aberrant test value at 768 (0x0300): 512 from read bytes 0x02 0x00
aberrant test value at 1024 (0x0400): 768 from read bytes 0x03 0x00
aberrant test value at 1280 (0x0500): 1024 from read bytes 0x04 0x00
aberrant test value at 1536 (0x0600): 1280 from read bytes 0x05 0x00
aberrant test value at 1792 (0x0700): 1536 from read bytes 0x06 0x00
aberrant test value at 2048 (0x0800): 1792 from read bytes 0x07 0x00
aberrant test value at 2304 (0x0900): 2048 from read bytes 0x08 0x00
aberrant test value at 2560 (0x0a00): 2304 from read bytes 0x09 0x00
aberrant test value at 2816 (0x0b00): 2560 from read bytes 0x0a 0x00
aberrant test value at 3072 (0x0c00): 2816 from read bytes 0x0b 0x00
aberrant test value at 3328 (0x0d00): 3072 from read bytes 0x0c 0x00
aberrant test value at 3584 (0x0e00): 3328 from read bytes 0x0d 0x00

Windows串口打开代码

bool opencomport(const char *name)
{
    COMMTIMEOUTS timeouts = { 100, //interval timeout. 0 = not used
                              0, // read multiplier
                             100, // read constant (milliseconds)
                              0, // Write multiplier
                              0  // Write Constant
                            };


    bool retv;

    hSerial = CreateFile(name,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         0,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);

    if (hSerial == INVALID_HANDLE_VALUE) {
        MessageBox(NULL,"failed to open comport","",MB_OK);
        exit(-1);
    }

    if ( !SetupComm(hSerial,2*16384,4096) ) {
        MessageBox(NULL,"failed to allocate serial port buffers","",MB_OK);
        exit(-1);
    }

    set8bit();

    if (!SetCommTimeouts(hSerial, &timeouts)) {
        MessageBox(NULL,"failed to set timeouts","",MB_OK);
        exit(-1);
    }
    
    getcomportbuffersizes();

    return true;
}

问题根源

问题出在Windows串口的文本模式默认配置上,导致二进制数据被错误转换:

  1. Windows串口默认以文本模式工作,会自动处理换行符(将CR/LF进行转换),甚至会对二进制数据中的特定字节(如0x00)进行误处理。从异常数据看,0x0000被读取为0x0a00,就是因为文本模式下驱动将某个字节错误替换成了换行符(0x0a)。
  2. 现有代码中的set8bit()函数仅配置了8位数据位,但未显式启用二进制模式。Windows串口必须通过DCB结构体设置fBinary = TRUE,才能禁用所有字符转换逻辑,和Linux下的串口行为保持一致。

解决方法

修改set8bit()函数,添加二进制模式配置:

void set8bit() {
    DCB dcb;
    GetCommState(hSerial, &dcb);
    // 根据实际波特率调整
    dcb.BaudRate = CBR_9600;
    dcb.ByteSize = 8;
    dcb.Parity = NOPARITY;
    dcb.StopBits = ONESTOPBIT;
    // 关键:启用二进制模式,禁止字符转换
    dcb.fBinary = TRUE;
    // 关闭流控制,避免额外干扰
    dcb.fOutX = FALSE;
    dcb.fInX = FALSE;
    SetCommState(hSerial, &dcb);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 06:55:13