版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
工控程序設(shè)計1學習情景2.4多個串口設(shè)備數(shù)據(jù)的連續(xù)采集
2學習情景2.4多個串口設(shè)備數(shù)據(jù)的連續(xù)采集
2.4.1學習要點1.知識點:煤礦鉆機性能檢測設(shè)備的數(shù)據(jù)通信協(xié)議,數(shù)據(jù)幀的校驗方法
2.技能點:校驗碼的計算,上位機主動模式串口通信類的設(shè)計,HC-100智能測控儀、JW-2A扭矩儀、LU-902M位式調(diào)節(jié)儀數(shù)據(jù)采集2.4.2任務描述在前一個情景中實現(xiàn)了對單個HSDZC電能綜合測試數(shù)據(jù)的接收。在鉆機性能測試系統(tǒng)中,還需要使用JW-2A扭矩儀、HC-100智能測控儀、LU-902M位式調(diào)節(jié)儀來采集其它參數(shù)的值,而這些設(shè)備的數(shù)據(jù)通信規(guī)則不同,所以必須對每種設(shè)備編寫通信程序,并同步、連續(xù)地采集多個設(shè)備的數(shù)據(jù)。該教學情景中先針對上位機主動通信模式設(shè)計基類CActiveCOMHelper,再分別對三種不同的儀器分別設(shè)計派生類來進行數(shù)據(jù)管理,實現(xiàn)對多個不同設(shè)備進行同步、連續(xù)的數(shù)據(jù)采集。2.4.3
相關(guān)知識1煤礦鉆機性能檢測設(shè)備的數(shù)據(jù)通信協(xié)議(1)HC-100智能測控儀
HC-100智能測控儀可以使用RS232、RS485接口與計算機通訊,數(shù)據(jù)格式為1個起始位,8個數(shù)據(jù)位,無奇偶校驗,1個停止位,共11位。設(shè)備的所有數(shù)字變換成ASCII碼進行傳輸:例如:儀表編號Addr=01,測量值=123.4,則數(shù)據(jù)千位為31H、百位為32H、十位為33H、小數(shù)點為2EH,個位為34H,符號位2BH為正,2DH為負。從儀表讀數(shù)據(jù)的指令格式為:EOT+儀表地址編號+52H+參數(shù)+ENQ表2.4.1發(fā)送給HC100的數(shù)據(jù)格式EOT儀表編號(十位)儀表編號(個位)R參數(shù)ENQ04H30H31H52H30H30H
05H儀表返回數(shù)據(jù)的格式為:STX+儀表地址編號+符號位+測量值+校驗碼+ETX。其中的數(shù)據(jù)參數(shù)值為符號位+4位有效位+小數(shù)點,共6位,校驗碼為前面發(fā)送的9個字節(jié)之和。表2.4.2HC100返回的數(shù)據(jù)格式STX儀表編號符號千位百位十位小數(shù)點個位校驗碼ETX02H30H31H2bH31H32H33H2eH34H83H03HHC-100智能控制儀的數(shù)據(jù)處理流程如圖2.4.1所示
圖2.4.1HC-100智能控制儀數(shù)據(jù)處理流程(2)JW-2A扭矩儀JW-2A扭矩儀采用多機通訊方式,本機地址為0AH。數(shù)據(jù)位8位,停止位1位。波特率可用跳線選擇4800bps或2400bps。奇偶位在這里做地址和數(shù)據(jù)判別位,1為地址,0為數(shù)據(jù)。儀器只被地址觸發(fā),即上位機只有向儀器發(fā)0AH,并且奇偶位為1時,才能得到儀器的響應。儀器被本機地址觸發(fā)后,向上位機傳回本機地址,然后等待上位機發(fā)來的命令。受到命令后,根據(jù)命令執(zhí)行不同的任務。命令為一個字節(jié)。目前有效的命令有15個,下面敘述各命令代表的任務。0:讀扭矩轉(zhuǎn)速儀器受到命令后向上位機依次傳送扭矩,轉(zhuǎn)速,采樣時間3個參數(shù)。扭矩、轉(zhuǎn)速為浮點數(shù),每個參數(shù)4個字節(jié)。采樣時間為整數(shù),2個字節(jié)。每個參數(shù)的傳送順序都是從內(nèi)存的低地址到高地址1:存儲操作。在測量狀態(tài)收到此命令,將啟動存儲操作;在存儲狀態(tài)收到此命令,將退出存儲狀態(tài)。2:讀儀器存儲的數(shù)據(jù)數(shù)組。在非存儲狀態(tài)收到此命令,將向上位機傳送春初數(shù)據(jù)的數(shù)組。3:釋放操作。在測量狀態(tài)收到此命令,將啟動釋放操作;在釋放狀態(tài)儀器不再接受命令。4:扣除/不扣除轉(zhuǎn)換。在扣除狀態(tài)收到此命令,將退出扣除狀態(tài);在非扣除狀態(tài)收到此命令,將進入扣除狀態(tài)。5:內(nèi)/外轉(zhuǎn)速顯示轉(zhuǎn)換。在顯示內(nèi)轉(zhuǎn)速時收到此命令,將顯示外轉(zhuǎn)速;在顯示外轉(zhuǎn)速時收到此命令,將顯示內(nèi)轉(zhuǎn)速。6:調(diào)零操作。儀器才測量狀態(tài)收到此命令,將啟動調(diào)零操作。7:讀儀器狀態(tài)。儀器收到命令后向上位機傳送儀器狀態(tài)字節(jié)。狀態(tài)字節(jié)各位的定義如表2.4.3所示。表2.4.3JW-2A通信協(xié)議Bit位置等于1的情況等于0的情況bit0存儲狀態(tài)非存儲狀態(tài)bit1釋放狀態(tài)非釋放狀態(tài)bit2扣除狀態(tài)非扣除狀態(tài)bit3外轉(zhuǎn)速狀態(tài)內(nèi)轉(zhuǎn)速狀態(tài)bit4調(diào)零狀態(tài)非調(diào)零狀態(tài)bit5外轉(zhuǎn)速通道為小電機轉(zhuǎn)速外轉(zhuǎn)速通道為外轉(zhuǎn)速bit6外轉(zhuǎn)速通道有信號外轉(zhuǎn)速通道無信號bit7儀器處于設(shè)置狀態(tài)儀器處于測量狀態(tài)8:讀模擬通道數(shù)據(jù)。儀器收到命令后向上位機依次傳送0至7通道的A/D采樣結(jié)果。每通道2字節(jié),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點位置。小數(shù)點位置為0,有0位小數(shù)點;小數(shù)點位置為1,有1位小數(shù)點;小數(shù)點位置為2,有2位小數(shù)點。9:讀0點。儀器收到命令后向上位機依次傳送10個零點值和其相應的轉(zhuǎn)速值。每個零點6個字節(jié)(前4個字節(jié)是零點,浮點數(shù),后2個字節(jié)是轉(zhuǎn)速,無符號整數(shù),高位在前),共60個字節(jié)。10:寫零點。儀器受到命令后準備接受10個零點,共60個字節(jié)的數(shù)據(jù)。上位機應按上述讀零點的順序依次將60個字節(jié)寫回去。注意,寫零點不能少于60字節(jié)。11:讀扭矩參數(shù)。儀器收到命令后向上位機依次傳送11個參數(shù),共24個字節(jié)。這11個參數(shù)的排列順序,數(shù)據(jù)類型,數(shù)據(jù)長度如表2.4.4所示。12:寫扭矩參數(shù)。儀器收到命令后準備接受11個參數(shù),共24個字節(jié)的數(shù)據(jù)。上位機應按上述讀扭矩參數(shù)的順序依次將24個字節(jié)寫回去。注意:寫扭矩參數(shù)不能少于24字節(jié)。13:讀模擬通道量程。儀器收到命令后向上位機依次傳送8個通道的量程值。每個量程2個字節(jié),共16個字節(jié)。數(shù)據(jù)類型是無符號整數(shù),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點位置。小數(shù)點位置為0,有0位小數(shù)點;小數(shù)點位置為1,有1位小數(shù)點,小數(shù)點位置為2,有2位小數(shù)點。表2.4.4JW-2A的扭矩參數(shù)數(shù)據(jù)名稱數(shù)據(jù)類型數(shù)據(jù)長度(byte)系數(shù)無符號整數(shù)2量程浮點數(shù)4齒數(shù)無符號整數(shù)2采樣周期無符號整數(shù)2扭矩報警值浮點數(shù)4轉(zhuǎn)速報警值無符號整數(shù)2小電機轉(zhuǎn)速無符號整數(shù)2定時打印時間無符號整數(shù)2轉(zhuǎn)速模擬輸出范圍無符號整數(shù)2標定溫度無符號整數(shù)1使用溫度無符號整數(shù)114:寫模擬通道量程。儀器收到命令后準備接收8個通道的量程表。每個量程2個字節(jié),共16個字節(jié)。數(shù)據(jù)類型是無符號整數(shù),高位在前。低14位表示數(shù)值大小,最高2位表示小數(shù)點位置。小數(shù)點位置為0,有0位小數(shù)點;小數(shù)點位置為1,有1位小數(shù)點,小數(shù)點位置為2,有2位小數(shù)點。上位機應按上述讀模擬通道量程的順序依次將16個字節(jié)寫回去。需要注意的是:寫模擬通道量程不能少于16字節(jié)。
JW-2A扭矩儀的數(shù)據(jù)采用IEEE浮點數(shù)形式表示,需要作浮點數(shù)字節(jié)數(shù)組到浮點數(shù)的轉(zhuǎn)換。如果用DCBA表示浮點數(shù),D為高位,A為低位,每個字母表示一個字節(jié),那么DCBA依次為SXXXXXXXXMMMMMMMMMMMMMMMMMMMMMMM,其中S代表符號,1位,1表示負,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ù)處理流程
另外,儀器處于釋放狀態(tài)時,每釋放一組數(shù)據(jù)都會將數(shù)據(jù)從串口發(fā)送出來。數(shù)據(jù)格式和發(fā)送的順序同于用0命令讀扭矩轉(zhuǎn)速。(3)LU-902M位式調(diào)節(jié)儀LU-902M采用串行異步通訊,提供RS232C、422A或者485通訊接口,波特率有1200、2400、4800、9600四種選擇。每幀數(shù)據(jù)包含1個起始位(第0位),8個數(shù)據(jù)位(第1-8位),1個“尋址/數(shù)據(jù)”選擇位(第9位,決定指令類別),1個停止位,共11位,數(shù)據(jù)采用16進制表達。在每個通訊指令中,儀表最后返回信息4FH、4BH表示通訊成功,返回3FH,3FH表示通訊失敗。1)尋址指令當上位機要對某LU-902M儀表進行通訊操作時,應先對其發(fā)尋址指令。尋址指令為單字節(jié)指令,第1-8位為地址,第9位(校驗位)為“1”(非尋址指令為“0”)。2)數(shù)據(jù)讀取指令指令格式:45H儀表返回:PV、SV、MV、4FH、4BH其中PV為測量值、SV為設(shè)定值、MV為輸出值,各占兩個字節(jié),低字節(jié)在前高字節(jié)在后。3)讀參數(shù)指令指令格式:52H+參數(shù)代碼儀表返回:參數(shù)值+4FH、4BH4)寫參數(shù)指令指令格式:57H+參數(shù)代碼+參數(shù)值儀表返回:4FH、4BH5)結(jié)束指令指令格式:4FH或第9位為“1”的非本機尋址指令儀表無返回2數(shù)據(jù)幀的校驗數(shù)據(jù)幀校驗的目的是為了檢查接收到的數(shù)據(jù)幀的完整性和準確性。和校驗位不同,校驗位的作用是保證一個數(shù)據(jù)單位的正確性,是從微觀角度考慮。形象地說,校驗位保證一個字正確,數(shù)據(jù)幀校驗是保證一段話正確。對數(shù)據(jù)幀進行校驗的方法是:發(fā)送方根據(jù)要發(fā)送的數(shù)據(jù)幀,利用某種算法計算出若干字節(jié)的校驗碼,并把校驗碼附加在數(shù)據(jù)幀中發(fā)送給接收端,接收端接收到數(shù)據(jù)后,分離出校驗碼和數(shù)據(jù)本身,再根據(jù)發(fā)送方的算法,計算出校驗碼,如果和接收到的校驗碼一致,則認為接收到的數(shù)據(jù)準確無誤。串口通信中常用的校驗方式有累加和校驗、異或和校驗、循環(huán)冗余校驗等。(1)累加和校驗累加和校驗的過程是,發(fā)送端將數(shù)據(jù)的每個字節(jié)累加求和,然后截取最低字節(jié)(或最低兩字節(jié))作為校驗碼發(fā)送給接收端,接收端收到數(shù)據(jù)后,用同樣的方法計算累加和,并與發(fā)送過來的校驗碼進行比較,從而檢驗發(fā)送的數(shù)據(jù)是否有誤。(2)異或和校驗異或和校驗的過程是,發(fā)送端取出發(fā)送數(shù)據(jù)的第1個字節(jié),與后續(xù)每個字節(jié)依次按位異或,然后將計算結(jié)果(1個字節(jié))作為校驗碼發(fā)送給接收端,接收端收到數(shù)據(jù)后,用同樣的方法計算異或和,并與發(fā)送過來的校驗碼進行比較,從而檢驗發(fā)送的數(shù)據(jù)是否有誤。(3)循環(huán)冗余校驗循環(huán)冗余校驗(CyclicalRedundancyCheck)簡稱CRC,它利用除法及余數(shù)的原理來作錯誤偵測。實際應用時,發(fā)送端計算出校驗碼值并附加在數(shù)據(jù)幀中發(fā)送給接收端,接收端對收到的數(shù)據(jù)重新計算校驗碼并與收到的校驗碼相比較,若兩個值不同,則說明數(shù)據(jù)通訊出現(xiàn)錯誤,要求發(fā)送端重新發(fā)送。常用的CRC標準有CRC-12、CRC-16、CRC-CCITT和CRC-32,其中CRC-16和CRC-CCITT用來作一個字節(jié)數(shù)據(jù)的校驗,在串口數(shù)據(jù)校驗中最常用的是CRC-16。下面是循環(huán)冗余校驗碼的計算過程:1)設(shè)置CRC寄存器,并給其賦值FFFF(hex)。2)將數(shù)據(jù)的第一個字節(jié)與16位CRC寄存器的低8位進行異或,并把結(jié)果存入CRC寄存器。3)CRC寄存器向右移一位,MSB(最高有效位)補零,移出并檢查LSB(最低有效位)。4)如果LSB為0,重復第三步;若LSB為1,CRC寄存器與多項式碼相異或。5)重復第3與第4步直到8次移位全部完成。此時一個字節(jié)數(shù)據(jù)處理完畢。6)重復第2至第5步直到所有數(shù)據(jù)全部處理完成。7)最終CRC寄存器的內(nèi)容即為CRC值。常用的循環(huán)冗余校驗標準多項式為:
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多項式對應多項式碼為1000000000000101(0x8005),CRC-CCITT對應的多項式碼為0001000000100001(0x1021)。2.4.4
任務實施1校驗碼的計算在串口通信通,校驗碼在保證數(shù)據(jù)幀的正確性方面具有重要作用,雖然在鉆機性能測試系統(tǒng)中只用到累加和校驗,但為了能應對串口通信中可能出現(xiàn)的復雜情況,下面對三種校驗碼的計算都進行具體實現(xiàn)。(1)累加和校驗碼的計算累加和校驗碼可以取累加和的低8位(1個字節(jié))或低16位(兩個字節(jié)),在下位機處理能力允許的情況下采用兩個字節(jié)作校驗碼可以提高校驗的準確度。下面的C#代碼將累加和校驗碼生成功能封裝到CCheck類的方法中,其中CheckSum_1方法計算單字節(jié)累加和校驗碼,CheckSum_2方法計算雙字節(jié)累加和校驗碼classCCheck{//函數(shù)功能://計算字節(jié)數(shù)組b中從offset位置開始的count個元素的單字節(jié)累加和校驗碼//參數(shù)://b:要計算累加和的字節(jié)數(shù)組//offset:要計算累加和的元素的起始位置//count:要計算累加和的連續(xù)元素個數(shù)//返回值:累加和的低8位(單個字節(jié))
publicstaticbyteCheckSum_1(byte[]b,intoffset,intcount){uintsum=0;for(inti=offset;i<offset+count;i++)sum+=b[i];//數(shù)組元素累加求和
return(byte)(sum&0xFF);}//函數(shù)功能://計算字節(jié)數(shù)組b中從offset位置開始的count個元素的雙字節(jié)累加和校驗碼//參數(shù)://b:要計算累加和的字節(jié)數(shù)組//offset:要計算累加和的元素的起始位置//count:要計算累加和的連續(xù)元素個數(shù)//返回值:長度為2的字節(jié)數(shù)組,第1個元素為累加和的低8位//第2個元素為累加和的高8位
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;}}下面的測試程序調(diào)用CheckSum_1方法,計算出長度為1個字節(jié)的累加和校驗碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0};//保留一個字節(jié)位置存儲校驗碼bytesum=CCheck.CheckSum_1(b,0,b.Length-1);//計算單字節(jié)累加和b[b.Length-1]=sum;//附加在字節(jié)數(shù)組末尾下面的測試程序調(diào)用CheckSum_2方法,計算出長度為兩個字節(jié)的累加和校驗碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0,0};//保留兩個字節(jié)位置存儲校驗碼byte[]sum=CCheck.CheckSum_2(b,0,b.Length-2);//計算雙字節(jié)累加和b[b.Length-2]=sum[0];//附加在字節(jié)數(shù)組末尾b[b.Length-1]=sum[1];(2)異或和校驗碼的計算下面的C#代碼將異或和校驗碼生成功能封裝到CCheck類的方法中,方法名為XorSum:classCCheck{//函數(shù)功能://計算字節(jié)數(shù)組b中從offset位置開始的count個元素的單字節(jié)異或和校驗碼//參數(shù)://b:要計算累加和的字節(jié)數(shù)組//offset:要參與計算校驗碼的元素的起始位置//count:要參與計算校驗碼的連續(xù)元素個數(shù)//返回值:異或和(8位,1個字節(jié))
publicstaticbyteXorSum(byte[]b,intoffset,intcount){bytesum=0;for(inti=offset;i<offset+count;i++)sum^=b[i];//依次和每個元素進行按位異或運算
returnsum;}}下面的測試程序調(diào)用XorSum方法,計算出長度為1個字節(jié)的異或和校驗碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0};//保留一個字節(jié)位置存儲校驗碼bytexorsum=CCheck.XorSum(b,0,b.Length-1);//計算異或和b[b.Length-1]=xorsum;//附加在字節(jié)數(shù)組末尾(3)循環(huán)冗余校驗碼的計算下面的C#代碼將CRC-16校驗碼生成功能封裝到CCheck類的方法中,方法名為CRC16:classCCheck{//函數(shù)功能://計算字節(jié)數(shù)組b中從offset位置開始的count個元素的循環(huán)冗余校驗碼//參數(shù)://b:要計算累加和的字節(jié)數(shù)組//offset:要參與計算校驗碼的元素的起始位置//count:要參與計算校驗碼的連續(xù)元素個數(shù)//CrcPoly:CRC多項式對應的16位二進制編碼//返回值:長度為2的字節(jié)數(shù)組,第1個元素為校驗碼的低8位//第2個元素為校驗碼的高8位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];//將當前字節(jié)與CRC寄存器的低8位進行按位異或
for(intn=1;n<=8;n++)//進行8次邏輯移位
{LSB=CrcReg&1u;//“u”表示該常量是無符號整型
CrcReg>>=1;//CRC寄存器邏輯右移1位
if(LSB==1)CrcReg^=CrcPoly;}}
tmp[0]=(byte)(CrcReg&0xFF);//低8位在前
tmp[1]=(byte)((CrcReg&0xFF00)>>8);//高8位在后
returntmp;}}下面的測試程序調(diào)用CRC16方法,計算出長度為兩個字節(jié)的循環(huán)冗余校驗碼,并附加在字節(jié)數(shù)組末尾:byte[]b={0x41,0x42,0x43,0,0};//保留兩個字節(jié)位置存儲校驗碼byte[]crc=CCheck.CRC16(b,0,b.Length–2,0x8005);//計算循環(huán)冗余校驗碼b[b.Length-2]=sum[0];//附加在字節(jié)數(shù)組末尾b[b.Length-1]=sum[1];2上位機主動模式串口通信類的設(shè)計煤礦鉆機性能測試系統(tǒng)中用到的HC-100智能測控儀、JW-2A扭矩儀和LU-902M位式調(diào)節(jié)儀與HSDZC電能綜合測試儀不同,這些設(shè)備需要上位機主動發(fā)送命令,才給予回復,因此可以把這三種設(shè)備的通信模式歸為“上位機主動模式”。下面將設(shè)計上位機主動模式的串口通信類CActiveCOMHelper,和CPassiveCOMHelper類不同的是,CActiveCOMHelper類中增加了一個名為command的成員,存放當前應該執(zhí)行的命令,線程函數(shù)根據(jù)該成員的相關(guān)屬性,就知道現(xiàn)在應該給下位機發(fā)送什么命令。由于采用“提問——回答”的方式,能夠準確控制下位機發(fā)送來的數(shù)據(jù),故不再需要隊列來暫存接收的數(shù)據(jù)。CCommand類實現(xiàn)代碼如下:publicclassCCommand{publicstringcommandName;//命令名字
publicbyte[]cmdContent;//命令的內(nèi)容
publicParityparity=Parity.None;//發(fā)送命令時采用的校驗方式
publicbyte[]replyContent;//回復內(nèi)容
publicintreplyLength;//回復內(nèi)容的規(guī)定長度
publicboolisCompleted;//命令是否完成
publicCCommand()//創(chuàng)建對象時commandName不能為null,以免后面比較時出錯
{mandName=""; }}
command成員(CCommand的實例)是UI模塊和CActiveCOMHelper對象的連接紐帶。UI模塊首先查詢前一個命令是否完成(isCompleted是否為true),若已經(jīng)完成,就設(shè)置下一條命令的名字、內(nèi)容、校驗方式、回復內(nèi)容的規(guī)定長度,交給CActiveCOMHelper對象去執(zhí)行;CActiveCOMHelper對象執(zhí)行完命令后,把回復內(nèi)容填好,并將完成標志isCompleted設(shè)置為true。如此循環(huán),就可以不斷讓CActiveCOMHelper對象執(zhí)行命令。這樣分工的好處是,處于上層的UI模塊沒有必要知道如何和串口通信、如何創(chuàng)建線程等等復雜瑣碎的具體操作,而只要知道該發(fā)什么命令,以及如何處理收到的結(jié)果。CActiveCOMHelper類實現(xiàn)代碼如下:publicclassCActiveCOMHelper{publicintreadTimeOut;//接收數(shù)據(jù)超時毫秒數(shù)
publicstringportName;//設(shè)備所占用的串口名
privateboolstopFlag;//線程循環(huán)停止標志
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;//默認3000毫秒讀取超時
mand=newCCommand();//始終保持有一個命令
mand.isCompleted=true;//該命令開始時處于完成狀態(tài)
}publicvoidstart(){Threadt=newThread(newThreadStart(threadFun));t.IsBackground=true;stopFlag=false;t.Start();}publicvoidstop(){stopFlag=true;}publicCCommandgetCommand()//獲取一個克隆的命令對象
{CCommandcmd=newCCommand();Monitor.Enter(this);//線程同步:在進行g(shù)et操作時,不準進行set操作
mandName=mandName;cmd.cmdContent=command.cmdContent;cmd.parity=command.parity;cmd.replyContent=command.replyContent;cmd.replyLength=command.replyLength;cmd.isCompleted=command.isCompleted;Monitor.Exit(this);returncmd;}publicvoidsetCommand(CCommandcmd){Monitor.Enter(this);//線程同步:在進行set操作時,不準進行g(shù)et操作
mand=cmd;Monitor.Exit(this);}protectedvirtualboolcheckReply(stringcmdType,byte[]bRecv){returnfalse;}privatevoidthreadFun(){SerialPortsp=newSerialPort(portName,baudRate,Parity.None,dataBits,stopBits);try{if(sp.IsOpen)sp.Close();sp.Open();}
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;//校驗位
sp.Write(bSend,0,bSend.Length);
first=(byte)sp.ReadByte();//阻塞方式讀取數(shù)據(jù)
bRecv=newbyte[cmd.replyLength];//存儲回復數(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ù)是否達到規(guī)定長度
}if(n>3)continue;//等待3次后數(shù)據(jù)還未到達
sp.Read(bRecv,1,cmd.replyLength-1);if(checkReply(mandName,bRecv)){cmd.replyContent=bRecv;//填寫回復內(nèi)容
cmd.isCompleted=true;//修改命令完成標志
setCommand(cmd);if(DataReceived!=null)//引發(fā)事件,通知使用該類的程序
DataReceived(this);}}catch{}elseThread.Sleep(20);//沒有新命令下達,延時防止CPU占用率過高
}if(sp!=null&&sp.IsOpen)sp.Close();}}
在前一個步驟中已經(jīng)實現(xiàn)了串口數(shù)據(jù)接收、解析和顯示的功能,并且在工作者線程中接收和處理數(shù)據(jù),在此期間前臺的UI線程能響應用戶輸入。從功能上看,已經(jīng)能夠滿足用戶需求,但是從代碼的組織和管理角度看,該程序還有比較大問題:負責接收和處理數(shù)據(jù)的代碼和負責顯示的代碼混雜在一起,不能重復使用,若增加一個同類設(shè)備,很多代碼還要重寫,而且給查看和調(diào)試程序也帶來較大困難。下面用面向?qū)ο蠓椒▽Τ绦蜻M行重新設(shè)計。3HC-100智能測控儀數(shù)據(jù)采集HC-100智能測控儀采用以上位機為主導的“提問——應答”通信模式,管理該設(shè)備的類可以從CActiveCOMHelper類派生而來,命名為CHC100,在類中覆蓋checkReply方法,并實現(xiàn)浮點數(shù)的解碼方法AsciiToFloat。該類的實現(xiàn)代碼如下:publicclassCHC100:CActiveCOMHelper{publicCHC100(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){} //根據(jù)命令名稱構(gòu)建命令對象
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++)//下標為3到8的數(shù)據(jù)段表示浮點數(shù)值
{s.Append((char)b[i]);//將字符連接為字符串
}floatf=0F;try{f=Single.Parse(s.ToString());//字符串轉(zhuǎn)換為浮點數(shù)
}catch{}returnf;}}下面的代碼說明了CHC100類在UI模塊中的應用。后臺工作者線程獲得下位機應答數(shù)據(jù)后,存儲在CCommand對象中,不用事件通知UI線程。UI線程每隔1秒鐘檢查一次命令執(zhí)行情況,如果命令執(zhí)行完畢,則讀取本次的應答數(shù)據(jù),并設(shè)置下一次的命令。privateCHC100hc100;privatevoidbtnStart_Click(objectsender,EventArgse)//開始采集數(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();//獲取當前命令
if(cmd.isCompleted)//當面命令已完成
{CCommandnextCmd=hc100.makeCommand("R");//構(gòu)建下一個命令
hc100.setCommand(nextCmd);if(cmd.cmdContent!=null)Trace.WriteLine("HC100回復:壓力:"+AsciiToFloat(cmd.replyContent));}elseTrace.WriteLine(mandName+"命令還未完成");}4JW-2A扭矩儀數(shù)據(jù)采集JW-2A扭矩儀用于測量鉆機的扭矩和轉(zhuǎn)速,該設(shè)備和HC-100智能測控儀相似,也采用以上位機為主導的“提問——應答”通信模式,不同的是通信方式比HC-100智能測控儀稍微復雜,每次通信需要發(fā)送兩道命令,首先發(fā)尋址指令激活,再發(fā)送讀數(shù)據(jù)指令獲取數(shù)據(jù)。管理該設(shè)備的類從CActiveCOMHelper類派生而來,命名為CJW2A,代碼如下:classCJW2A:CActiveCOMHelper{publicCJW2A(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){}publicCCommandmakeCommand(stringcommandName)//根據(jù)命令名稱構(gòu)建命令對象
{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)換為浮點數(shù)(按照IEEE754規(guī)范){ints;//符號位,+1或者-1。
inte;//指數(shù),根據(jù)IEEE754,指數(shù)部份算出來后要減127floatm;//小數(shù)位。
floatmreturn;//返回的浮點數(shù),應為:(1+小數(shù)位)*2^(指數(shù))*(符號位)
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模塊中,每個CJW2A對象負則和一個JW-2A扭矩儀通信,由于每次通信過程要發(fā)送兩道命令,所以代碼中采用事件通知方式來使兩道命令連貫地發(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回復:扭矩"+nj+",轉(zhuǎn)速"+zs);}}elseTrace.WriteLine("JW2A的"+mandName+"命令還未完成");}5LU-902M位式調(diào)節(jié)儀數(shù)據(jù)采集LU-902M位式調(diào)節(jié)儀在鉆機性能測試系統(tǒng)中應用最廣泛,用于測量大氣溫度、馬達溫度、泵溫度、油溫、冷卻水流量、馬達進油流量、馬達回油流量、馬達油壓、操縱臺噪音、馬達噪音等諸多參數(shù),該設(shè)備同樣采用以上位機為主導的“提問——應答”通信模式,它仍然需要激活,不過只激活一次,以后就象HC-100智能測控儀一樣發(fā)送查詢指令獲取數(shù)據(jù)。管理該設(shè)備的類從CActiveCOMHelper類派生而來,命名為CLU902M,代碼如下:classCLU902M:CActiveCOMHelper{publicboolisActive;//設(shè)備激活標志
publicbyteaddress;//設(shè)備地址
publicCLU902M(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){}//根據(jù)命令名稱構(gòu)建命令對象
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)ret
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年己二酸二甲酯項目建議書
- 全程融資合同范本
- 商鋪轉(zhuǎn)租賃合同
- 超市柜臺租賃協(xié)議
- 佳木斯市個人車位租賃合同
- 2025年海洋潛標系統(tǒng)項目合作計劃書
- 2025年碳纖維正交三向織物項目合作計劃書
- 2025年X射線管項目發(fā)展計劃
- 2025個人承包土地合同書
- 2024年零星建筑工程施工合作合同范本版B版
- DB3302-T 1015-2022 城市道路清掃保潔作業(yè)規(guī)范
- 手術(shù)室提高患者術(shù)中保溫措施的執(zhí)行率PDCA課件
- 報刊雜志發(fā)放登記表
- 大學物理(下)(太原理工大學)知到章節(jié)答案智慧樹2023年
- 布袋除塵器項目可行性分析報告
- 2023年安徽省公務員錄用考試《行測》真題及答案解析
- 我和我的祖國-電影賞析
- 基本事實要素表
- 市場監(jiān)督管理局企業(yè)注冊、經(jīng)營范圍登記規(guī)范表述:行業(yè)分類及條目代碼
- 2023-2024學年青海省西寧市小學數(shù)學二年級上冊期末自測試題
- 2023年中國工商銀行度校園招聘筆試題庫及答案解析
評論
0/150
提交評論