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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:10:58