Java串口通信的通用模式及其问题
2015-11-21 21:45
363 查看
通常,串口通信应用程序有两种模式,一种是实现SerialPortEventListener接口,监听各种串口事件并作相应处理;另一种是建立一个独立的接收线程专门负责数据的接收。但这两种方法在某些情况下存在很严重的问题。
事件监听模型
事件监听模型的运作方式:
(1)首先需要在端口控制类(如SerialManager)加上“implements SerialPortEventListener”
(2)在初始化时加入如下代码:
(3)覆写public void serialEvent(SerialPortEvent e)方法,在其中对事件进行判断。
BI -通讯中断.
CD -载波检测.
CTS -清除发送.
DATA_AVAILABLE -有数据到达.
DSR -数据设备准备好.
FE -帧错误.
OE -溢位错误.
OUTPUT_BUFFER_EMPTY -输出缓冲区已清空.
PE -奇偶校验错.
RI - 振铃指示.
一般最常用的就是DATA_AVAILABLE--串口有数据到达事件。也就是说当串口有数据到达时,可以在serialEvent中接收并处理所收到的数据。此模式存在的问题:数据有丢失。
串口读数据的线程模型
这个模型顾名思义,就是将接收数据的操作写成一个线程的形式。将收到的数据打包放到一个缓存中,然后启动另一个线程从缓存中获取并处理数据。两个线程以生产者—消费者模式协同工作,数据的流向如下图所示:
此模式存在的问题:传感器节点已经停止传送数据,但是串口线程依然在执行读串口的操作。原因是传感器节点发送数据过快,而接收线程处理不过来,所以InputStream就先把已经到达却还没处理的字节缓存起来,于是就导致了明明传感器节点已经不再发数据了,而控制台却还能看见数据不断打印的现象。简言之,线程模型导致了对于发送端数据发送速率过快的情况下的数据接收延迟。
申明一点,对于数据发送速率不是很快的情况下,前两种模型应该还是好用的,只是特殊情况应该特殊处理。
第三种方法(根源入手)
解决上述问题的方法其实很简单,就是从根源入手。根源就是接收线程导致的,那干脆取消接收线程和作为中介的共享缓存,而直接在处理线程中调用串口读数据的方法来解决问题(为什么不把处理线程也一并取消?----都取消应用程序界面会锁死,所以必须保留)于是程序变成了这样:
在处理线程中调用这个方法返回所需要的数据序列并处理之,这样不但没有丢失数据的现象出现,也没有数据接收延迟了。这里唯一需要注意的就是当串口停止发送数据或没有数据的时候is.read()一直都返回-1,如果一旦在开始接收数据的时候发现-1就不要理它,继续接收,直到收到真正的数据为止。
事件监听模型
事件监听模型的运作方式:
(1)首先需要在端口控制类(如SerialManager)加上“implements SerialPortEventListener”
(2)在初始化时加入如下代码:
try { SerialPort sPort.addEventListener(SerialManager); } catch (TooManyListenersException e) { throw new SerialConnectionException("too many listeners added"); sPort.close(); } sPort.notifyOnDataAvailable(true);
(3)覆写public void serialEvent(SerialPortEvent e)方法,在其中对事件进行判断。
BI -通讯中断.
CD -载波检测.
CTS -清除发送.
DATA_AVAILABLE -有数据到达.
DSR -数据设备准备好.
FE -帧错误.
OE -溢位错误.
OUTPUT_BUFFER_EMPTY -输出缓冲区已清空.
PE -奇偶校验错.
RI - 振铃指示.
一般最常用的就是DATA_AVAILABLE--串口有数据到达事件。也就是说当串口有数据到达时,可以在serialEvent中接收并处理所收到的数据。此模式存在的问题:数据有丢失。
串口读数据的线程模型
这个模型顾名思义,就是将接收数据的操作写成一个线程的形式。将收到的数据打包放到一个缓存中,然后启动另一个线程从缓存中获取并处理数据。两个线程以生产者—消费者模式协同工作,数据的流向如下图所示:
此模式存在的问题:传感器节点已经停止传送数据,但是串口线程依然在执行读串口的操作。原因是传感器节点发送数据过快,而接收线程处理不过来,所以InputStream就先把已经到达却还没处理的字节缓存起来,于是就导致了明明传感器节点已经不再发数据了,而控制台却还能看见数据不断打印的现象。简言之,线程模型导致了对于发送端数据发送速率过快的情况下的数据接收延迟。
申明一点,对于数据发送速率不是很快的情况下,前两种模型应该还是好用的,只是特殊情况应该特殊处理。
第三种方法(根源入手)
解决上述问题的方法其实很简单,就是从根源入手。根源就是接收线程导致的,那干脆取消接收线程和作为中介的共享缓存,而直接在处理线程中调用串口读数据的方法来解决问题(为什么不把处理线程也一并取消?----都取消应用程序界面会锁死,所以必须保留)于是程序变成了这样:
public byte[] getPack(){ while (true) { // PacketLength为数据包长度 byte[] msgPack = new byte[PacketLength]; if( (newData = is.read()) != -1){ for(int i = 0; i < PacketLength; i++){ msgPack[i] = (byte) newData; } System.out.println(msgPack[i]); } } return msgPack; }
在处理线程中调用这个方法返回所需要的数据序列并处理之,这样不但没有丢失数据的现象出现,也没有数据接收延迟了。这里唯一需要注意的就是当串口停止发送数据或没有数据的时候is.read()一直都返回-1,如果一旦在开始接收数据的时候发现-1就不要理它,继续接收,直到收到真正的数据为止。
相关文章推荐
- 防止服务器宕机时MySQL数据丢失的几种方案
- Iphone里面的数据丢失了怎么办
- Boost.asio 一些注意事项
- 造成数据丢失的原因有哪些
- SQL陷阱之leftjoin的where条件
- RabbitMQ消息队列(三):任务分发机制
- 深圳建筑公司数据恢复纪实
- 雅虎回应数据丢失:备份是自己的问题
- lvm灾难性恢复
- 制定数据丢失防范策略的六个要点 推荐
- 下厨房数据丢失引发的自我反思
- 数据丢失后都能恢复吗?
- POST提交大量数据数据丢失问题
- Mysql分页查询丢失数据
- IIS WebService 内存溢出问题的修改过程
- Kafka重复消费和丢失数据研究
- 解决:MySQL Load Data数据丢失问题
- greendao操作数据库升级导致表数据丢失
- STM32学习笔记8——串口输出数据丢失问题
- 两个fragment之间跳转listview数据丢失