版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
序言說到開源,恐怕很少有人不挑大指稱贊。學(xué)生通過開源代碼學(xué)到了知識,程序員通過開源類庫獲得了別人的成功經(jīng)驗(yàn)及能夠按時完成手頭的工程,商家通過開源軟件賺到了錢……,總之是皆大歡喜。然而開源軟件或類庫的首要缺點(diǎn)就是大多缺乏詳細(xì)的說明文檔和使用的例子,或者就是軟件代碼隨便你用,就是文檔,例子和后期服務(wù)收錢。這也難怪,畢竟就像某個著名NBA球員說的那樣:“我還要養(yǎng)家,所以千萬美元以下的合同別找我談,否則我寧可待業(yè)”。是啊,支持開源的人也要養(yǎng)家,收點(diǎn)錢也不過分。要想既不花錢又學(xué)到知識就只能借助網(wǎng)絡(luò)和了,我只是想拋磚引玉,為開源事業(yè)做出點(diǎn)微薄共獻(xiàn),能為你的工程解決哪怕一個小問題,也就足夠了。雖然我的這個系列介紹的東西不是什么Web框架,也不是什么開源服務(wù)器,但是我相信,作為一個程序員,什么樣的問題都會遇到。有時候越是簡單的問題反而越棘手;越是小的地方就越是找不到稱手的家伙。只要你不是整天只與“架構(gòu)”、“構(gòu)件”、“框架”打交道的話,相信我所說的東西你一定會用到。
1
串口通信簡介1.1
常見的Java串口包1.2
串口包的安裝(Windows下)2
串口API概覽2.1
m.CommPort2.2
m.CommPortIdentifier2.3
m.SerialPort2.4
串口API實(shí)例2.4.1
列舉出本機(jī)所有可用串口2.4.2
串口參數(shù)的配置2.4.3
串口的讀寫3
串口通信的通用模式及其問題3.1
事件監(jiān)聽模型3.2
串口讀數(shù)據(jù)的線程模型3.3
第三種方法4
結(jié)束語
1
串口通信簡介嵌入式系統(tǒng)或傳感器網(wǎng)絡(luò)的很多應(yīng)用和測試都需要通過PC機(jī)與嵌入式設(shè)備或傳感器節(jié)點(diǎn)進(jìn)行通信。其中,最常用的接口就是RS-232串口和并口(鑒于USB接口的復(fù)雜性以及不需要很大的數(shù)據(jù)傳輸量,USB接口用在這里還是顯得過于奢侈,況且目前除了SUN有一個支持USB的包之外,我還沒有看到其他直接支持USB的Java類庫)。SUN的CommAPI分別提供了對常用的RS232串行端口和IEEE1284并行端口通訊的支持。RS-232-C(又稱EIARS-232-C,以下簡稱RS232)是在1970年由美國電子工業(yè)協(xié)會(EIA)聯(lián)合貝爾系統(tǒng)、調(diào)制解調(diào)器廠家及計(jì)算機(jī)終端生產(chǎn)廠家共同制定的用于串行通訊的標(biāo)準(zhǔn)。RS232是一個全雙工的通訊協(xié)議,它可以同時進(jìn)行數(shù)據(jù)接收和發(fā)送的工作。1.1
常見的Java串口包目前,常見的Java串口包有SUN在1998年發(fā)布的串口通信API:comm2.0.jar(Windows下)、comm3.0.jar(Linux/Solaris);IBM的串口通信API以及一個開源的實(shí)現(xiàn)。鑒于在Windows下SUN的API比較常用以及IBM的實(shí)現(xiàn)和SUN的在API層面都是一樣的,那個開源的實(shí)現(xiàn)又不像兩家大廠的產(chǎn)品那樣讓人放心,這里就只介紹SUN的串口通信API在Windows平臺下的使用。1.2
串口包的安裝(Windows下)到SUN的網(wǎng)站下載javacomm20-win32.zip,包含的東西如下所示:按照其使用說明(Readme.html)的說法,要想使用串口包進(jìn)行串口通信,除了設(shè)置好環(huán)境變量之外,還要將win32com.dll復(fù)制到<JDK>\bin目錄下;將comm.jar復(fù)制到<JDK>\lib;把perties也同樣拷貝到<JDK>\lib目錄下。然而在真正運(yùn)行使用串口包的時候,僅作這些是不夠的。因?yàn)橥ǔ.?dāng)運(yùn)行“javaMyApp”的時候,是由JRE下的虛擬機(jī)啟動MyApp的。而我們只復(fù)制上述文件到JDK相應(yīng)目錄下,所以應(yīng)用程序?qū)崾菊也坏酱凇=鉀Q這個問題的方法很簡單,我們只須將上面提到的文件放到JRE相應(yīng)的目錄下就可以了。值得注意的是,在網(wǎng)絡(luò)應(yīng)用程序中使用串口API的時候,還會遇到其他更復(fù)雜問題。有興趣的話,你可以查看CSDN社區(qū)中“關(guān)于網(wǎng)頁上Applet用javacomm20讀取客戶端串口的問題”的帖子。2
串口API概覽2.1
m.CommPort這是用于描述一個被底層系統(tǒng)支持的端口的抽象類。它包含一些高層的IO控制方法,這些方法對于所有不同的通訊端口來說是通用的。SerialPort和ParallelPort都是它的子類,前者用于控制串行端口而后者用于控這并口,二者對于各自底層的物理端口都有不同的控制方法。這里我們只關(guān)心SerialPort。2.2
m.CommPortIdentifier這個類主要用于對串口進(jìn)行管理和設(shè)置,是對串口進(jìn)行訪問控制的核心類。主要包括以下方法l
確定是否有可用的通信端口l
為IO操作打開通信端口l
決定端口的所有權(quán)l(xiāng)
處理端口所有權(quán)的爭用l
管理端口所有權(quán)變化引發(fā)的事件(Event)2.3
m.SerialPort這個類用于描述一個RS-232串行通信端口的底層接口,它定義了串口通信所需的最小功能集。通過它,用戶可以直接對串口進(jìn)行讀、寫及設(shè)置工作。2.4
串口API實(shí)例大段的文字怎么也不如一個小例子來的清晰,下面我們就一起看一下串口包自帶的例子---SerialDemo中的一小段代碼來加深對串口API核心類的使用方法的認(rèn)識。2.4.1
列舉出本機(jī)所有可用串口voidlistPortChoices(){
CommPortIdentifierportId;
Enumerationen=CommPortIdentifier.getPortIdentifiers();
//iteratethroughtheports.
while(en.hasMoreElements()){
portId=(CommPortIdentifier)en.nextElement();
if(portId.getPortType()==CommPortIdentifier.PORT_SERIAL){
System.out.println(portId.getName());
}
}
portChoice.select(parameters.getPortName());
}以上代碼可以列舉出當(dāng)前系統(tǒng)所有可用的串口名稱,我的機(jī)器上輸出的結(jié)果是COM1和COM3。2.4.2
串口參數(shù)的配置串口一般有如下參數(shù)可以在該串口打開以前配置進(jìn)行配置:包括波特率,輸入/輸出流控制,數(shù)據(jù)位數(shù),停止位和齊偶校驗(yàn)。SerialPortsPort;try{
sPort.setSerialPortParams(BaudRate,Databits,Stopbits,Parity);
//設(shè)置輸入/輸出控制流
sPort.setFlowControlMode(FlowControlIn|FlowControlOut);
}catch(UnsupportedCommOperationExceptione){}2.4.3
串口的讀寫對串口讀寫之前需要先打開一個串口:CommPortIdentifierportId=CommPortIdentifier.getPortIdentifier(PortName);try{
SerialPort
sPort=(SerialPort)portId.open("串口所有者名稱",超時等待時間);
}catch(PortInUseExceptione){//如果端口被占用就拋出這個異常
thrownewSerialConnectionException(e.getMessage());
}//用于對串口寫數(shù)據(jù)OutputStreamos=newBufferedOutputStream(sPort.getOutputStream());os.write(intdata);//用于從串口讀數(shù)據(jù)InputStreamis=newBufferedInputStream(sPort.getInputStream());intreceivedData=is.read();讀出來的是int型,你可以把它轉(zhuǎn)換成需要的其他類型。這里要注意的是,由于Java語言沒有無符號類型,即所有的類型都是帶符號的,在由byte到int的時候應(yīng)該尤其注意。因?yàn)槿绻鸼yte的最高位是1,則轉(zhuǎn)成int類型時將用1來占位。這樣,原本是10000000的byte類型的數(shù)變成int型就成了1111111110000000,這是很嚴(yán)重的問題,應(yīng)該注意避免。3
串口通信的通用模式及其問題終于嘮叨完我最討厭的基礎(chǔ)知識了,下面開始我們本次的重點(diǎn)--串口應(yīng)用的研究。由于向串口寫數(shù)據(jù)很簡單,所以這里我們只關(guān)注于從串口讀數(shù)據(jù)的情況。通常,串口通信應(yīng)用程序有兩種模式,一種是實(shí)現(xiàn)SerialPortEventListener接口,監(jiān)聽各種串口事件并作相應(yīng)處理;另一種就是建立一個獨(dú)立的接收線程專門負(fù)責(zé)數(shù)據(jù)的接收。由于這兩種方法在某些情況下存在很嚴(yán)重的問題(至于什么問題這里先賣個關(guān)子J),所以我的實(shí)現(xiàn)是采用第三種方法來解決這個問題。3.1
事件監(jiān)聽模型現(xiàn)在我們來看看事件監(jiān)聽模型是如何運(yùn)作的:l
首先需要在你的端口控制類(例如SManager)加上“implementsSerialPortEventListener”l
在初始化時加入如下代碼:try{
SerialPortsPort.addEventListener(SManager);
}catch(TooManyListenersExceptione){
sPort.close();
thrownewSerialConnectionException("toomanylistenersadded");
}
sPort.notifyOnDataAvailable(true);l
覆寫publicvoidserialEvent(SerialPortEvente)方法,在其中對如下事件進(jìn)行判斷:BI-通訊中斷.CD-載波檢測.CTS-清除發(fā)送.DATA_AVAILABLE-有數(shù)據(jù)到達(dá).DSR-數(shù)據(jù)設(shè)備準(zhǔn)備好.FE-幀錯誤.OE-溢位錯誤.OUTPUT_BUFFER_EMPTY-輸出緩沖區(qū)已清空.PE-奇偶校驗(yàn)錯.RI-振鈴指示.一般最常用的就是DATA_AVAILABLE--串口有數(shù)據(jù)到達(dá)事件。也就是說當(dāng)串口有數(shù)據(jù)到達(dá)時,你可以在serialEvent中接收并處理所收到的數(shù)據(jù)。然而在我的實(shí)踐中,遇到了一個十分嚴(yán)重的問題。首先描述一下我的實(shí)驗(yàn):我的應(yīng)用程序需要接收傳感器節(jié)點(diǎn)從串口發(fā)回的查詢數(shù)據(jù),并將結(jié)果以圖標(biāo)的形式顯示出來。串口設(shè)定的波特率是115200,川口每隔128毫秒返回一組數(shù)據(jù)(大約是30字節(jié)左右),周期(即持續(xù)時間)為31秒。實(shí)測的時候在一個周期內(nèi)應(yīng)該返回4900多個字節(jié),而用事件監(jiān)聽模型我最多只能收到不到1500字節(jié),不知道這些字節(jié)都跑哪里去了,也不清楚到底丟失的是那部分?jǐn)?shù)據(jù)。值得注意的是,這是我將serialEvent()中所有處理代碼都注掉,只剩下打印代碼所得的結(jié)果。數(shù)據(jù)丟失的如此嚴(yán)重是我所不能忍受的,于是我決定采用其他方法。3.2
串口讀數(shù)據(jù)的線程模型這個模型顧名思義,就是將接收數(shù)據(jù)的操作寫成一個線程的形式:publicvoidstartReadingDataThread(){
ThreadreadDataProcess=newThread(newRunnable(){
publicvoidrun(){
while(newData!=-1){
try{
newData=is.read();
System.out.println(newData);
//其他的處理過程
……….
}catch(IOExceptionex){
System.err.println(ex);
return;
}
}
readDataProcess.start();}在我的應(yīng)用程序中,我將收到的數(shù)據(jù)打包放到一個緩存中,然后啟動另一個線程從緩存中獲取并處理數(shù)據(jù)。兩個線程以生產(chǎn)者—消費(fèi)者模式協(xié)同工作,數(shù)據(jù)的流向如下圖所示:
這樣,我就圓滿解決了丟數(shù)據(jù)問題。然而,沒高興多久我就又發(fā)現(xiàn)了一個同樣嚴(yán)重的問題:雖然這回不再丟數(shù)據(jù)了,可是原本一個周期(31秒)之后,傳感器節(jié)電已經(jīng)停止傳送數(shù)據(jù)了,但我的串口線程依然在努力的執(zhí)行讀串口操作,在控制臺也可以看見收到的數(shù)據(jù)仍在不斷的打印。原來,由于傳感器節(jié)點(diǎn)發(fā)送的數(shù)據(jù)過快,而我的接收線程處理不過來,所以InputStream就先把已到達(dá)卻還沒處理的字節(jié)緩存起來,于是就導(dǎo)致了明明傳感器節(jié)點(diǎn)已經(jīng)不再發(fā)數(shù)據(jù)了,而控制臺卻還能看見數(shù)據(jù)不斷打印這一奇怪的現(xiàn)象。唯一值得慶幸的是最后收到數(shù)據(jù)確實(shí)是4900左右字節(jié),沒出現(xiàn)丟失現(xiàn)象。然而當(dāng)處理完最后一個數(shù)據(jù)的時候已經(jīng)快1分半鐘了,這個時間遠(yuǎn)遠(yuǎn)大于節(jié)點(diǎn)運(yùn)行周期。這一延遲對于一個實(shí)時的顯示系統(tǒng)來說簡直是災(zāi)難!后來我想,是不是由于兩個線程之間的同步和通信導(dǎo)致了數(shù)據(jù)接收緩慢呢?于是我在接收線程的代碼中去掉了所有處理代碼,僅保留打印收到數(shù)據(jù)的語句,結(jié)果依然如故??磥聿⒉皇蔷€程間的通信阻礙了數(shù)據(jù)的接收速度,而是用線程模型導(dǎo)致了對于發(fā)送端數(shù)據(jù)發(fā)送速率過快的情況下的數(shù)據(jù)接收延遲。這里申明一點(diǎn),就是對于數(shù)據(jù)發(fā)送速率不是如此快的情況下前面者兩種模型應(yīng)該還是好用的,只是特殊情況還是應(yīng)該特殊處理。3.3
第三種方法痛苦了許久(Boss天天催我L)之后,偶然的機(jī)會,我聽說TinyOS中(又是開源的)有一部分是和我的應(yīng)用程序類似的串口通信部分,于是我下載了它的1.x版的Java代碼部分,參考了它的處理方法。解決問題的方法說穿了其實(shí)很簡單,就是從根源入手。根源不就是接收線程導(dǎo)致的嗎,那好,我就干脆取消接收線程和作為中介的共享緩存,而直接在處理線程中調(diào)用串口讀數(shù)據(jù)的方法來解決問題(什么,為什么不把處理線程也一并取消?----都取消應(yīng)用程序界面不就鎖死了嗎?所以必須保留)于是程序變成了這樣:publicbyte[]getPack(){
while(true){
//PacketLength為數(shù)據(jù)包長度
byte[]msgPack=newbyte[PacketLength];
for(inti=0;i<PacketLength;i++){
if(
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年溫州體育行業(yè)勞動合同模板(含運(yùn)動員保障及培訓(xùn)協(xié)議)3篇
- 2025年水庫承包合同范本:水庫水資源調(diào)度管理合同3篇
- 2025年消防暖通系統(tǒng)安裝與運(yùn)行維護(hù)服務(wù)合同3篇
- 2025年消防設(shè)施設(shè)備檢測及維修保養(yǎng)合同2篇
- 2025年度臨時雇工合同范本與服務(wù)保障協(xié)議4篇
- 二零二五年羅森便利店特許經(jīng)營加盟合同模板6篇
- 二零二五年度煤炭企業(yè)煤炭采購與環(huán)保運(yùn)輸合同范本3篇
- 二零二五版校園視頻監(jiān)控系統(tǒng)購買合同
- 二零二五年度煤礦安全管理人員專項(xiàng)勞動合同4篇
- 二零二五年度國際碼頭堆場租賃及貨物裝卸服務(wù)合同4篇
- 冬春季呼吸道傳染病防控
- 中介費(fèi)合同范本(2025年)
- 《kdigo專家共識:補(bǔ)體系統(tǒng)在腎臟疾病的作用》解讀
- 生產(chǎn)調(diào)度員崗位面試題及答案(經(jīng)典版)
- 【物 理】2024-2025學(xué)年八年級上冊物理寒假作業(yè)人教版
- 交通運(yùn)輸安全生產(chǎn)管理規(guī)范
- 電力行業(yè) 電力施工組織設(shè)計(jì)(施工方案)
- 《法制宣傳之盜竊罪》課件
- 通信工程單位勞動合同
- 查對制度 課件
- 2024-2030年中國豬肉市場銷售規(guī)模及競爭前景預(yù)測報告~
評論
0/150
提交評論