多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集課件_第1頁(yè)
多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集課件_第2頁(yè)
多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集課件_第3頁(yè)
多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集課件_第4頁(yè)
多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集課件_第5頁(yè)
已閱讀5頁(yè),還剩46頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

工控程序設(shè)計(jì)學(xué)習(xí)情景2.4多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集

學(xué)習(xí)情景2.4多個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)采集

2.4.1學(xué)習(xí)要點(diǎn)1.知識(shí)點(diǎn):煤礦鉆機(jī)性能檢測(cè)設(shè)備的數(shù)據(jù)通信協(xié)議,數(shù)據(jù)幀的校驗(yàn)方法

2.技能點(diǎn):校驗(yàn)碼的計(jì)算,上位機(jī)主動(dòng)模式串口通信類(lèi)的設(shè)計(jì),HC-100智能測(cè)控儀、JW-2A扭矩儀、LU-902M位式調(diào)節(jié)儀數(shù)據(jù)采集2.4.2任務(wù)描述在前一個(gè)情景中實(shí)現(xiàn)了對(duì)單個(gè)HSDZC電能綜合測(cè)試數(shù)據(jù)的接收。在鉆機(jī)性能測(cè)試系統(tǒng)中,還需要使用JW-2A扭矩儀、HC-100智能測(cè)控儀、LU-902M位式調(diào)節(jié)儀來(lái)采集其它參數(shù)的值,而這些設(shè)備的數(shù)據(jù)通信規(guī)則不同,所以必須對(duì)每種設(shè)備編寫(xiě)通信程序,并同步、連續(xù)地采集多個(gè)設(shè)備的數(shù)據(jù)。該教學(xué)情景中先針對(duì)上位機(jī)主動(dòng)通信模式設(shè)計(jì)基類(lèi)CActiveCOMHelper,再分別對(duì)三種不同的儀器分別設(shè)計(jì)派生類(lèi)來(lái)進(jìn)行數(shù)據(jù)管理,實(shí)現(xiàn)對(duì)多個(gè)不同設(shè)備進(jìn)行同步、連續(xù)的數(shù)據(jù)采集。儀表返回?cái)?shù)據(jù)的格式為:STX+儀表地址編號(hào)+符號(hào)位+測(cè)量值+校驗(yàn)碼+ETX。其中的數(shù)據(jù)參數(shù)值為符號(hào)位+4位有效位+小數(shù)點(diǎn),共6位,校驗(yàn)碼為前面發(fā)送的9個(gè)字節(jié)之和。表2.4.2HC100返回的數(shù)據(jù)格式STX儀表編號(hào)符號(hào)千位百位十位小數(shù)點(diǎn)個(gè)位校驗(yàn)碼ETX02H30H31H2bH31H32H33H2eH34H83H03HHC-100智能控制儀的數(shù)據(jù)處理流程如圖2.4.1所示

圖2.4.1HC-100智能控制儀數(shù)據(jù)處理流程(2)JW-2A扭矩儀JW-2A扭矩儀采用多機(jī)通訊方式,本機(jī)地址為0AH。數(shù)據(jù)位8位,停止位1位。波特率可用跳線選擇4800bps或2400bps。奇偶位在這里做地址和數(shù)據(jù)判別位,1為地址,0為數(shù)據(jù)。儀器只被地址觸發(fā),即上位機(jī)只有向儀器發(fā)0AH,并且奇偶位為1時(shí),才能得到儀器的響應(yīng)。儀器被本機(jī)地址觸發(fā)后,向上位機(jī)傳回本機(jī)地址,然后等待上位機(jī)發(fā)來(lái)的命令。受到命令后,根據(jù)命令執(zhí)行不同的任務(wù)。命令為一個(gè)字節(jié)。目前有效的命令有15個(gè),下面敘述各命令代表的任務(wù)。0:讀扭矩轉(zhuǎn)速儀器受到命令后向上位機(jī)依次傳送扭矩,轉(zhuǎn)速,采樣時(shí)間3個(gè)參數(shù)。扭矩、轉(zhuǎn)速為浮點(diǎn)數(shù),每個(gè)參數(shù)4個(gè)字節(jié)。采樣時(shí)間為整數(shù),2個(gè)字節(jié)。每個(gè)參數(shù)的傳送順序都是從內(nèi)存的低地址到高地址1:存儲(chǔ)操作。在測(cè)量狀態(tài)收到此命令,將啟動(dòng)存儲(chǔ)操作;在存儲(chǔ)狀態(tài)收到此命令,將退出存儲(chǔ)狀態(tài)。2:讀儀器存儲(chǔ)的數(shù)據(jù)數(shù)組。在非存儲(chǔ)狀態(tài)收到此命令,將向上位機(jī)傳送春初數(shù)據(jù)的數(shù)組。3:釋放操作。在測(cè)量狀態(tài)收到此命令,將啟動(dòng)釋放操作;在釋放狀態(tài)儀器不再接受命令。8:讀模擬通道數(shù)據(jù)。儀器收到命令后向上位機(jī)依次傳送0至7通道的A/D采樣結(jié)果。每通道2字節(jié),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點(diǎn)位置。小數(shù)點(diǎn)位置為0,有0位小數(shù)點(diǎn);小數(shù)點(diǎn)位置為1,有1位小數(shù)點(diǎn);小數(shù)點(diǎn)位置為2,有2位小數(shù)點(diǎn)。9:讀0點(diǎn)。儀器收到命令后向上位機(jī)依次傳送10個(gè)零點(diǎn)值和其相應(yīng)的轉(zhuǎn)速值。每個(gè)零點(diǎn)6個(gè)字節(jié)(前4個(gè)字節(jié)是零點(diǎn),浮點(diǎn)數(shù),后2個(gè)字節(jié)是轉(zhuǎn)速,無(wú)符號(hào)整數(shù),高位在前),共60個(gè)字節(jié)。10:寫(xiě)零點(diǎn)。儀器受到命令后準(zhǔn)備接受10個(gè)零點(diǎn),共60個(gè)字節(jié)的數(shù)據(jù)。上位機(jī)應(yīng)按上述讀零點(diǎn)的順序依次將60個(gè)字節(jié)寫(xiě)回去。注意,寫(xiě)零點(diǎn)不能少于60字節(jié)。11:讀扭矩參數(shù)。儀器收到命令后向上位機(jī)依次傳送11個(gè)參數(shù),共24個(gè)字節(jié)。這11個(gè)參數(shù)的排列順序,數(shù)據(jù)類(lèi)型,數(shù)據(jù)長(zhǎng)度如表2.4.4所示。12:寫(xiě)扭矩參數(shù)。儀器收到命令后準(zhǔn)備接受11個(gè)參數(shù),共24個(gè)字節(jié)的數(shù)據(jù)。上位機(jī)應(yīng)按上述讀扭矩參數(shù)的順序依次將24個(gè)字節(jié)寫(xiě)回去。注意:寫(xiě)扭矩參數(shù)不能少于24字節(jié)。13:讀模擬通道量程。儀器收到命令后向上位機(jī)依次傳送8個(gè)通道的量程值。每個(gè)量程2個(gè)字節(jié),共16個(gè)字節(jié)。數(shù)據(jù)類(lèi)型是無(wú)符號(hào)整數(shù),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點(diǎn)位置。小數(shù)點(diǎn)位置為0,有0位小數(shù)點(diǎn);小數(shù)點(diǎn)位置為1,有1位小數(shù)點(diǎn),小數(shù)點(diǎn)位置為2,有2位小數(shù)點(diǎn)。表2.4.4JW-2A的扭矩參數(shù)數(shù)據(jù)名稱(chēng)數(shù)據(jù)類(lèi)型數(shù)據(jù)長(zhǎng)度(byte)系數(shù)無(wú)符號(hào)整數(shù)2量程浮點(diǎn)數(shù)4齒數(shù)無(wú)符號(hào)整數(shù)2采樣周期無(wú)符號(hào)整數(shù)2扭矩報(bào)警值浮點(diǎn)數(shù)4轉(zhuǎn)速報(bào)警值無(wú)符號(hào)整數(shù)2小電機(jī)轉(zhuǎn)速無(wú)符號(hào)整數(shù)2定時(shí)打印時(shí)間無(wú)符號(hào)整數(shù)2轉(zhuǎn)速模擬輸出范圍無(wú)符號(hào)整數(shù)2標(biāo)定溫度無(wú)符號(hào)整數(shù)1使用溫度無(wú)符號(hào)整數(shù)114:寫(xiě)模擬通道量程。儀器收到命令后準(zhǔn)備接收8個(gè)通道的量程表。每個(gè)量程2個(gè)字節(jié),共16個(gè)字節(jié)。數(shù)據(jù)類(lèi)型是無(wú)符號(hào)整數(shù),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點(diǎn)位置。小數(shù)點(diǎn)位置為0,有0位小數(shù)點(diǎn);小數(shù)點(diǎn)位置為1,有1位小數(shù)點(diǎn),小數(shù)點(diǎn)位置為2,有2位小數(shù)點(diǎn)。上位機(jī)應(yīng)按上述讀模擬通道量程的順序依次將16個(gè)字節(jié)寫(xiě)回去。需要注意的是:寫(xiě)模擬通道量程不能少于16字節(jié)。

JW-2A扭矩儀的數(shù)據(jù)采用IEEE浮點(diǎn)數(shù)形式表示,需要作浮點(diǎn)數(shù)字節(jié)數(shù)組到浮點(diǎn)數(shù)的轉(zhuǎn)換。如果用DCBA表示浮點(diǎn)數(shù),D為高位,A為低位,每個(gè)字母表示一個(gè)字節(jié),那么DCBA依次為SXXXXXXXXMMMMMMMMMMMMMMMMMMMMMMM,其中S代表符號(hào),1位,1表示負(fù),0表示正,X代表指數(shù),8位,0到255轉(zhuǎn)換為-127到128,M代表尾數(shù),23位,注意尾數(shù)總共24位,最高位等于1是隱含的。JW-2A扭矩儀的數(shù)據(jù)處理流程如圖2.4.2所示。圖2.4.2JW2A數(shù)據(jù)處理流程2數(shù)據(jù)幀的校驗(yàn)數(shù)據(jù)幀校驗(yàn)的目的是為了檢查接收到的數(shù)據(jù)幀的完整性和準(zhǔn)確性。和校驗(yàn)位不同,校驗(yàn)位的作用是保證一個(gè)數(shù)據(jù)單位的正確性,是從微觀角度考慮。形象地說(shuō),校驗(yàn)位保證一個(gè)字正確,數(shù)據(jù)幀校驗(yàn)是保證一段話正確。對(duì)數(shù)據(jù)幀進(jìn)行校驗(yàn)的方法是:發(fā)送方根據(jù)要發(fā)送的數(shù)據(jù)幀,利用某種算法計(jì)算出若干字節(jié)的校驗(yàn)碼,并把校驗(yàn)碼附加在數(shù)據(jù)幀中發(fā)送給接收端,接收端接收到數(shù)據(jù)后,分離出校驗(yàn)碼和數(shù)據(jù)本身,再根據(jù)發(fā)送方的算法,計(jì)算出校驗(yàn)碼,如果和接收到的校驗(yàn)碼一致,則認(rèn)為接收到的數(shù)據(jù)準(zhǔn)確無(wú)誤。串口通信中常用的校驗(yàn)方式有累加和校驗(yàn)、異或和校驗(yàn)、循環(huán)冗余校驗(yàn)等。(1)累加和校驗(yàn)累加和校驗(yàn)的過(guò)程是,發(fā)送端將數(shù)據(jù)的每個(gè)字節(jié)累加求和,然后截取最低字節(jié)(或最低兩字節(jié))作為校驗(yàn)碼發(fā)送給接收端,接收端收到數(shù)據(jù)后,用同樣的方法計(jì)算累加和,并與發(fā)送過(guò)來(lái)的校驗(yàn)碼進(jìn)行比較,從而檢驗(yàn)發(fā)送的數(shù)據(jù)是否有誤。(2)異或和校驗(yàn)異或和校驗(yàn)的過(guò)程是,發(fā)送端取出發(fā)送數(shù)據(jù)的第1個(gè)字節(jié),與后續(xù)每個(gè)字節(jié)依次按位異或,然后將計(jì)算結(jié)果(1個(gè)字節(jié))作為校驗(yàn)碼發(fā)送給接收端,接收端收到數(shù)據(jù)后,用同樣的方法計(jì)算異或和,并與發(fā)送過(guò)來(lái)的校驗(yàn)碼進(jìn)行比較,從而檢驗(yàn)發(fā)送的數(shù)據(jù)是否有誤。(3)循環(huán)冗余校驗(yàn)循環(huán)冗余校驗(yàn)(CyclicalRedundancyCheck)簡(jiǎn)稱(chēng)CRC,它利用除法及余數(shù)的原理來(lái)作錯(cuò)誤偵測(cè)。實(shí)際應(yīng)用時(shí),發(fā)送端計(jì)算出校驗(yàn)碼值并附加在數(shù)據(jù)幀中發(fā)送給接收端,接收端對(duì)收到的數(shù)據(jù)重新計(jì)算校驗(yàn)碼并與收到的校驗(yàn)碼相比較,若兩個(gè)值不同,則說(shuō)明數(shù)據(jù)通訊出現(xiàn)錯(cuò)誤,要求發(fā)送端重新發(fā)送。常用的CRC標(biāo)準(zhǔn)有CRC-12、CRC-16、CRC-CCITT和CRC-32,其中CRC-16和CRC-CCITT用來(lái)作一個(gè)字節(jié)數(shù)據(jù)的校驗(yàn),在串口數(shù)據(jù)校驗(yàn)中最常用的是CRC-16。下面是循環(huán)冗余校驗(yàn)碼的計(jì)算過(guò)程:1)設(shè)置CRC寄存器,并給其賦值FFFF(hex)。2)將數(shù)據(jù)的第一個(gè)字節(jié)與16位CRC寄存器的低8位進(jìn)行異或,并把結(jié)果存入CRC寄存器。3)CRC寄存器向右移一位,MSB(最高有效位)補(bǔ)零,移出并檢查L(zhǎng)SB(最低有效位)。4)如果LSB為0,重復(fù)第三步;若LSB為1,CRC寄存器與多項(xiàng)式碼相異或。5)重復(fù)第3與第4步直到8次移位全部完成。此時(shí)一個(gè)字節(jié)數(shù)據(jù)處理完畢。6)重復(fù)第2至第5步直到所有數(shù)據(jù)全部處理完成。7)最終CRC寄存器的內(nèi)容即為CRC值。常用的循環(huán)冗余校驗(yàn)標(biāo)準(zhǔn)多項(xiàng)式為:

CRC-16:X16+X15+X2+1

CRC-CCITT:X16+X12+X5+1

CRC-32:X32+X26+X23+X16+X12+X11+X10+X8+X7+X5+X4+X2+X+1其中CRC-16多項(xiàng)式對(duì)應(yīng)多項(xiàng)式碼為1000000000000101(0x8005),CRC-CCITT對(duì)應(yīng)的多項(xiàng)式碼為0001000000100001(0x1021)。2.4.4

任務(wù)實(shí)施1校驗(yàn)碼的計(jì)算在串口通信通,校驗(yàn)碼在保證數(shù)據(jù)幀的正確性方面具有重要作用,雖然在鉆機(jī)性能測(cè)試系統(tǒng)中只用到累加和校驗(yàn),但為了能應(yīng)對(duì)串口通信中可能出現(xiàn)的復(fù)雜情況,下面對(duì)三種校驗(yàn)碼的計(jì)算都進(jìn)行具體實(shí)現(xiàn)。(1)累加和校驗(yàn)碼的計(jì)算累加和校驗(yàn)碼可以取累加和的低8位(1個(gè)字節(jié))或低16位(兩個(gè)字節(jié)),在下位機(jī)處理能力允許的情況下采用兩個(gè)字節(jié)作校驗(yàn)碼可以提高校驗(yàn)的準(zhǔn)確度。下面的C#代碼將累加和校驗(yàn)碼生成功能封裝到CCheck類(lèi)的方法中,其中CheckSum_1方法計(jì)算單字節(jié)累加和校驗(yàn)碼,CheckSum_2方法計(jì)算雙字節(jié)累加和校驗(yàn)碼classCCheck{//函數(shù)功能://計(jì)算字節(jié)數(shù)組b中從offset位置開(kāi)始的count個(gè)元素的單字節(jié)累加和校驗(yàn)碼//參數(shù)://b:要計(jì)算累加和的字節(jié)數(shù)組//offset:要計(jì)算累加和的元素的起始位置//count:要計(jì)算累加和的連續(xù)元素個(gè)數(shù)//返回值:累加和的低8位(單個(gè)字節(jié))

publicstaticbyte[]CheckSum_2(byte[]b,intoffset,intcount){uintsum=0;byte[]tmp=newbyte[2];//存放累加和的低8位和高8位

for(inti=offset;i<offset+count;i++)sum+=b[i];//數(shù)組元素累加求和

tmp[0]=(byte)(sum&0xFF);//低8位在前

tmp[1]=(byte)((sum&0xFF00)>>8);//高8位在后

returntmp;}}下面的測(cè)試程序調(diào)用CheckSum_1方法,計(jì)算出長(zhǎng)度為1個(gè)字節(jié)的累加和校驗(yàn)碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0};//保留一個(gè)字節(jié)位置存儲(chǔ)校驗(yàn)碼bytesum=CCheck.CheckSum_1(b,0,b.Length-1);//計(jì)算單字節(jié)累加和b[b.Length-1]=sum;//附加在字節(jié)數(shù)組末尾下面的測(cè)試程序調(diào)用CheckSum_2方法,計(jì)算出長(zhǎng)度為兩個(gè)字節(jié)的累加和校驗(yàn)碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0,0};//保留兩個(gè)字節(jié)位置存儲(chǔ)校驗(yàn)碼byte[]sum=CCheck.CheckSum_2(b,0,b.Length-2);//計(jì)算雙字節(jié)累加和b[b.Length-2]=sum[0];//附加在字節(jié)數(shù)組末尾b[b.Length-1]=sum[1];(2)異或和校驗(yàn)碼的計(jì)算下面的C#代碼將異或和校驗(yàn)碼生成功能封裝到CCheck類(lèi)的方法中,方法名為XorSum:classCCheck{//函數(shù)功能://計(jì)算字節(jié)數(shù)組b中從offset位置開(kāi)始的count個(gè)元素的單字節(jié)異或和校驗(yàn)碼//參數(shù)://b:要計(jì)算累加和的字節(jié)數(shù)組//offset:要參與計(jì)算校驗(yàn)碼的元素的起始位置//count:要參與計(jì)算校驗(yàn)碼的連續(xù)元素個(gè)數(shù)//返回值:異或和(8位,1個(gè)字節(jié))

publicstaticbyteXorSum(byte[]b,intoffset,intcount){bytesum=0;for(inti=offset;i<offset+count;i++)sum^=b[i];//依次和每個(gè)元素進(jìn)行按位異或運(yùn)算

returnsum;}}下面的測(cè)試程序調(diào)用XorSum方法,計(jì)算出長(zhǎng)度為1個(gè)字節(jié)的異或和校驗(yàn)碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0};//保留一個(gè)字節(jié)位置存儲(chǔ)校驗(yàn)碼bytexorsum=CCheck.XorSum(b,0,b.Length-1);//計(jì)算異或和b[b.Length-1]=xorsum;//附加在字節(jié)數(shù)組末尾publicstaticbyte[]CRC16(byte[]b,intoffset,intcount,ushortCrcPoly){ushortCrcReg=0xFFFF;//16位CRC寄存器

uintLSB;//最低有效位

byte[]tmp=newbyte[2];for(inti=offset;i<offset+count;i++){CrcReg^=b[i];//將當(dāng)前字節(jié)與CRC寄存器的低8位進(jìn)行按位異或

for(intn=1;n<=8;n++)//進(jìn)行8次邏輯移位

{LSB=CrcReg&1u;//“u”表示該常量是無(wú)符號(hào)整型

CrcReg>>=1;//CRC寄存器邏輯右移1位

if(LSB==1)CrcReg^=CrcPoly;}}

tmp[0]=(byte)(CrcReg&0xFF);//低8位在前

tmp[1]=(byte)((CrcReg&0xFF00)>>8);//高8位在后

returntmp;}}下面的測(cè)試程序調(diào)用CRC16方法,計(jì)算出長(zhǎng)度為兩個(gè)字節(jié)的循環(huán)冗余校驗(yàn)碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0,0};//保留兩個(gè)字節(jié)位置存儲(chǔ)校驗(yàn)碼byte[]crc=CCheck.CRC16(b,0,b.Length–2,0x8005);//計(jì)算循環(huán)冗余校驗(yàn)碼b[b.Length-2]=sum[0];//附加在字節(jié)數(shù)組末尾b[b.Length-1]=sum[1];2上位機(jī)主動(dòng)模式串口通信類(lèi)的設(shè)計(jì)煤礦鉆機(jī)性能測(cè)試系統(tǒng)中用到的HC-100智能測(cè)控儀、JW-2A扭矩儀和LU-902M位式調(diào)節(jié)儀與HSDZC電能綜合測(cè)試儀不同,這些設(shè)備需要上位機(jī)主動(dòng)發(fā)送命令,才給予回復(fù),因此可以把這三種設(shè)備的通信模式歸為“上位機(jī)主動(dòng)模式”。下面將設(shè)計(jì)上位機(jī)主動(dòng)模式的串口通信類(lèi)CActiveCOMHelper,和CPassiveCOMHelper類(lèi)不同的是,CActiveCOMHelper類(lèi)中增加了一個(gè)名為command的成員,存放當(dāng)前應(yīng)該執(zhí)行的命令,線程函數(shù)根據(jù)該成員的相關(guān)屬性,就知道現(xiàn)在應(yīng)該給下位機(jī)發(fā)送什么命令。由于采用“提問(wèn)——回答”的方式,能夠準(zhǔn)確控制下位機(jī)發(fā)送來(lái)的數(shù)據(jù),故不再需要隊(duì)列來(lái)暫存接收的數(shù)據(jù)。CCommand類(lèi)實(shí)現(xiàn)代碼如下:publicclassCCommand{publicstringcommandName;//命令名字

publicbyte[]cmdContent;//命令的內(nèi)容

publicParityparity=Parity.None;//發(fā)送命令時(shí)采用的校驗(yàn)方式

publicbyte[]replyContent;//回復(fù)內(nèi)容CActiveCOMHelper類(lèi)實(shí)現(xiàn)代碼如下:publicclassCActiveCOMHelper{publicintreadTimeOut;//接收數(shù)據(jù)超時(shí)毫秒數(shù)

publicstringportName;//設(shè)備所占用的串口名

privateboolstopFlag;//線程循環(huán)停止標(biāo)志

privateintbaudRate,dataBits;privateStopBitsstopBits;privateCCommandcommand;

publicdelegatevoidDataReceivedHandler(CActiveCOMHelpersender);publiceventDataReceivedHandlerDataReceived;

publicCActiveCOMHelper(stringportName,intbaudRate,intdataBits,StopBitsstopBits){this.portName=portName;this.baudRate=baudRate;this.dataBits=dataBits;this.stopBits=stopBits;this.readTimeOut=3000;//默認(rèn)3000毫秒讀取超時(shí)

mand=newCCommand();//始終保持有一個(gè)命令

mand.isCompleted=true;//該命令開(kāi)始時(shí)處于完成狀態(tài)

}publicvoidstart(){Threadt=newThread(newThreadStart(threadFun));t.IsBackground=true;stopFlag=false;t.Start();}

catch{return;}bytefirst;byte[]bRecv,bSend;while(!stopFlag){CCommandcmd=getCommand();if(cmd.isCompleted==false)try{sp.ReadTimeout=readTimeOut;sp.ReadExisting();//清除接收緩沖區(qū)

bSend=cmd.cmdContent;//要發(fā)送的內(nèi)容

sp.Parity=cmd.parity;//校驗(yàn)位

sp.Write(bSend,0,bSend.Length);

first=(byte)sp.ReadByte();//阻塞方式讀取數(shù)據(jù)

bRecv=newbyte[cmd.replyLength];//存儲(chǔ)回復(fù)數(shù)據(jù)(字節(jié)數(shù)已經(jīng)規(guī)定)

bRecv[0]=first;intn=0;//檢查的次數(shù)

while(n<=3&&sp.BytesToRead<cmd.replyLength-1){n++;Thread.Sleep(20);//等待20毫秒后再檢查數(shù)據(jù)是否達(dá)到規(guī)定長(zhǎng)度

}if(n>3)continue;//等待3次后數(shù)據(jù)還未到達(dá)

sp.Read(bRecv,1,cmd.replyLength-1);if(checkReply(mandName,bRecv)){cmd.replyContent=bRecv;//填寫(xiě)回復(fù)內(nèi)容

cmd.isCompleted=true;//修改命令完成標(biāo)志

setCommand(cmd);if(DataReceived!=null)//引發(fā)事件,通知使用該類(lèi)的程序

DataReceived(this);}}catch{}elseThread.Sleep(20);//沒(méi)有新命令下達(dá),延時(shí)防止CPU占用率過(guò)高

}if(sp!=null&&sp.IsOpen)sp.Close();}}

在前一個(gè)步驟中已經(jīng)實(shí)現(xiàn)了串口數(shù)據(jù)接收、解析和顯示的功能,并且在工作者線程中接收和處理數(shù)據(jù),在此期間前臺(tái)的UI線程能響應(yīng)用戶輸入。從功能上看,已經(jīng)能夠滿足用戶需求,但是從代碼的組織和管理角度看,該程序還有比較大問(wèn)題:負(fù)責(zé)接收和處理數(shù)據(jù)的代碼和負(fù)責(zé)顯示的代碼混雜在一起,不能重復(fù)使用,若增加一個(gè)同類(lèi)設(shè)備,很多代碼還要重寫(xiě),而且給查看和調(diào)試程序也帶來(lái)較大困難。下面用面向?qū)ο蠓椒▽?duì)程序進(jìn)行重新設(shè)計(jì)。3HC-100智能測(cè)控儀數(shù)據(jù)采集HC-100智能測(cè)控儀采用以上位機(jī)為主導(dǎo)的“提問(wèn)——應(yīng)答”通信模式,管理該設(shè)備的類(lèi)可以從CActiveCOMHelper類(lèi)派生而來(lái),命名為CHC100,在類(lèi)中覆蓋checkReply方法,并實(shí)現(xiàn)浮點(diǎn)數(shù)的解碼方法AsciiToFloat。該類(lèi)的實(shí)現(xiàn)代碼如下:publicclassCHC100:CActiveCOMHelper{publicCHC100(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){} //根據(jù)命令名稱(chēng)構(gòu)建命令對(duì)象

publicCCommandmakeCommand(stringcommandName){CCommandcommand=newCCommand();switch(commandName){case"R"://讀數(shù)據(jù)指令

mandName=commandName;command.replyLength=11;command.cmdContent=newbyte[]{0x04,0x30,0x31,0x52,0x30,0x30,0x05};break;}returncommand;}

protectedoverrideboolcheckReply(stringcmdType,byte[]bRecv){switch(cmdType){case"R"://讀數(shù)據(jù)指令

if(bRecv[0]==0x02&&bRecv[10]==0x03)if(bRecv[9]==CCheck.CheckSum_1(bRecv,0,9))returntrue;break;}

returnfalse;}publicfloatAsciiToFloat(byte[]b){StringBuilders=newStringBuilder();for(inti=3;i<=8;i++)//下標(biāo)為3到8的數(shù)據(jù)段表示浮點(diǎn)數(shù)值

{s.Append((char)b[i]);//將字符連接為字符串

}floatf=0F;try{f=Single.Parse(s.ToString());//字符串轉(zhuǎn)換為浮點(diǎn)數(shù)

}catch{}returnf;}}下面的代碼說(shuō)明了CHC100類(lèi)在UI模塊中的應(yīng)用。后臺(tái)工作者線程獲得下位機(jī)應(yīng)答數(shù)據(jù)后,存儲(chǔ)在CCommand對(duì)象中,不用事件通知UI線程。UI線程每隔1秒鐘檢查一次命令執(zhí)行情況,如果命令執(zhí)行完畢,則讀取本次的應(yīng)答數(shù)據(jù),并設(shè)置下一次的命令。privateCHC100hc100;privatevoidbtnStart_Click(objectsender,EventArgse)//開(kāi)始采集數(shù)據(jù){hc100=newCHC100("COM1",9600,8,StopBits.One);hc100.start();timer1.Enabled=true;}privatevoidbtnStop_Click(objectsender,EventArgse)//結(jié)束采集{timer1.Enabled=false;hc100.stop();}privatevoidtimer1_Tick(objectsender,EventArgse){CCommandcmd=hc100.getCommand();//獲取當(dāng)前命令

if(cmd.isCompleted)//當(dāng)面命令已完成

{CCommandnextCmd=hc100.makeCommand("R");//構(gòu)建下一個(gè)命令

hc100.setCommand(nextCmd);if(cmd.cmdContent!=null)Trace.WriteLine("HC100回復(fù):壓力:"+AsciiToFloat(cmd.replyContent));}elseTrace.WriteLine(mandName+"命令還未完成");}4JW-2A扭矩儀數(shù)據(jù)采集JW-2A扭矩儀用于測(cè)量鉆機(jī)的扭矩和轉(zhuǎn)速,該設(shè)備和HC-100智能測(cè)控儀相似,也采用以上位機(jī)為主導(dǎo)的“提問(wèn)——應(yīng)答”通信模式,不同的是通信方式比HC-100智能測(cè)控儀稍微復(fù)雜,每次通信需要發(fā)送兩道命令,首先發(fā)尋址指令激活,再發(fā)送讀數(shù)據(jù)指令獲取數(shù)據(jù)。管理該設(shè)備的類(lèi)從CActiveCOMHelper類(lèi)派生而來(lái),命名為CJW2A,代碼如下:classCJW2A:CActiveCOMHelper{publicCJW2A(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){}publicCCommandmakeCommand(stringcommandName)//根據(jù)命令名稱(chēng)構(gòu)建命令對(duì)象

{CCommandcommand=newCCommand();

switch(commandName){case"A"://尋址指令(激活設(shè)備)

mandName=commandName;command.replyLength=1;command.parity=Parity.Mark;command.cmdContent=newbyte[]{0x0A};break;case"R"://讀數(shù)據(jù)指令

mandName=commandName;command.replyLength=10;command.parity=Parity.Space;command.cmdContent=newbyte[]{0x00};break;}returncommand;}

protectedoverrideboolcheckReply(stringcmdType,byte[]bRecv){switch(cmdType){case"A"://尋址指令

if(bRecv[0]==0x0A)returntrue;break;case"R"://讀數(shù)據(jù)指令

if(bRecv[0]==0x02&&bRecv[10]==0x03)if(bRecv[9]==CCheck.CheckSum_1(bRecv,0,9))returntrue;break;}returnfalse;}

publicfloatHexToFloat(byte[]data)//4字節(jié)轉(zhuǎn)換為浮點(diǎn)數(shù)(按照IEEE754規(guī)范){ints;//符號(hào)位,+1或者-1。

inte;//指數(shù),根據(jù)IEEE754,指數(shù)部份算出來(lái)后要減127floatm;//小數(shù)位。

floatmreturn;//返回的浮點(diǎn)數(shù),應(yīng)為:(1+小數(shù)位)*2^(指數(shù))*(符號(hào)位)

s=data[0]&128;

if(s==128)s=1;e=(data[0]&127)*2+(data[1]&128)/128;m=(data[1]&127)*65536+data[2]*256+data[3];m=m/8388608;

mreturn=(float)((m+1)*Math.Pow((-1),s)*Math.Pow(2,(e-127)));returnmreturn;}}在UI模塊中,每個(gè)CJW2A對(duì)象負(fù)則和一個(gè)JW-2A扭矩儀通信,由于每次通信過(guò)程要發(fā)送兩道命令,所以代碼中采用事件通知方式來(lái)使兩道命令連貫地發(fā)送,當(dāng)收到第一道命令的回復(fù)后,引發(fā)事件,在事件處理程序中緊接著發(fā)第二道命令。代碼如下:privateCJW2Ajw2a;privatevoidbtnStart_Click(objectsender,EventArgse){jw2a=newCJW2A("COM3",4800,8,StopBits.One);jw2a.DataReceived+=newCActiveCOMHelper.DataReceivedHandler(DataReceived);jw2a.start();timer1.Enabled=true;}privatevoidbtnStop_Click(objectsender,EventArgse){timer1.Enabled=false;jw2a.stop();}privatevoidDataReceived(CActiveCOMHelpersender){CCommandcmd,nextCmd;switch(sender.portName.ToUpper()){case"COM3"://JW2A要先發(fā)“A”命令,完成后緊接著發(fā)“R”命令

cmd=jw2a.getCommand();if(mandName=="A"&&cmd.isCompleted)//讀數(shù)命令已完成

{nextCmd=jw2a.makeCommand("R");//JW2A要先發(fā)A命令

jw2a.setCommand(nextCmd);Trace.WriteLine("JW2A的A命令已完成,立即發(fā)送R命令。");}break;}}privatevoidtimer1_Tick(objectsender,EventArgse){CCommandcmd,nextCmd;//處理JW2A的返回結(jié)果cmd=jw2a.getCommand();if(mandName=="R"&&cmd.isCompleted)//讀數(shù)命令已完成

{nextCmd=jw2a.makeCommand("A");//JW2A要先發(fā)A命令

jw2a.setCommand(nextCmd);if(cmd.cmdContent!=null){floatnj,zs;byte[]tmp=newbyte[4];Array.Copy(cmd.replyContent,0,tmp,0,4);nj=jw2a.HexToFloat(tmp);//扭矩

Array.Copy(cmd.replyContent,4,tmp,0,4);zs=jw2a.HexToFloat(tmp);//轉(zhuǎn)速

Trace.WriteLine("JW2A回復(fù):扭矩"+nj+",轉(zhuǎn)速"+zs);}}elseTrace.WriteLine("JW2A的"+mandName+"命令還未完成");}5LU-902M位式調(diào)節(jié)儀數(shù)據(jù)采集LU-902M位式調(diào)節(jié)儀在鉆機(jī)性能測(cè)試系統(tǒng)中應(yīng)用最廣泛,用于測(cè)量大氣溫度、馬達(dá)溫度、泵溫度、油溫、冷卻水流量、馬達(dá)進(jìn)油流量、馬達(dá)回油流量、馬達(dá)油壓、操縱臺(tái)噪音、馬達(dá)噪音等諸多參數(shù),該設(shè)備同樣采用以上位機(jī)為主導(dǎo)的“提問(wèn)——應(yīng)答”通信模式,它仍然需要激活,不過(guò)只激活一次,以后就象HC-100智能測(cè)控儀一樣發(fā)送查詢指令獲取數(shù)據(jù)。管理該設(shè)備的類(lèi)從CActiveCOMHelper類(lèi)派生而來(lái),命名為CLU902M,代碼如下:classCLU902M:CActiveCOMHelper{publicboolisActive;//設(shè)備激活標(biāo)志

publicbyteaddress;//設(shè)備地址

publicCLU902M(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){}//根據(jù)命令名稱(chēng)構(gòu)建命令對(duì)象

publicCCommandmakeCommand(stringcommandName){CCommandcommand=newCCommand();switch(commandName){case"A"://尋址指令(激活設(shè)備)

mandName=commandName;command.replyLength=2;command.parity=Parity.Mark;command.cmdContent=newbyte[]{address};break;case"R"://讀數(shù)據(jù)指令

mandName=commandName;command.replyLength=8;command.parity=Parity.Space;command.cmdContent=newbyte[]{0x45};

break;}returncommand;}

protectedoverrideboolcheckReply(stringcmdType,byte[]bRecv){switch(cmdType){case"A"://尋址命令

if(bRecv[0]==0x4F&&bRecv[1]==0x4B){this.isActive=true;returntrue;}break;case"R"://讀數(shù)據(jù)指令

if(bRecv[6]==0x4F&&bRecv[7]==0x4B)returntrue;break;}returnfalse;}publicfloatHexToFloat(byteH,byteL){return(float)(H*256+L)/10.0F;}}在UI模塊中,每個(gè)CLU902M對(duì)象負(fù)則和一個(gè)LU-902M位式調(diào)節(jié)儀通信,程序先判斷設(shè)備是否激活,未激活前先發(fā)尋址命令激活設(shè)備,對(duì)已經(jīng)激活的設(shè)備,UI線程每隔1秒鐘發(fā)送讀數(shù)命令獲取參數(shù)值。代碼如下:privateCLU902Mlu902m;privatevoidbtnStart_Click(objectsender,EventArgse){lu902m=newCLU902M

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論