工控程序設(shè)計(jì)之串口設(shè)備的數(shù)據(jù)采集_第1頁(yè)
工控程序設(shè)計(jì)之串口設(shè)備的數(shù)據(jù)采集_第2頁(yè)
工控程序設(shè)計(jì)之串口設(shè)備的數(shù)據(jù)采集_第3頁(yè)
工控程序設(shè)計(jì)之串口設(shè)備的數(shù)據(jù)采集_第4頁(yè)
工控程序設(shè)計(jì)之串口設(shè)備的數(shù)據(jù)采集_第5頁(yè)
已閱讀5頁(yè),還剩38頁(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ì)第一頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2串口設(shè)備的數(shù)據(jù)采集第二頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收2.3.1學(xué)習(xí)要點(diǎn)

1.知識(shí)點(diǎn):線程的概念,委托的概念和使用方法,線程的創(chuàng)建和啟動(dòng),工作者線程和用戶界面線程之間的數(shù)據(jù)傳遞,線程同步技2.技能點(diǎn):工作者線程的創(chuàng)建,串口數(shù)據(jù)接收和處理操作的封裝2.3.2任務(wù)描述

1.在前一個(gè)情景中完成了接收和處理單一串口設(shè)備數(shù)據(jù)的工作任務(wù)。實(shí)際應(yīng)用中,上位機(jī)需要連續(xù)地接收和處理下位機(jī)發(fā)送的數(shù)據(jù),而且在等待和接收數(shù)據(jù)的時(shí)候,用戶界面不能停止響應(yīng)。接收數(shù)據(jù)和響應(yīng)用戶輸入這兩個(gè)工作在宏觀上是同時(shí)進(jìn)行的,為了滿足該需求,必須采用多線程模式來(lái)進(jìn)行程序設(shè)計(jì)。

2.該教學(xué)情景通過(guò)“在工作者線程中接收HSDZC電能綜合測(cè)試儀的”“HSDZC電能綜合測(cè)試儀數(shù)據(jù)接收和處理操作的封裝”這兩個(gè)實(shí)施步驟達(dá)到連續(xù)接收接收單個(gè)串口設(shè)備(下位機(jī))數(shù)據(jù)的目的。第三頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

2.3.3相關(guān)知識(shí)1多線程技術(shù)概述(1)線程的概念Windows是一個(gè)搶占式多任務(wù)操作系統(tǒng),在系統(tǒng)內(nèi)核中提供了對(duì)多線程的支持,多線程技術(shù)可以讓應(yīng)用程序在一個(gè)耗時(shí)的操作中能夠及時(shí)對(duì)用戶操作進(jìn)行響應(yīng),并且從宏觀上達(dá)到多個(gè)任務(wù)“齊頭并進(jìn)”的目的進(jìn)程是應(yīng)用程序的一個(gè)運(yùn)行例程,是應(yīng)用程序的一次動(dòng)態(tài)執(zhí)行過(guò)程。線程是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。每個(gè)進(jìn)程至少需要一個(gè)執(zhí)行線程,由系統(tǒng)自動(dòng)創(chuàng)建,程序設(shè)計(jì)者可以根據(jù)需要?jiǎng)?chuàng)建其它線程。由于多個(gè)線程共享進(jìn)程中的全局變量和系統(tǒng)資源,所以線程間的切換比較容易,通信也比較方便。第四頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

(2).NETFramework對(duì)多線程的支持.NET平臺(tái)庫(kù)提供了Thread類對(duì)線程進(jìn)行處理,該類包含在System.Threading命名空間中,程序中需要包含語(yǔ)句“usingSystem.Threading;”。編程人員可以通過(guò)創(chuàng)建一個(gè)Thread類的實(shí)例來(lái)創(chuàng)建一個(gè)線程,并通過(guò)Thread類提供的方法對(duì)線程進(jìn)行管理。Thread類的常用屬性和方法如下表:表2.3.1Thread類的常用屬性和方法第五頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

2委托的概念和使用方法C#中的委托的作用相當(dāng)于C/C++中的函數(shù)指針,函數(shù)指針是一個(gè)函數(shù)的入口地址。必修使用函數(shù)指針的場(chǎng)合是:程序員A編寫了函數(shù)f,該函數(shù)中需要執(zhí)行另外一個(gè)參數(shù)和返回值已經(jīng)確定,但名字暫時(shí)不能確定函數(shù),所以給函數(shù)設(shè)置一個(gè)函數(shù)指針類型的形式參數(shù);當(dāng)程序員B使用函數(shù)f時(shí),定義函數(shù)g,并把g的入口地址作為實(shí)際參數(shù)傳遞給函數(shù)f,這樣就可以在f中執(zhí)行函數(shù)g了。線程的啟動(dòng)是使用函數(shù)指針的一個(gè)典型例子,在啟動(dòng)線程之前,先要給操作系統(tǒng)指明線程啟動(dòng)后執(zhí)行哪一函數(shù)中包含的代碼,這時(shí)就要把函數(shù)的指針傳遞給創(chuàng)建線程的函數(shù)?;卣{(diào)(完成后通知)是使用函數(shù)指針的另外一個(gè)典型例子。如程序員A編寫了負(fù)責(zé)接收網(wǎng)絡(luò)數(shù)據(jù)的函數(shù)f1,程序員B編寫了負(fù)責(zé)處理數(shù)據(jù)的函數(shù)f2,那么就可以把f2的函數(shù)指針作為參數(shù)傳遞給函數(shù)f1,當(dāng)f1接收數(shù)據(jù)完畢后,自動(dòng)調(diào)用f2。所以回調(diào)的特點(diǎn)是:站在程序員B的角度看,函數(shù)由自己編寫,但是不由自己調(diào)用,且不知道什么時(shí)候被調(diào)用(因?yàn)榫W(wǎng)絡(luò)速度有快有慢),函數(shù)編寫者要做的就是把函數(shù)指針傳遞出去。第六頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

定義委托的關(guān)鍵字是delegate,它是從System.Delegate類派生出來(lái)的。例如:delegateintSomeDelegate(intp1,stringp2);//intp1和stringp2是被引用函數(shù)的參數(shù)類型和名稱。其中參數(shù)類型和參數(shù)的個(gè)數(shù)必須和被引用函數(shù)的類型與個(gè)數(shù)一致。3創(chuàng)建和啟動(dòng)線程一個(gè)線程必須和一個(gè)方法的入口(委托)關(guān)聯(lián)起來(lái),線程啟動(dòng)后,自動(dòng)從該入口進(jìn)入,執(zhí)行函數(shù)體中包含的內(nèi)容。C#應(yīng)用程序啟動(dòng)時(shí),自動(dòng)創(chuàng)建主線程,并進(jìn)入Main方法開始執(zhí)行,其它線程需要在程序里自己定義和啟動(dòng)。由于委托可以代表一個(gè)方法的入口

,第七頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

所以創(chuàng)建線程實(shí)例時(shí)只需要在Thread類的構(gòu)造方法里傳入一個(gè)委托實(shí)例即可,這個(gè)委托名叫ThreadStart,已經(jīng)在線程命名空間中定義作了定義:publicdelegatevoidThreadStart();所以創(chuàng)建線程方式如下:ThreadStartfunctionEntrance=newThreadStart(threadFunction);Threadt=newThread(functionEntrance);在委托ThreadStart的構(gòu)造方法里面?zhèn)魅氲氖欠椒?,這個(gè)方法可以是靜態(tài)方法,也可以是某個(gè)對(duì)象的方法。線程對(duì)象創(chuàng)建后,我們就可以調(diào)用其Start方法開始線程的執(zhí)行了。第八頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

我們可以在主線程里建立線程,也可以在線程里再創(chuàng)建線程,線程啟動(dòng)后會(huì)自動(dòng)執(zhí)行委托實(shí)例代表的方法,線程執(zhí)行完后會(huì)自動(dòng)銷毀并釋放其占用的資源。在一個(gè)新線程中執(zhí)行帶參數(shù)的函數(shù),操作步驟如下:●定義線程函數(shù):privatevoidparamThreadFunction(objectparam){ //函數(shù)體}●用ParameterizedThreadStart委托封裝線程函數(shù):第九頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

ParameterizedThreadStartfunctionEntrance=newParameterizedThreadStart(paramThreadFunction);●創(chuàng)建線程對(duì)象hreadt=newThread(functionEntrance);●啟動(dòng)線程

t.Start(param);//param為傳入的參數(shù),可以是任意對(duì)象第十頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

4線程同步技術(shù)多線程應(yīng)用程序中的的線程啟動(dòng)后,執(zhí)行的先后順序是無(wú)法預(yù)知的,通常情況下多個(gè)線程會(huì)交錯(cuò)執(zhí)行。但是在多個(gè)線程訪問(wèn)共享數(shù)據(jù)的情況下,必須對(duì)數(shù)據(jù)的訪問(wèn)進(jìn)行同步。好比有兩路車,一路自東向西,一路自南向北運(yùn)行,在一個(gè)十字路口交匯。在十字路口以外的區(qū)域可以看著私有區(qū)域,而十字路口則是共有區(qū)域,需要紅綠燈或交警來(lái)維護(hù)秩序,即確保在同一時(shí)刻只能有一路車進(jìn)入,而另外一路車必須等待,這就是現(xiàn)實(shí)生活中的線程同步問(wèn)題。第十一頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

下面的例子展示了一個(gè)讀數(shù)據(jù)線程和一個(gè)寫數(shù)據(jù)線程同時(shí)運(yùn)行的情況:privatestaticint[]a=newint[5];staticvoidMain(string[]args){Threadt1=newThread(newThreadStart(threadFun1));Threadt2=newThread(newThreadStart(threadFun2));t1.Start();t2.Start();}privatestaticvoidthreadFun1()//線程函數(shù)1{while(true)第十二頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

{for(inti=0;i<a.Length;i++)//將數(shù)組元素全部輸出

System.Console.Write(a[i]+"");System.Console.WriteLine();}}privatestaticvoidthreadFun2()//線程函數(shù)2{intflag=0,i;while(true){for(i=0;i<a.Length;i++)//將數(shù)組元素全部改為0或1

a[i]=flag;flag=flag==0?1:0;}}第十三頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

下面采用Monitor類來(lái)進(jìn)行線程同步,使數(shù)據(jù)讀、寫操作稱為原子操作。即達(dá)到這樣的目的:在線程2寫數(shù)據(jù)時(shí),線程1等待,在線程1讀數(shù)據(jù)時(shí),線程2等待,使每次輸出的結(jié)果全部為0或全部為1。當(dāng)調(diào)用Monitor類的Enter(Objectobj)方法時(shí),會(huì)獲取對(duì)象obj的獨(dú)占權(quán),直到調(diào)用Exit(Objectobj)方法時(shí),才會(huì)釋放對(duì)obj的獨(dú)占權(quán)。注意調(diào)用Enter方法的次數(shù)要和,調(diào)用Exit方法的次數(shù)相等。Monitor類還提供了TryEnter方法,該方法嘗試獲取obj對(duì)象的獨(dú)占權(quán),當(dāng)獲取獨(dú)占權(quán)失敗時(shí),將返回false。實(shí)現(xiàn)代碼如下:

第十四頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

privatestaticint[]a=newint[5];privatestaticobjectobj=newobject();staticvoidMain(string[]args){Threadt1=newThread(newThreadStart(threadFun1));Threadt2=newThread(newThreadStart(threadFun2));t1.Start();t2.Start();}privatestaticvoidthreadFun1(){while(true){Monitor.Enter(obj);//線程1進(jìn)入臨界區(qū)活動(dòng)時(shí),線程2等待

for(inti=0;i<a.Length;i++)System.Console.Write(a[i]+"");System.Console.WriteLine();第十五頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

Monitor.Exit(obj);//線程1出臨界區(qū)后,線程2才可以進(jìn)入

}}privatestaticvoidthreadFun2(){intflag=0,i;while(true){Monitor.Enter(obj);//線程2進(jìn)入臨界區(qū)活動(dòng)時(shí),線程1等待

for(i=0;i<a.Length;i++)a[i]=flag;

flag=flag==0?1:0;Monitor.Exit(obj);//線程2出臨界區(qū)后,線程1才可以進(jìn)入

}}第十六頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

5工作者線程向用戶界面線程傳遞數(shù)據(jù)用戶界面線程簡(jiǎn)稱UI線程,其主要特點(diǎn)是能響應(yīng)Windows消息,主要負(fù)責(zé)接收用戶輸入和向用戶展示程序執(zhí)行結(jié)果。為了及時(shí)響應(yīng)用戶的輸入,UI線程中不應(yīng)執(zhí)行費(fèi)時(shí)的運(yùn)算,更不能被阻塞。工作者線程一般用于在后臺(tái)進(jìn)行費(fèi)時(shí)運(yùn)算或和慢速設(shè)備打交道,這種線程不響應(yīng)Windows消息。在通信程序中,數(shù)據(jù)的發(fā)送和接收耗費(fèi)的時(shí)間不確定。為了在通信過(guò)程中能夠響應(yīng)用戶輸入,通常在建立一個(gè)或多個(gè)工作者線程,在后臺(tái)完成通信任務(wù)。工作者線程向運(yùn)行在UI線程中的用戶控件傳遞數(shù)據(jù)時(shí),不能直接對(duì)對(duì)控件的屬性和方法進(jìn)行調(diào)用,而要先定義一個(gè)委托,再用控件的Invoke方法,切換到UI線程去執(zhí)行委托所指向的函數(shù),來(lái)更新控件顯示的內(nèi)容。在下面的程序中,工作線程每循環(huán)完一次,就更新UI線程中的控件屬性,向用戶報(bào)告當(dāng)前步驟。程序界面和后臺(tái)代碼如下:第十七頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

圖2.3.1工作者線程向UI線程傳遞數(shù)據(jù)privatevoidbtnRun_Click(objectsender,EventArgse){ThreadStartfunEntrance=newThreadStart(threadFun);Threadt=newThread(funEntrance);t.IsBackground=true;t.Start();}第十八頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

privatedelegatevoidcrossThreadDelegate(inti);//定義委托voidshowValue(inti){lblReport.Text="執(zhí)行到了第"+i+"步";}privatevoidthreadFun(){crossThreadDelegatecdt=newcrossThreadDelegate(showValue);for(inti=1;i<=5;i++){ //Invoke方法將當(dāng)前線程切換到UI線程,再執(zhí)行委托指向的函數(shù)

this.Invoke(cdt,i);//this指代當(dāng)前窗口

Thread.Sleep(1000);//延時(shí),便于看清中間執(zhí)行過(guò)程

}第十九頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

下面的程序在工作者線程的線程函數(shù)中直接使用lblReport.Text屬性,而沒(méi)有用Invoke方法:privatevoidthreadFun(){for(inti=1;i<=5;i++){lblReport.Text="執(zhí)行到了第"+i+"步";Thread.Sleep(1000);}}在運(yùn)行時(shí)會(huì)捕獲到圖2.4.2所示的異常:第二十頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

圖2.3.2后臺(tái)線程向UI線程傳遞數(shù)據(jù)第二十一頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

使用委托和Invoke方法會(huì)使代碼復(fù)雜度增加,在實(shí)際應(yīng)用中,可以用匿名委托來(lái)簡(jiǎn)化代碼:privatedelegatevoidcrossThreadDelegate();privatevoidthreadFun(){for(inti=1;i<=5;i++){crossThreadDelegatecdt=delegate//匿名委托(無(wú)函數(shù)名showValue)

{lblReport.Text="執(zhí)行到了第"+i+"步";};this.Invoke(cdt);//指向委托指向的函數(shù)

Thread.Sleep(1000);}}第二十二頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

2.3.4任務(wù)實(shí)施1在工作者線程中接收HSDZC電能綜合測(cè)試儀的數(shù)據(jù)(1)設(shè)計(jì)界面在轉(zhuǎn)機(jī)性能測(cè)試中需要讀取HSDZC電能綜合測(cè)試儀采集到的3個(gè)數(shù)值:輸入功率、輸出功率和功率因數(shù),以測(cè)試電機(jī)效率,此時(shí)測(cè)試儀的是選擇測(cè)量方式1。程序設(shè)計(jì)時(shí)的界面如圖2.3.3,用3個(gè)文本框分別顯示輸入功率、輸出功率和功率因數(shù),控件名稱分別為txtSrgl、txtScgl和txtGlys。該界面是整個(gè)鉆機(jī)性能測(cè)試系統(tǒng)主界面的一部份,為了便于觀察和調(diào)試,在界面的右邊以十六進(jìn)制形式顯示收到的數(shù)據(jù)幀,程序運(yùn)行時(shí)的界面如圖2.3.4所示。第二十三頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

圖2.3.3電機(jī)效率測(cè)試程序設(shè)計(jì)時(shí)界面第二十四頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

圖2.3.4電機(jī)效率測(cè)試程序運(yùn)行時(shí)界面第二十五頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

privatevoidbtnStart_Click(objectsender,EventArgse){//啟動(dòng)工作者線程

ThreadStartfunEntrance=newThreadStart(threadFun);Threadt=newThread(funEntrance);t.IsBackground=true;stop=false;t.Start();}(3)編寫在工作者線程中執(zhí)行的函數(shù)點(diǎn)擊“開始讀數(shù)”按鈕后時(shí),啟動(dòng)一個(gè)工作者線程,線程執(zhí)行函數(shù)threadFun中的內(nèi)容。threadFun在執(zhí)行時(shí)先打開串口,設(shè)置超時(shí)毫秒數(shù),并創(chuàng)建數(shù)據(jù)接收隊(duì)列recvBuf,然后就進(jìn)入while循環(huán)開始不斷地接收串口數(shù)據(jù)并進(jìn)行分析和顯示。while循環(huán)受到bool型變量stop的控制,可以通過(guò)設(shè)置該變量值為true,來(lái)結(jié)束線程中的循環(huán)。其中用到recvBuf對(duì)象和getBlock方法,它們的用法在前一節(jié)已經(jīng)進(jìn)行了詳細(xì)說(shuō)明。第二十六頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

privatevoidthreadFun(){SerialPortsp=newSerialPort("COM1",9600,Parity.None,8,StopBits.One);try{sp.Open();}catch(Exceptionex){MessageBox.Show("打開串口失?。?);return;}bytefirst;byte[]bRecv;//HSDZC在工作方式1時(shí),數(shù)據(jù)幀長(zhǎng)度為46字節(jié)第二十七頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

privatevoidthreadFun(){SerialPortsp=newSerialPort("COM1",9600,Parity.None,8,StopBits.One);try{sp.Open();}catch(Exceptionex){MessageBox.Show("打開串口失敗!");return;}bytefirst;byte[]bRecv;//HSDZC在工作方式1時(shí),數(shù)據(jù)幀長(zhǎng)度為46字節(jié)第二十八頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

(4)編寫顯示數(shù)據(jù)到控件的showData方法在線程函數(shù)中調(diào)用了showData方法顯示數(shù)據(jù),代碼如下:privatedelegatevoidcrossThreadDelegate();privatevoidshowData(byte[]b){floatv;//跨線程訪問(wèn)UI控件

crossThreadDelegatecdt=delegate//匿名委托

{if(b==null)//沒(méi)有接收到數(shù)據(jù)

{txtSrgl.Text="Error";txtScgl.Text="Error";txtGlys.Text="Error";}else{第二十九頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

//以十六進(jìn)制形式在txtData文本框中顯示數(shù)據(jù)幀的內(nèi)容

txtData.Text=CCheck.BinaryToHexString(b); //對(duì)浮點(diǎn)數(shù)進(jìn)行解碼(用HexToFloat函數(shù)),并分別顯示在3個(gè)文本框中

v=HexToFloat(b[4+9*3],b[4+9*3+1],b[4+9*3+2]);txtSrgl.Text=v.ToString("0.00");//輸入功率(第9個(gè)數(shù)值)v=HexToFloat(b[4+12*3],b[4+12*3+1],b[4+12*3+2]);txtScgl.Text=v.ToString("0.00");//輸出功率(第12個(gè)數(shù)值)

v=HexToFloat(b[4+6*3],b[4+6*3+1],b[4+6*3+2]);txtGlys.Text=v.ToString("0.00");//功率因數(shù)(第6個(gè)數(shù)值)

}};this.Invoke(cdt);}第三十頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

(5)編寫代碼處理“停止讀數(shù)”按鈕的點(diǎn)擊事件:privatevoidbtnStop_Click(objectsender,EventArgse){stop=true;//設(shè)置標(biāo)志,使線程中的循環(huán)自然結(jié)束}2HSDZC電能綜合測(cè)試儀數(shù)據(jù)接收和處理操作的封裝在前一個(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è)同類設(shè)備,很多代碼還要重寫,而且給查看和調(diào)試程序也帶來(lái)較大困難。下面用面向?qū)ο蠓椒▽?duì)程序進(jìn)行重新設(shè)計(jì)。第三十一頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

(1)創(chuàng)建抽象類CPassiveCOMHelperpublicclassCPassiveCOMHelper{publicintreadTimeOut,recvBufLength;//讀取超時(shí)毫秒數(shù),接收隊(duì)列大小

protectedCRecvBufrecvBuf;//接收隊(duì)列

privateboolstopFlag;//線程循環(huán)結(jié)束標(biāo)志

privatestringportName;//串口名稱

privateintbaudRate,dataBits;//波特率,數(shù)據(jù)位數(shù)

privateStopBitsstopBits;//停止位

privatebyte[]dataBlock;//一個(gè)完整的數(shù)據(jù)幀第三十二頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

publicdelegatevoidDataReceivedHandler();publiceventDataReceivedHandlerDataReceived;//數(shù)據(jù)接收完畢事件

//構(gòu)造方法

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

this.recvBufLength=100;//默認(rèn)接收隊(duì)列大小為100字節(jié)

}第三十三頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

publicvoidstart()//啟動(dòng)線程

{Threadt=newThread(newThreadStart(threadFun));t.IsBackground=true;stopFlag=false;t.Start();}publicvoidstop()//停止線程循環(huán),自然終止線程

{stopFlag=true;}protectedvirtualbyte[]getBlock(List<byte>li)//需要在派生類中重寫該方法第三十四頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

publicbyte[]getData(){byte[]tmp=null;Monitor.Enter(this);//線程同步:在進(jìn)行g(shù)et操作時(shí),不準(zhǔn)進(jìn)行set操作

if(dataBlock!=null){tmp=newbyte[dataBlock.Length];dataBlock.CopyTo(tmp,0);}Monitor.Exit(this);returntmp;}privatevoidsetData(byte[]tmp)第三十五頁(yè),共四十三頁(yè)。

Monitor.Enter(this);//線程同步:在進(jìn)行set操作時(shí),不準(zhǔn)進(jìn)行g(shù)et操作

dataBlock=tmp;Monitor.Exit(this);}privatevoidthreadFun(){recvBuf=newCRecvBuf(recvBufLength);SerialPortsp=newSerialPort(portName,baudRate,Parity.None,dataBits,stopBits);try{if(sp.IsOpen)sp.Close();sp.Open();}第三十六頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收catch{return;}bytefirst;byte[]bRecv;while(!stopFlag){try{sp.ReadTimeout=readTimeOut;first=(byte)sp.ReadByte();if(sp.BytesToRead+1>recvBuf.maxLength)//堆積數(shù)據(jù)太多

第三十七頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收(2)派生出具體類CHSDZC在CPassiveCOMHelper類中實(shí)現(xiàn)了串口打開、關(guān)閉、線程創(chuàng)建、數(shù)據(jù)接收等基礎(chǔ)操作,其中有一個(gè)虛方法getBlock,需要在派生類中根據(jù)具體情況實(shí)現(xiàn),下面實(shí)現(xiàn)專門采集HSDZC電能綜合測(cè)試儀數(shù)據(jù)的類CHSDZC:classCHSDZC:CPassiveCOMHelper{//構(gòu)造方法

publicCHSDZC(stringportName,intbaudRate,intdataBits,StopBitsstopBits):base(portName,baudRate,dataBits,stopBits){}//覆蓋基類的getBlock方法,專門針對(duì)HSDZC獲取數(shù)據(jù)第三十八頁(yè),共四十三頁(yè)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

protectedoverridebyte[]getBlock(List<byte>li){byte[]b=null;if(li.Count<46)returnb;//總長(zhǎng)度不足46字節(jié)

//查找最后一個(gè)完整的數(shù)據(jù)幀

intp=li.Count;//從右向左查找起始

溫馨提示

  • 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)論