Windows下串口WriteFile写操作阻塞,需接收字节后才执行问题排查
关于RS485串口监控程序WriteFile挂起的问题
问题场景
我用C++编写了一个小型RS485串口总线监控程序,功能是从串口读取最大32字节的小数据包,并在用户请求时偶尔发送同类数据包。读取功能运行正常:初始化时通过SetCommMask(hComm, EV_RXCHAR)设置读取线程,借助ReadFile配合超时机制识别数据包间隔。但主程序中调用WriteFile发送数据包时,会挂起直到总线上有字节被接收,之后总线设备才能识别并正常响应。
相关代码
串口初始化与接收线程代码
HANDLE uart_init(char *portname, int baudrate) { HANDLE hComm; BOOL Write_Status, Read_Status; DCB dcbSerialParams; COMMTIMEOUTS timeouts = { 0 }; hComm = CreateFile(L"com8", //port name GENERIC_READ | GENERIC_WRITE, //Read/Write 0, // No Sharing NULL, // No Security OPEN_EXISTING, // Open existing port only 0, // Non Overlapped I/O NULL); // Null for Comm Devices if (hComm == INVALID_HANDLE_VALUE) printf("Error in opening serial port\n"); else printf("opening serial port successful\n"); Write_Status = GetCommState(hComm, &dcbSerialParams); //retreives the current settings if (Write_Status == FALSE) { printf(" Error in GetCommState()\n"); CloseHandle(hComm); return NULL; } dcbSerialParams.BaudRate = baudrate; // Setting BaudRate = 1200 dcbSerialParams.ByteSize = 8; // Setting ByteSize = 8 dcbSerialParams.StopBits = ONESTOPBIT; // Setting StopBits = 1 dcbSerialParams.Parity = NOPARITY; // Setting Parity = None Write_Status = SetCommState(hComm, &dcbSerialParams); //Configuring the port according to settings in DCB if (Write_Status == FALSE) { printf(" Error! in Setting DCB Structure\n"); CloseHandle(hComm); return NULL; } else { printf(" Setting DCB Structure Successful\n"); printf(" Baudrate = %d\n", dcbSerialParams.BaudRate); printf(" ByteSize = %d\n", dcbSerialParams.ByteSize); printf(" StopBits = %d\n", dcbSerialParams.StopBits); printf(" Parity = %d\n\n", dcbSerialParams.Parity); } // Set COM port timeout settings timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 0; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; if (SetCommTimeouts(hComm, &timeouts) == 0) { printf("Error setting timeouts\n"); CloseHandle(hComm); return NULL; } Read_Status = SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception if (Read_Status == FALSE) printf(" Error! in Setting CommMask\n\n"); else printf(" Setting CommMask successfull\n\n"); return hComm; } unsigned int __stdcall RS485Receiver(void* data) { BOOL status = 0; DWORD dwEventMask = 0; DWORD nBytes; // Bytes read by ReadFile() puts("Serial Thread started"); if (hComm = uart_init("COM8", 1200)) { printf("Waiting for Data Reception...\n"); status = WaitCommEvent(hComm, &dwEventMask, NULL); //Wait for the character to be received if (status == FALSE) { printf("Error! in Setting WaitCommEvent()\n"); } else //If WaitCommEvent()==True Read the RXed data using ReadFile(); { _putch('.'); fflush(stdout); do { //Read_Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, NULL); if ((!ReadFile(hComm, RS485PacketBuffer, sizeof(T_PACKET), &nBytes, NULL))) { printf("wrong character"); } else if (nBytes) { RS485PrintPacket(RS485PacketBuffer, RS485PacketBuffer->length + 4, stdout); } } while (1); } CloseHandle(hComm);//Closing the Serial Port } puts("Serial Thread stopped"); return 0; } #endif
会挂起的发送函数代码
uint8_t sendPacket(T_PACKET* packet) { DWORD nBytes; //calculate checksum packet->d[packet->length] = crc8((uint8_t*)packet, packet->length + 4); // PORTB &= ~(1 << TRANSENABLE); // ToDo: How do I enable transmitter on PC Sleep(10); // short pause to stabilize bus transceiver printf("Sende Paket, length = %u\n", packet->length+5); if (!WriteFile(hComm, packet, packet->length + 5, &nBytes, NULL)) { printf("Error writing text to RS485 port\n"); return 6; } printf("gesendet\n"); fflush(stdout); if (nBytes != packet->length + 5) return 7; printf("kein Fehler\n"); // PORTB |= (1 << TRANSENABLE); // ToDo: How do I disable transmitter on PC return 0; }
排查尝试与猜测
- 尝试过多种超时设置,未解决问题。
- 怀疑是USB/RS485转换器的问题,或者RS485总线中串口检测到自身发送的字节导致异常。
- 猜测阻塞的接收线程导致整个串口被阻塞。
解决方案方向
按照@Codo的建议,尝试使用重叠IO(Overlapped IO),已得到完整解决方案。
内容的提问来源于stack exchange,提问作者Thorsten Erdmann
相关产品推荐
相关产品推荐

