自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

簡單介紹Java的串口通信(下)

開發(fā) 后端
串行接口是一種可以將接受來自CPU的并行數(shù)據(jù)字符轉(zhuǎn)換為連續(xù)的串行數(shù)據(jù)流發(fā)送出去,同時(shí)可將接受的串行數(shù)據(jù)流轉(zhuǎn)換為并行的數(shù)據(jù)字符供給CPU的器件。本文介紹的是JAVA的串口通信。

串行接口是一種可以將接受來自CPU的并行數(shù)據(jù)字符轉(zhuǎn)換為連續(xù)的串行數(shù)據(jù)流發(fā)送出去,同時(shí)可將接受的串行數(shù)據(jù)流轉(zhuǎn)換為并行的數(shù)據(jù)字符供給CPU的器件。簡單介紹Java的串口通信。接上一篇>>

3.1 事件監(jiān)聽模型

現(xiàn)在我們來看看事件監(jiān)聽模型是如何運(yùn)作的:

首先需要在你的端口控制類(例如SManager)加上“implements SerialPortEventListener”

在初始化時(shí)加入如下代碼:

  1. try {  
  2. SerialPort sPort.addEventListener(SManager);  
  3. catch (TooManyListenersException e) {  
  4. sPort.close();  
  5. throw new SerialConnectionException("too many listeners added");  
  6. }  
  7. sPort.notifyOnDataAvailable(true); 

 

覆寫public void serialEvent(SerialPortEvent e)方法,在其中對(duì)如下事件進(jìn)行判斷:

  • BI -通訊中斷.
  • CD -載波檢測(cè).
  • CTS -清除發(fā)送.
  • DATA_AVAILABLE -有數(shù)據(jù)到達(dá).
  • DSR -數(shù)據(jù)設(shè)備準(zhǔn)備好.
  • FE -幀錯(cuò)誤.
  • OE -溢位錯(cuò)誤.
  • OUTPUT_BUFFER_EMPTY -輸出緩沖區(qū)已清空.
  • PE -奇偶校驗(yàn)錯(cuò).
  • RI - 振鈴指示.

一般最常用的就是DATA_AVAILABLE--串口有數(shù)據(jù)到達(dá)事件。也就是說當(dāng)串口有數(shù)據(jù)到達(dá)時(shí),你可以在serialEvent中接收并處理所收到的數(shù)據(jù)。然而在我的實(shí)踐中,遇到了一個(gè)十分嚴(yán)重的問題。

首先描述一下我的實(shí)驗(yàn):我的應(yīng)用程序需要接收傳感器節(jié)點(diǎn)從串口發(fā)回的查詢數(shù)據(jù),并將結(jié)果以圖標(biāo)的形式顯示出來。串口設(shè)定的波特率是 115200,川口每隔128毫秒返回一組數(shù)據(jù)(大約是30字節(jié)左右),周期(即持續(xù)時(shí)間)為31秒。實(shí)測(cè)的時(shí)候在一個(gè)周期內(nèi)應(yīng)該返回4900多個(gè)字節(jié),而用事件監(jiān)聽模型我最多只能收到不到1500字節(jié),不知道這些字節(jié)都跑哪里去了,也不清楚到底丟失的是那部分?jǐn)?shù)據(jù)。值得注意的是,這是我將 serialEvent()中所有處理代碼都注掉,只剩下打印代碼所得的結(jié)果。數(shù)據(jù)丟失的如此嚴(yán)重是我所不能忍受的,于是我決定采用其他方法。

3.2 串口讀數(shù)據(jù)的線程模型

這個(gè)模型顧名思義,就是將接收數(shù)據(jù)的操作寫成一個(gè)線程的形式:

  1. public void startReadingDataThread() {  
  2. Thread readDataProcess = new Thread(new Runnable() {  
  3. public void run() {  
  4. while (newData != -1) {  
  5. try {  
  6. newData = is.read();  
  7. System.out.println(newData);  
  8. //其他的處理過程  
  9. ……….  
  10. catch (IOException ex) {  
  11. System.err.println(ex);  
  12. return;  
  13. }  
  14. }  
  15. readDataProcess.start();  

 

在我的應(yīng)用程序中,我將收到的數(shù)據(jù)打包放到一個(gè)緩存中,然后啟動(dòng)另一個(gè)線程從緩存中獲取并處理數(shù)據(jù)。兩個(gè)線程以生產(chǎn)者—消費(fèi)者模式協(xié)同工作。

這樣,我就圓滿解決了丟數(shù)據(jù)問題。然而,沒高興多久我就又發(fā)現(xiàn)了一個(gè)同樣嚴(yán)重的問題:雖然這回不再丟數(shù)據(jù)了,可是原本一個(gè)周期(31秒)之后,傳感器節(jié)電已經(jīng)停止傳送數(shù)據(jù)了,但我的串口線程依然在努力的執(zhí)行讀串口操作,在控制臺(tái)也可以看見收到的數(shù)據(jù)仍在不斷的打印。

原來,由于傳感器節(jié)點(diǎn)發(fā)送的數(shù)據(jù)過快,而我的接收線程處理不過來,所以InputStream就先把已到達(dá)卻還沒處理的字節(jié)緩存起來,于是就導(dǎo)致了明明傳感器節(jié)點(diǎn)已經(jīng)不再發(fā)數(shù)據(jù)了,而控制臺(tái)卻還能看見數(shù)據(jù)不斷打印這一奇怪的現(xiàn)象。唯一值得慶幸的是最后收到數(shù)據(jù)確實(shí)是4900左右字節(jié),沒出現(xiàn)丟失現(xiàn)象。然而當(dāng)處理完最后一個(gè)數(shù)據(jù)的時(shí)候已經(jīng)快1分半鐘了,這個(gè)時(shí)間遠(yuǎn)遠(yuǎn)大于節(jié)點(diǎn)運(yùn)行周期。這一延遲對(duì)于一個(gè)實(shí)時(shí)的顯示系統(tǒng)來說簡直是災(zāi)難!

后來我想,是不是由于兩個(gè)線程之間的同步和通信導(dǎo)致了數(shù)據(jù)接收緩慢呢?于是我在接收線程的代碼中去掉了所有處理代碼,僅保留打印收到數(shù)據(jù)的語句,結(jié)果依然如故??磥聿⒉皇蔷€程間的通信阻礙了數(shù)據(jù)的接收速度,而是用線程模型導(dǎo)致了對(duì)于發(fā)送端數(shù)據(jù)發(fā)送速率過快的情況下的數(shù)據(jù)接收延遲。這里申明一點(diǎn),就是對(duì)于數(shù)據(jù)發(fā)送速率不是如此快的情況下前面者兩種模型應(yīng)該還是好用的,只是特殊情況還是應(yīng)該特殊處理。

3.3 第三種方法

痛苦了許久(Boss天天催我L)之后,偶然的機(jī)會(huì),我聽說TinyOS中(又是開源的)有一部分是和我的應(yīng)用程序類似的串口通信部分,于是我下載了它的1.x版的Java代碼部分,參考了它的處理方法。

解決問題的方法說穿了其實(shí)很簡單,就是從根源入手。根源不就是接收線程導(dǎo)致的嗎,那好,我就干脆取消接收線程和作為中介的共享緩存,而直接在處理線程中調(diào)用串口讀數(shù)據(jù)的方法來解決問題(什么,為什么不把處理線程也一并取消?----都取消應(yīng)用程序界面不就鎖死了嗎?所以必須保留)于是程序變成了這樣:

  1. public byte[] getPack(){  
  2. while (true) {  
  3. // PacketLength為數(shù)據(jù)包長度  
  4. byte[] msgPack = new byte[PacketLength];  
  5. for(int i = 0; i < PacketLength; i++){  
  6. if( (newData = is.read()) != -1){  
  7. msgPack[i] = (byte) newData;  
  8. System.out.println(msgPack[i]);  
  9. }  
  10. }  
  11. return msgPack;  
  12. }  

 

在處理線程中調(diào)用這個(gè)方法返回所需要的數(shù)據(jù)序列并處理之,這樣不但沒有丟失數(shù)據(jù)的現(xiàn)象行出現(xiàn),也沒有數(shù)據(jù)接收延遲了。這里唯一需要注意的就是當(dāng)串口停止發(fā)送數(shù)據(jù)或沒有數(shù)據(jù)的時(shí)候is.read()一直都返回-1,如果一旦在開始接收數(shù)據(jù)的時(shí)候發(fā)現(xiàn)-1就不要理它,繼續(xù)接收,直到收到真正的數(shù)據(jù)為止。

4 結(jié)束語

本文介紹了串口通信的基本知識(shí),以及常用的幾種模式。通過實(shí)踐,提出了一些問題,并在最后加以解決。值得注意的是對(duì)于第一種方法,我曾將傳感器發(fā)送的時(shí)間由128毫秒增加到512毫秒,仍然有很嚴(yán)重的數(shù)據(jù)丟失現(xiàn)象發(fā)生,所以如果你的應(yīng)用程序需要很精密的結(jié)果,傳輸數(shù)據(jù)的速率又很快的話,就最好不要用第一種方法。

對(duì)于第二種方法,由于是線程導(dǎo)致的問題,所以對(duì)于不同的機(jī)器應(yīng)該會(huì)有不同的表現(xiàn),對(duì)于那些處理多線程比較好的機(jī)器來說,應(yīng)該會(huì)好一些。但是我的機(jī)器是Inter 奔四3.0雙核CPU+512DDR內(nèi)存,這樣都延遲這么厲害,還得多強(qiáng)的CPU才行啊?

所以對(duì)于數(shù)據(jù)量比較大的傳輸來說,還是用第三種方法吧。不過這個(gè)世界問題是很多的,而且未知的問題比已知的問題多的多,說不定還有什么其他問題存在,歡迎你通過下面的聯(lián)系方式和我一起研究。

責(zé)任編輯:于鐵 來源: 互聯(lián)網(wǎng)
相關(guān)推薦

2011-07-11 14:12:19

Java串口通信

2010-01-05 17:39:10

.NET Framew

2010-03-16 10:10:57

Java線程通信

2024-12-24 07:38:44

C#串口通信

2011-06-22 17:49:35

Linux Qt 串口

2011-08-30 13:48:50

phpmyadmin

2011-06-28 11:27:19

java克隆對(duì)象

2010-06-11 11:15:33

Linux編程工具

2011-07-20 16:13:03

SQL Profile數(shù)據(jù)庫

2011-07-04 10:04:52

java網(wǎng)絡(luò)程序

2011-06-27 13:17:07

Java EE

2011-06-13 17:46:07

Qt 串口通信

2011-08-22 15:19:25

2011-07-26 18:22:42

MySQL Workb數(shù)據(jù)庫

2010-06-13 17:57:23

局域網(wǎng)協(xié)議

2009-06-25 16:52:34

2011-03-11 09:35:01

LAMP介紹

2013-12-12 15:59:23

Lua腳本語言

2010-06-13 15:53:35

ICMP協(xié)議

2010-07-08 12:53:21

HART協(xié)議
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)