我正在开发Windows应用程序,该应用程序必须通过其串行端口与Arduino通信(输入和输出)。出于可移植性原因,我正在使用boost :: asio,我想继续使用它。发生的情况是,第一次运行应用程序时,它运行良好,但是如果第二次运行,则不再有来自Arduino的数据,并且应用程序卡在了读取操作上。恢复的唯一方法是从计算机上拔下并重新连接Arduino USB电缆。
此行为是Windows特定的。相同的代码可以在Linux上完美运行。
编译器是Visual Studio 2017 Community Edition。
以下是重现此问题的示例代码:
#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
}
这是Arduino草图(从Arduino网站获得):
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
有没有办法恢复连接的正确状态?我想念什么吗?
答案 0 :(得分:0)
USB串行适配器可能存在设备驱动程序错误和硬件问题。您必须拔出并重新插入设备才能使它重新工作,这一事实表明设备驱动程序存在错误。
答案 1 :(得分:0)
学到了几件事之后,下面是解决方法:
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());
}
并用它替换问题示例中的port.set_option(
行。
我还将流控制设置为DTR_CONTROL_ENABLE
而不是原始的none
,以便在连接时重置Arduino。