Windows平台下C语言实现RS-232流控制失效问题求助
问题:RS-232与HP 7550绘图仪通信时流控制失效
用C语言编写程序通过RS-232与HP 7550绘图仪通信,流控制功能无法正常工作:
- 使用TeraTerm等终端程序时,XON/XOFF流控制运行正常;
- 用自己的程序发送数据时,流控制被忽略,绘图仪缓冲区溢出;
- 观察USB转RS-232适配器LED,确认绘图仪已发送XOFF字符,但PC端仍持续发送数据。
已尝试XON/XOFF和RTS/CTS两种流控制,更换两款RS-232适配器及两台PC(Windows 7 Ultimate、Windows 10 Professional),问题依旧。
现有代码
串口初始化与配置函数
// Function openPort // - Opens a serial port with a port name provided in the format "\\.\COM#" HANDLE openPort(char *portName) { HANDLE serialPort; COMMTIMEOUTS timeouts = {0}; // open the port //printf("opening serial port . . . "); serialPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL); // open the port if(serialPort == INVALID_HANDLE_VALUE) { //printf("failed\n"); return NULL; } else //printf("ok\n"); // set up timeouts //printf("Setting up timeouts . . . "); timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if(!SetCommTimeouts(serialPort, &timeouts)) { //printf("failed - could not set timeouts\n"); return NULL; } if(!SetCommMask(serialPort, EV_RXCHAR)) { //printf("failed - could not set comm mask\n"); return NULL; } //printf("ok\n"); return serialPort; } // Function setupPort // - Sets up the paramters of the serial port bool setupPort(HANDLE *serialPort, int baudRate, int byteSize, int stopBits, char parityType[], char flowControl[]) { DCB dcb = {0}; bool error = false; if(GetCommState(serialPort, &dcb)) { //printf("Setting up serial port parameters . . .\n"); // basic setup parameters dcb.fBinary = true; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = false; dcb.fTXContinueOnXoff = false; dcb.fOutX = false; dcb.fInX = false; dcb.fErrorChar = false; dcb.fNull = false; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fAbortOnError = false; dcb.fOutxCtsFlow = false; dcb.fOutxDsrFlow = false; // set up baud rate and byte size dcb.BaudRate = baudRate; dcb.ByteSize = byteSize; // set up stop bits //printf("Setting up stop bits . . . "); switch(stopBits) { case 1: dcb.StopBits = ONESTOPBIT; //printf("ok\n"); break; case 2: dcb.StopBits = TWOSTOPBITS; //printf("ok\n"); break; default: //printf("Invalid number of stop bits\n"); error = true; } // set up parity //printf("Configuring %s parity . . . ", parityType); if(parityType == "NONE") { dcb.Parity = NOPARITY; //printf("ok\n"); } else if(parityType == "ODD") { dcb.Parity = ODDPARITY; //printf("ok\n"); } else if(parityType == "EVEN") { dcb.Parity = EVENPARITY; //printf("ok\n"); } else if(parityType == "MARK") { dcb.Parity = MARKPARITY; //printf("ok\n"); } else if(parityType == "SPACE") { dcb.Parity = SPACEPARITY; //printf("ok\n"); } else { //printf("Invalid parity type\n"); error = true; } // set up flow control //printf("Configuring %s flow control . . . ", flowControl); if(flowControl == "NONE") { //printf("ok\n"); } else if(flowControl == "XONXOFF") { dcb.fOutX = true; dcb.fInX = true; //printf("ok\n"); } else if(flowControl == "RTS/CTS") { dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutxCtsFlow = true; //printf("ok\n"); } else if(flowControl == "DSR/DTR") { dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fOutxDsrFlow = true; //printf("ok\n"); } else { //printf("Invaid flow control type\n"); error = true; } } if(!SetCommState(serialPort, &dcb)) { error = true; } return error; }
串口写数据函数
// Function writeData // - Writes an array of chars to the port bool writeData(HANDLE serialPort, const char *data) { DWORD dataSize = strlen(data); DWORD bytesWritten; return WriteFile(serialPort, data, dataSize, &bytesWritten, NULL); }
串口初始化调用代码
// Function initSerial(): // This function initializes the serial connection for the plotter to communicate // It takes five arguments: // - portNumber (1-255) // - baudRate (110, 220, 440, 680, 1200, 2400, 4800, or 9600 baud) // - dataBits (7 or 8) // - parity (NONE, ODD, EVEN, MARK, SPACE) // - flowControl(NONE, XONXOFF, RTS/CTS, DSR/DTR) HANDLE initSerial(int portNumber, int baudRate, int dataBits, char* parity, char* flowControl) { char s[13]; sprintf(s, "\\.\COM%d", portNumber); // format COM port number HANDLE serialPort = openPort(s); setupPort(serialPort, baudRate, dataBits, 1, parity, flowControl); return serialPort; }
调用方式:
HANDLE port = initSerial(12, 9600, 8, "NONE", "XONXOFF");
问题根源与修复方案
1. 串口句柄参数类型不匹配
setupPort函数的第一个参数是HANDLE*(串口句柄指针),但initSerial中调用时传入的是serialPort(HANDLE类型,非指针),导致GetCommState调用失败,整个串口配置未生效。
修复:
修改initSerial中的调用代码,传入句柄的地址:
setupPort(&serialPort, baudRate, dataBits, 1, parity, flowControl);
2. 字符串比较错误
C语言中不能用==直接比较字符串内容,parityType == "NONE"这类写法比较的是指针地址,而非字符串内容,导致 parity 和流控制的配置逻辑完全失效。
修复:
用strcmp函数替代==进行字符串比较,例如:
// 校验配置部分 if(strcmp(parityType, "NONE") == 0) { dcb.Parity = NOPARITY; } else if(strcmp(parityType, "ODD") == 0) { dcb.Parity = ODDPARITY; // ... 其他校验分支同理 } // 流控制配置部分 if(strcmp(flowControl, "NONE") == 0) { // do nothing } else if(strcmp(flowControl, "XONXOFF") == 0) { dcb.fOutX = true; dcb.fInX = true; // ... 其他流控制分支同理 }
3. XON/XOFF流控制参数优化
对于软件流控,建议调整fTXContinueOnXoff参数为TRUE,确保收到XOFF后,先发送完当前缓冲区中的数据再停止,避免数据截断:
dcb.fTXContinueOnXoff = TRUE;
4. 路径转义符与错误检查修正
原代码中串口路径写法错误,Windows下的串口路径应为\\\\.\\COMx,需修正转义符;同时增加配置失败后的错误处理:
HANDLE initSerial(int portNumber, int baudRate, int dataBits, char* parity, char* flowControl) { char s[13]; sprintf(s, "\\\\.\\COM%d", portNumber); // 修正路径转义符 HANDLE serialPort = openPort(s); if(serialPort != INVALID_HANDLE_VALUE) { bool configError = setupPort(&serialPort, baudRate, dataBits, 1, parity, flowControl); if(configError) { // 配置失败,关闭端口 CloseHandle(serialPort); return NULL; } } return serialPort; }
内容的提问来源于stack exchange,提问作者PatrioticStripey
相关产品推荐
相关产品推荐

