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串口的文本模式默认配置上,导致二进制数据被错误转换:
- Windows串口默认以文本模式工作,会自动处理换行符(将CR/LF进行转换),甚至会对二进制数据中的特定字节(如0x00)进行误处理。从异常数据看,0x0000被读取为0x0a00,就是因为文本模式下驱动将某个字节错误替换成了换行符(0x0a)。
- 现有代码中的
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
相关产品推荐
相关产品推荐

