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

Boost ASIO System Timer伪超时问题:串口接收误判为多段传输

串口接收超时判定异常问题排查与解决

当前方案

开发串口程序,规则为:若25毫秒内无新数据接收,则判定当前传输接收完成。首次触发read_handler(Boost ASIO回调方法)时启动定时器,每次新的read_handler调用,都会取消定时器的等待异步操作并重新创建新的定时器异步任务。

问题描述

出现随机异常:单次传输的接收数据被判定为2-3次独立传输,根源是receive_timeout事件(receive_timeout_handler)被多次触发。无法确定问题源于Boost ASIO system_timer的实现/使用错误,还是USB转串口转换器的驱动问题。

测试环境使用FT4232模块(内置4个UART/串口):从UART1发送4KB文本文件,UART0接收数据。预期流程为接收完所有4KB数据后,串口类向主线程发送信号,但实际中有时单次4KB传输会触发2-3次信号。

代码实现

class SerialPort
{
public:
    SerialPort() : io(), port(io), receive_timeout_timer(io) {}
    bool open_port(void);
    bool read_async(std::int32_t read_timeout = -1);
    void read_handler(const boost::system::error_code& error, std::size_t bytes_transferred);
    void receive_timeout_handler(const boost::system::error_code& error);
private:
    boost::asio::io_context         io;
    boost::asio::serial_port        port;
    boost::asio::system_timer       receive_timeout_timer {io};
    std::array<std::byte, 8096>     read_byte_buffer;
    std::string                     received_data;
    std::uint32_t                   read_timeout;
    static constexpr std::uint32_t  bulk_data_receive_complete = 25;
};


bool SerialPort::open_port(void)
{
    try
    {
        this->port.open("COM3");
        return true;
    }
    catch (const std::exception& ex)
    {
        return false;
    }
    return false;
}

bool SerialPort::read_async(std::uint32_t read_timeout)
{
    try
    {
        this->read_byte_buffer.fill(static_cast<std::byte>(0));
        if (read_timeout != -1)
        {
            this->read_timeout = read_timeout;
        }
        this->port.async_read_some(
            boost::asio::buffer(
                this->read_byte_buffer.data(),
                this->read_byte_buffer.size()
            ),
            boost::bind(
                &SerialPort::read_handler,
                this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred
            )
        );
        return true;
    }
    catch (const std::exception& ex)
    {
        return false;
    }
}

void SerialPort::read_handler(const boost::system::error_code& error, std::size_t bytes_transferred)
{
    std::string temporary_recieve_data;
    try
    {
        if (error != boost::system::errc::success)
        {
            this->receive_timeout_timer.cancel();
            return;
        }
        std::transform(this->read_byte_buffer.begin(), this->read_byte_buffer.begin() + bytes_transferred,
            std::back_inserter(temporary_recieve_data), [](std::byte character) {
                return static_cast<char>(character);
            }
        );
        this->received_data += temporary_recieve_data;
        
        this->receive_timeout_timer.cancel();   
        this->receive_timeout_timer.expires_after(boost::asio::chrono::milliseconds(SerialPort::bulk_data_receive_complete));   
        this->receive_timeout_timer.async_wait(boost::bind(&SerialPort::receive_timeout_handler, this, boost::asio::placeholders::error));
        
        this->read_async();
    }
    catch (const std::exception& ex)
    {
    }
}

void SerialPort::receive_timeout_handler(const boost::system::error_code& error)
{
    try
    {
        if (error != boost::system::errc::success)
        {
            return;
        }

        // this->signal(this->port_number, SerialPortEvents::read_data, this->received_data);
        
        this->received_data.clear();
    }
    catch (const std::exception& ex)
    {
    }
}

协议框图

协议框图


问题分析与解决建议

  1. 定时器初始化错误:原代码中receive_timeout_timer {25}初始化参数错误,system_timer构造需传入io_context作为第一个参数,修正后可避免定时器底层行为异常。
  2. 时序逻辑问题:原代码先启动新的异步读取再处理定时器,可能导致旧定时器超时事件已进入执行队列。调整为先更新定时器,再启动新读取,确保新数据到来时能及时终止旧定时器。
  3. 错误处理缺失:读取出错时未取消定时器,可能导致超时事件仍被触发,错误判定传输完成。需在读取错误分支添加定时器取消逻辑。
  4. 缓冲区未重置:超时触发后未清空received_data,会导致下次接收数据与残留数据合并,或重复触发信号。需在超时处理完成后重置缓冲区。
  5. USB转串口设备特性:FT4232的USB批量传输特性可能将数据拆分为多包发送,若包间隔接近25ms会触发多次超时。可微调超时时间(如30ms),或在驱动中增大串口接收缓冲区、启用硬件流控优化传输连续性。

内容的提问来源于stack exchange,提问作者Dark Sorrow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 01:20:41