C++ 如何使用boost::asio通过串行连接正确编写Win32应用程序

C++ 如何使用boost::asio通过串行连接正确编写Win32应用程序,c++,boost,arduino,serial-port,C++,Boost,Arduino,Serial Port,我正在开发一个Windows应用程序,它必须通过其串行端口与Arduino进行通信(输入和输出)。出于可移植性的原因,我正在使用boost::asio,我希望继续使用它。发生的情况是,第一次运行应用程序时,它工作得很好,但如果第二次运行,则不再有来自Arduino的数据,应用程序将停止读取操作。恢复的唯一方法是从计算机上拔下并重新插入Arduino USB电缆 此行为特定于Windows。同样的代码在Linux上也能完美地工作 编译器是Visual Studio 2017社区版 下面是重现问题的

我正在开发一个Windows应用程序,它必须通过其串行端口与Arduino进行通信(输入和输出)。出于可移植性的原因,我正在使用boost::asio,我希望继续使用它。发生的情况是,第一次运行应用程序时,它工作得很好,但如果第二次运行,则不再有来自Arduino的数据,应用程序将停止读取操作。恢复的唯一方法是从计算机上拔下并重新插入Arduino USB电缆

此行为特定于Windows。同样的代码在Linux上也能完美地工作

编译器是Visual Studio 2017社区版

下面是重现问题的示例代码:

#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <vector>


int main() {
  boost::asio::serial_port port(ioctx, "COM3"); // "/dev/ttyACM0" on Linux

  port.set_option(boost::asio::serial_port::baud_rate(9600));
  port.set_option(boost::asio::serial_port::character_size(8));
  port.set_option(boost::asio::serial_port::stop_bits(boost::asio::serial_port::stop_bits::one));
  port.set_option(boost::asio::serial_port::parity(boost::asio::serial_port::parity::none));
  port.set_option(boost::asio::serial_port::flow_control(boost::asio::serial_port::flow_control::none));
  char c = 'e';
  auto const s = boost::asio::write(port, boost::asio::buffer(&c, 1));
  std::cout << "sent " << s << " bytes" << std::endl;
  boost::asio::streambuf response;
  boost::asio::read_until(port, response, "\r\n");
  std::istream response_stream(&response);
  std::string line;
  std::getline(response_stream, line);
  std::cout << line << std::endl;

  port.close(); // last-ditch effort to get it working
}

有没有办法恢复连接的正确状态?我遗漏了什么吗?

USB串行适配器可能有设备驱动程序错误和硬件问题。您必须拔下并插入设备才能使其重新工作,这表明存在设备驱动程序错误

  • 寻找更新的驱动程序。它可能是一个多产或FTDI芯片组,确保你从芯片制造商那里得到驱动程序。看到或
  • 如果是与流量控制相关的硬件问题,您可以将DTR、DSR和CD引脚连接在一起,并将USB适配器上RS-232接口上的RTS和CTS引脚连接在一起。我见过USB适配器,这是必要的,尽管设置没有流量控制的软件

在学习了一些东西之后,下面是解决方案:

  • Arduino使用其USB通信来烧录草图和在PC上来回传输数据。引导序列预计,在2秒钟内(对于新的Arduino版本和标准引导加载程序),与引导加载程序的通信处于活动状态。之后,将执行草图
  • Windows API允许通过
    SetCommState
    函数一次设置所有连接参数,并以与
    GetCommState
    函数类似的方式检索它们。这是
    set_option
    函数用来设置参数的方法,但是在一行中多次调用
    GetCommState
    -
    SetCommState
    会大大降低过程的速度(可能是通过多次重置Arduino)
  • 我结束了以下函数的编写:

        #include <Windows.h>
        #include <chrono>
    
        void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
        {
          DCB dcbSerialParams = { 0 };
          GetCommState(port.native_handle(), &dcbSerialParams);
          // this is the optimal way to set the whole serial port configuration
          // just in one shot.
          dcbSerialParams.BaudRate = CBR_9600;
          dcbSerialParams.ByteSize = 8;
          dcbSerialParams.StopBits = ONESTOPBIT;
          dcbSerialParams.Parity = NOPARITY;
          //Setting the DTR to Control_Enable ensures that the Arduino is properly
          //reset upon establishing a connection
          dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
          SetCommState(port.native_handle(), &dcbSerialParams);
          PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);
    
          // Wait for Arduino to boot the sketch
          Sleep(sleep.count());
        }
    
    #包括
    #包括
    void init_arduino(boost::asio::串行端口和端口,std::chrono::毫秒常量和睡眠=2000)
    {
    DCB dcbSerialParams={0};
    GetCommState(port.native_handle(),&dcbSerialParams);
    //这是设置整个串行端口配置的最佳方式
    //就这么一枪。
    dcbSerialParams.BaudRate=CBR_9600;
    dcbSerialParams.ByteSize=8;
    dcbSerialParams.StopBits=一个停止位;
    dcbSerialParams.奇偶性=无奇偶性;
    //将DTR设置为Control_Enable可确保Arduino正常运行
    //建立连接后重置
    dcbSerialParams.fDtrControl=DTR\u CONTROL\u ENABLE;
    SetCommState(port.native_handle(),&dcbSerialParams);
    PurgeComm(port.native_handle(),PURGE_RXCLEAR | PURGE_TXCLEAR);
    //等待Arduino启动草图
    Sleep(Sleep.count());
    }
    
    并使用它替换问题示例中的
    port.set_选项(
    行)


    我还将流量控制设置为
    DTR\u control\u ENABLE
    ,而不是原来的
    none
    ,以便在连接时重置Arduino。

    谢谢您的发帖,我只是在自己回答问题的过程中。的确,出现了错误,但在这种情况下,它既不是驱动程序,也不是硬件。Arduino正在工作在Linux下以及Windows上使用Arduino IDE串行监视器时,g都非常完美。
        #include <Windows.h>
        #include <chrono>
    
        void init_arduino(boost::asio::serial_port& port, std::chrono::milliseconds const& sleep = 2000)
        {
          DCB dcbSerialParams = { 0 };
          GetCommState(port.native_handle(), &dcbSerialParams);
          // this is the optimal way to set the whole serial port configuration
          // just in one shot.
          dcbSerialParams.BaudRate = CBR_9600;
          dcbSerialParams.ByteSize = 8;
          dcbSerialParams.StopBits = ONESTOPBIT;
          dcbSerialParams.Parity = NOPARITY;
          //Setting the DTR to Control_Enable ensures that the Arduino is properly
          //reset upon establishing a connection
          dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
          SetCommState(port.native_handle(), &dcbSerialParams);
          PurgeComm(port.native_handle(), PURGE_RXCLEAR | PURGE_TXCLEAR);
    
          // Wait for Arduino to boot the sketch
          Sleep(sleep.count());
        }