arduino与processing串口通信问题

6 篇文章 0 订阅
1 篇文章 0 订阅

最近进行Arduino与processing串口通信时遇到了这种问题,觉得这篇博文写的很对,就转了下来,在此感谢原博主“行走的仙人”。

http://guoyunhe.me/zh/2013/03/10/arduino与processing的串口通信/

在网络上普遍存在的Arduino与Processing互动的例子,都具有一个很简单的构造:Arduino上用Serial.print()发送,在Processing中用Serial.readString()读取,或者反过来。然而实际应用过程中大家就会发现这个简单的逻辑模型会发生莫名其妙的错误。最显著的是有时候会收到空值,即使用Serial.available()检测,也会有时收到间断的字符串或者多个字符串混在一起了。

下面是一个经典的Processing与Arduino通信实例:

//Processing Code

import processing.serial.*;


Serial myPort;


void setup(){

  myPort = new Serial(this,"/dev/ttyACM0", 115200); //Set Serial Port


}


void draw(){

  if(myPort.available()>0){

    String message = myPort.readString();

    println(message);

  }

}

//Arduino code

int data=12345; 

void setup()

{

  Serial.begin(115200);//rate

}

void loop()

{

  Serial.print(data); //send data

  delay(1000);

}

然后我们期待着每次获取“12345”并显示在屏幕上,但事与愿违,我们得到的情况是这样的:

12345

123

45

12345

12345

输出时的中断是怎样产生的呢?要探究这个问题的根源,需要重新审视串口通信的原理。

串口通讯就像一趟公共汽车,每个字节是一个在等车的人。他来到车站(发送数据),车还没有来,所以新来的人就一直等待(缓存)。当公共汽车来了的时候,将这些人一次接走(读取数据),当然车也是有容量的,只能载一定数量的人(缓存大小)。现在有一个旅行团(字符串/字符数组),一部分人走在前面刚刚赶上了车(被读取),而另一部分人没赶上,只能等待下一班车(下一次读取)。另一种情况是,两个旅行团都在车站等车,被同一班车接走了。这就是为什么我们读取的时候字符串会断成两节,或者并起来。

核心原因是:串口流通的数据都是bytes而没有字符串概念,所有发送数据都会按一个byte一个byte缓存,不论是否是连续字符串;而读取时会取走所有缓存bytes,不论它们是否是一个、半个还是多个字符串。

Arduino和Processing的数据收发速度是不一样的。如果用Arduino延时较长时间,Processing可能读取一个字符串或字符串的一部分。如果Arduino延时较短,Processing可能读取多个字符串,但不一定完整。在读取字符串的时候,无法确定上一个字符串是否被读取了,当前字符串是否缓存完毕,因为字符串都已经切成了bytes,连成一串。这个问题是串口通信本身造成的,一定会出现。

一种解决方法是,通过在接收端缓存数据来解决这个问题。为传输数据设置一个结束标记,如’\n’(换行符),就能在接收到的数据流中识别到一个字符串的结尾。当未遇到结束标记,就一直将串口数据保存在一个buffer变量中,继续接收。

Processing的SerialEvent事件类型就提供了这种方式,使用bufferUntil(ch)可以在遇到某个指定字符时才完成缓存。

程序实例:

//Processing Code

import processing.serial.*;


Serial myPort;


void setup(){

  myPort = new Serial(this,"/dev/ttyACM0", 115200);  //in fact, any rate is ok...

  myPort.bufferUntil('\n');  //buffer until meet '\n', then call the event listener

}


void draw(){


}


//listen to the event. when buffer filled, run this method

void serialEvent(Serial p) {

  String inString = p.readString();

  print(inString);

}


//then the buffer will reveive all the bytes

//Arduino Code

int data=12345; 

void setup()

{

  Serial.begin(115200);//rate

}

void loop()

{

  Serial.println(data); //send data, end up with '\n'

  delay(1000);

}

当然,这种方法也可以用在普通的串口通信中,不必使用SerialEvent。接收的数据不直接使用,而是作为缓存。若未遇到结束标记,就继续读取下一次。当遇到结束标记,即完成缓存。

程序实例:

//Processing Code

import processing.serial.*;


String message;

String temp;

Serial myPort;


void setup(){

  myPort = new Serial(this,"/dev/ttyACM0", 115200); //Set Serial Port

}


void draw(){

  if(myPort.available()>0){

    temp = myPort.readString(); //temp for read bytes

    for(int i = 0; i < temp.length(); i++){

      //if meet the end mark

      if(temp.charAt(i) == '\n'){

        println(message);

        message = "";  //clean string

      }

      else

        message += temp.charAt(i);  //store byte

    }

  }

}

//Arduino Code

int data=12345; 

void setup()

{

  Serial.begin(115200);//rate

}

void loop()

{

  Serial.println(data); //send data, end up with '\n'

  delay(1000);

}


  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值