与Arduino的串行通信仅在重启后的第一条消息上失败

时间:2012-11-09 17:21:04

标签: c++ boost serial-port arduino

我有一个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 个答案:

答案 0 :(得分:1)

如Hans的评论所述,您的通讯协议已关闭。

你的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

答案 1 :(得分: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进行通信,因为它工作得更好。

  4. 第四个选项是希望得到Boost asio专家告诉我们如何在不重置Arduino的情况下打开端口(因为CTB可以做到这一点必须有办法,但我不够专业知道如何做它与Boost)。

答案 2 :(得分:0)

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

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

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

  1. 在RESET和GND线之间连接一个10uF电容
  2. 在RESET
  3. 之间放一个120欧姆的电阻
  4. 永久删除R3以禁用Arduino的自动重置功能。<​​/ li>

答案 3 :(得分:0)

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