5

我有一个 Arduino 设备和 PC。我在板上尝试了以下代码:

gpsdata data;

char needtosend;

void setup() {            
  Serial.begin(9600);
  Serial.flush();  
  data.id = 0;
  data.src= 500;
  data.lat= 1;
  data.lon= 2;
  data.alt= 3;
  strcpy(data.date, "test date format");

}

void loop() {


   if(Serial.available() > 0)
   {
    needtosend = Serial.read();
    if ( needtosend == '2')
    {
      data.id = ++data.id % 10;
    }

    byte* buff = (byte*)&data;
    Serial.write(buff, sizeof(data));

   }
   delay (200);

}

PC 应用程序是用 C++ 编写的,并使用 boost 库与 Arduino 设备进行通信。这是PC代码:

Serial serial("/dev/ttyUSB0",9600);
            gpsdata *data;
            char *values = new char[sizeof(gpsdata)];
    while(true)
    {
        try {

            serial.writeString("2",1);
            serial.read(values,sizeof(gpsdata));
            data = (gpsdata *)values;
            cout<<data->id<<endl;
        } 
        catch(boost::system::system_error& e)
        {
            cout<<"Error: "<<e.what()<<endl;
        }
        catch(timeout_exception& e)
        {
            cout<<"Error: "<<e.what()<<endl;
        }
    }
            delete[] values;


Serial::Serial(std::string port, unsigned int baud_rate): io(), serial(io,port)
{
    serial.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));  
}
void Serial::read(char *data, size_t size)
{
    boost::asio::read(serial,boost::asio::buffer(data,size));
}

void Serial::writeString(const char* s, int length)
{
   boost::asio::write(serial,boost::asio::buffer(s,length))<<std::endl;
}

当我打开设备然后第一次启动 PC 应用程序时,它将字符串“2”发送到设备,然后 read() 阻塞并且从不接收来自 Arduino 的数据。如果我终止应用程序并重新启动它而不重新启动 Arduino,一切都开始正常工作。我尝试了异步读取,结果是一样的,第一条消息的读取超时,然后一切开始正常。在 PC 应用程序中收到的第二条消息的 id 为 1,这意味着 Arduino 尚未收到第一条消息。知道我的错误在哪里吗?

4

4 回答 4

1

正如汉斯在评论中提到的,您的通信协议已关闭。

你的 Arduino 循环基本上说:

读取一个值。如果还有其他可用值,请执行某些操作。等待 0.2 秒。然后重复。

您的 PC 循环说:

发送“2”。然后读取一个值数组。然后重复。

您正在做的事情是,您的通信中的 Arduino 方面正在等待比发送更多的值。在 Arduino 上,轮询Serial.avaliable,然后进行读取。

在 PC 上,您可能不需要更改它。

当您断开连接并重新连接时,会发送一个额外的位来初始化波特连接,这会诱使您的协议正常工作。

编辑:一定要检查串行库连接的设置。以下是我在使用 Qt QextSerialPort 库之前用于连接到 Arduino 板的设置。

port->setFlowControl(FLOW_OFF);
port->setParity(PAR_NONE);
port->setDataBits(DATA_8);
port->setStopBits(STOP_1);
port->setTimeout(500);

以下是两个可能有用的链接:

http://www.webalice.it/fede.tft/serial_port/serial_port.html

https://www.google.com/search?q=arduino+and+boost%3A%3Aasio

于 2012-11-09T18:30:41.533 回答
1

在 Win7 上使用 Boost asio 和 Arduino Uno 时,我在我的一个项目中看到了完全相同的行为。看来,当 Boost 打开串行端口时,它正在发送重置 Arduino 并触发引导加载程序的任何信号(这似乎与从 Arduino IDE 上传代码时发生的事情相同)。

我想出了三种可能的解决方法:

  1. 当 Arduino 意外重置时(当 Boost 打开串行端口时),需要几秒钟才能重新开始工作。这似乎是引导加载程序通常会为 Arduino IDE 开始代码上传提供的时间窗口。在打开端口后等待几秒钟,我可以让事情变得更好:

    serial->open(strPortName);
    SleepEx(2000,false);
    serial->set_option(...);  
    ...
    

    即使使用这种方法,我仍然通常会在第一次读取时得到乱码数据。通常它会在下一次阅读时正常工作。

  2. 丢失引导加载程序。使用与 Arduino IDE 不同的方法通过 6 针 ISP 对 Arduino 进行编程。这涉及放弃 Arduino IDE 并使用 AVR Studio 之类的东西和某种硬件 ISP 程序员。如果你走那条路,请参考:http ://www.engblaze.com/tutorial-using-atmel-studio-6-with-arduino-projects/

  3. 切换库。我已经看到使用 Boost 的上述行为,但在使用 Boost 之前,我使用的是 CTB 库(https://iftools.com/opensource/ctb.en.php),它运行良好并且在打开时没有重置 Arduino串口。在我的项目中,我最初切换到 Boost 以获得它提供的其他功能,但我切换回 CTB 进行通信,因为它工作得更好。

第四种选择是希望让 Boost asio 专家告诉我们如何在不重置 Arduino 的情况下打开端口(因为 CTB 可以做到,所以必须有办法,但我不够专业,不知道如何使用 Boost )。

于 2012-11-11T05:40:15.560 回答
0

从 Arduino 网站上的硬件角度来看,对此进行了非常彻底的处理:

http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection

它也解释了这个问题的一些硬件解决方案,包括:

  1. 在 RESET 和 GND 线之间连接一个 10uF 电容
  2. 在 RESET 之间放一个 120 欧姆的电阻
  3. 永久移除 R3 以禁用 Arduino 的自动复位功能。
于 2013-02-24T05:18:20.857 回答
0

只需导入时间库并time.sleep(2)在行后添加Serial.begin(9600);

于 2013-03-30T09:24:28.803 回答