串口通信:如何正确设置DCB并获取Arduino完整配置?
仿制Arduino Nano串口通信异常问题
我用一款廉价仿制的Arduino Nano做串口通信已有一段时间,但通信始终异常,不确定自身配置是否正确。我通过GENERIC_WRITE、GENERIC_READ、OPEN_EXISTING、FILE_FLAG_OVERLAPPED打开端口,且正确调用SetCommMask设置EV_RXCHAR标志。
我通过以下代码调用SetCommState配置DCB,还尝试过两种方法:
- 短暂将开发板连接到Arduino IDE
- 自行编写程序调用
GetCommState,期望获取Arduino IDE设置的配置,但似乎无效,现在我的另一款读写程序完全无法工作。
DCB dcbSerialParams = { 0 }; dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(hComm, &dcbSerialParams)) { printf("Error getting device state\n"); CloseHandle(hComm); } dcbSerialParams.BaudRate = 9600; ///< 当前波特率 dcbSerialParams.ByteSize = 8; ///< 每字节位数,4-8 dcbSerialParams.Parity = NOPARITY; ///< 0-4 = 无、奇、偶、标记、空格 dcbSerialParams.StopBits = ONESTOPBIT; ///< 0, 1, 2 = 1, 1.5, 2 dcbSerialParams.fTXContinueOnXoff = 1; dcbSerialParams.fOutX = 0; dcbSerialParams.fInX = 0; if (!SetCommState(hComm, &dcbSerialParams)) { printf("Error setting device parameters\n"); CloseHandle(hComm); } GetCommState(hComm, &dcbSerialParams); printf("%hd %hd\n", dcbSerialParams.XonLim, dcbSerialParams.XoffLim);
我知道可以查阅CH340 datasheet解决问题,但仍有两个疑问:
- 如何获取Arduino的完整正确配置?
- 若Arduino IDE和PuTTY能与Arduino正常通信,是否说明驱动工作正常?
编辑:以下是Arduino端的setup代码:
void setup() { Serial.begin(9600); }
问题解答
1. 驱动状态判断
是的,如果Arduino IDE和PuTTY都能与开发板正常通信,说明CH340驱动工作正常。这排除了硬件驱动层面的问题,故障大概率出在你编写的串口程序的配置细节上。
2. 获取Arduino完整配置
Arduino的Serial.begin(9600)默认配置为:
- 波特率:9600
- 数据位:8
- 校验位:无(NOPARITY)
- 停止位:1(ONESTOPBIT)
- 流控制:无(不使用XON/XOFF或硬件流控)
但Windows串口API的DCB结构体包含很多易被忽略的默认参数(如XonLim、XoffLim、fNull、fErrorChar等),要获取Arduino IDE的完整配置,可按以下步骤操作:
- 打开Arduino IDE串口监视器并保持连接
- 编写仅调用
GetCommState的程序,打印DCB结构体的所有字段,不要调用SetCommState修改任何配置 - 得到的参数即为Arduino IDE使用的完整串口配置,可直接复用至你的程序
3. 代码潜在问题分析
从你提供的代码来看,存在几个可能导致通信异常的点:
- 仅设置了DCB的部分字段,未覆盖的默认参数(如
fNull开启会丢弃空字符、fErrorChar开启会替换错误字符)可能不符合Arduino串口通信要求 - 使用
FILE_FLAG_OVERLAPPED(重叠IO)时,后续读写操作必须配合OVERLAPPED结构体,若你的读写逻辑未处理异步操作,会引发未定义行为 - 未配置串口超时参数,
SetCommTimeouts是必要步骤,参考配置如下:COMMTIMEOUTS timeouts = {0}; timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; SetCommTimeouts(hComm, &timeouts);
4. 快速修复建议
- 先关闭重叠IO(移除
FILE_FLAG_OVERLAPPED),用同步IO测试,排除异步操作带来的问题 - 完整复制Arduino IDE的DCB参数,不要仅设置部分字段
- 添加
SetCommTimeouts配置合理超时 - 串口打开后调用
PurgeComm清除缓冲区:PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
内容的提问来源于stack exchange,提问作者l_KarmaKat
相关产品推荐
相关产品推荐

