單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收_第1頁
單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收_第2頁
單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收_第3頁
單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收_第4頁
單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收_第5頁
已閱讀5頁,還剩39頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

工控程序設(shè)計(jì)學(xué)習(xí)情景2串口設(shè)備的數(shù)據(jù)采集學(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)行的,為了滿足該需求,必須采用多線程模式來進(jìn)行程序設(shè)計(jì)。

2.該教學(xué)情景通過“在工作者線程中接收HSDZC電能綜合測(cè)試儀的”“HSDZC電能綜合測(cè)試儀數(shù)據(jù)接收和處理操作的封裝”這兩個(gè)實(shí)施步驟達(dá)到連續(xù)接收接收單個(gè)串口設(shè)備(下位機(jī))數(shù)據(jù)的目的。學(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í)行過程。線程是被系統(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)資源,所以線程間的切換比較容易,通信也比較方便。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備數(shù)據(jù)的連續(xù)接收

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

定義委托的關(guān)鍵字是delegate,它是從System.Delegate類派生出來的。例如: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)起來,線程啟動(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è)方法的入口

,學(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í)行了。學(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ù):學(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ì)象學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收4線程同步技術(shù)術(shù)多線程應(yīng)用程程序中的的線線程啟動(dòng)后,,執(zhí)行的先后后順序是無法法預(yù)知的,通通常情況下多多個(gè)線程會(huì)交交錯(cuò)執(zhí)行。但但是在多個(gè)線線程訪問共享享數(shù)據(jù)的情況況下,必須對(duì)對(duì)數(shù)據(jù)的訪問問進(jìn)行同步。。好比有兩路路車,一路自自東向西,一一路自南向北北運(yùn)行,在一一個(gè)十字路口口交匯。在十十字路口以外外的區(qū)域可以以看著私有區(qū)區(qū)域,而十字字路口則是共共有區(qū)域,需需要紅綠燈或或交警來維護(hù)護(hù)秩序,即確確保在同一時(shí)時(shí)刻只能有一一路車進(jìn)入,,而另外一路路車必須等待待,這就是現(xiàn)現(xiàn)實(shí)生活中的的線程同步問問題。學(xué)習(xí)情情景2.下面的的例子子展示示了一一個(gè)讀讀數(shù)據(jù)據(jù)線程程和一一個(gè)寫寫數(shù)據(jù)據(jù)線程程同時(shí)時(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)學(xué)習(xí)情情景2.3單個(gè)串串口設(shè)設(shè)備數(shù)數(shù)據(jù)的的連續(xù)續(xù)接收收{(diào)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或1a[i]=flag;flag=flag==0?1:0;}}學(xué)習(xí)情情景2.3單個(gè)串串口設(shè)設(shè)備數(shù)數(shù)據(jù)的的連續(xù)續(xù)接收收下面采采用Monitor類來進(jìn)進(jìn)行線線程同同步,,使數(shù)數(shù)據(jù)讀讀、寫寫操作作稱為為原子子操作作。即即達(dá)到到這樣樣的目目的::在線線程2寫數(shù)據(jù)據(jù)時(shí),,線程程1等待,,在線線程1讀數(shù)據(jù)據(jù)時(shí),,線程程2等待,,使每每次輸輸出的的結(jié)果果全部部為0或全部部為1。當(dāng)調(diào)用用Monitor類的Enter(Objectobj)方法時(shí)時(shí),會(huì)獲取取對(duì)象象obj的獨(dú)占占權(quán),直到調(diào)調(diào)用Exit(Objectobj)方法時(shí)時(shí),才會(huì)釋釋放對(duì)對(duì)obj的獨(dú)占占權(quán)。。注意意調(diào)用用Enter方法的的次數(shù)數(shù)要和和,調(diào)用Exit方法的的次數(shù)數(shù)相等等。Monitor類還提提供了了TryEnter方法,該方法法嘗試試獲取取obj對(duì)象的的獨(dú)占占權(quán),當(dāng)獲取取獨(dú)占占權(quán)失失敗時(shí)時(shí),將返回回false。實(shí)現(xiàn)現(xiàn)代碼碼如下下:學(xué)習(xí)情情景2.3單個(gè)串串口設(shè)設(shè)備數(shù)數(shù)據(jù)的的連續(xù)續(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();學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(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)入}}學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收5工作者線程向向用戶界面線線程傳遞數(shù)據(jù)據(jù)用戶界面線程程簡稱UI線程,其主要要特點(diǎn)是能響響應(yīng)Windows消息,主要負(fù)負(fù)責(zé)接收用戶戶輸入和向用用戶展示程序序執(zhí)行結(jié)果。。為了及時(shí)響響應(yīng)用戶的輸輸入,UI線程中不應(yīng)執(zhí)執(zhí)行費(fèi)時(shí)的運(yùn)運(yùn)算,更不能能被阻塞。工作者線程一一般用于在后后臺(tái)進(jìn)行費(fèi)時(shí)時(shí)運(yùn)算或和慢慢速設(shè)備打交交道,這種線線程不響應(yīng)Windows消息。在通信信程序中,數(shù)數(shù)據(jù)的發(fā)送和和接收耗費(fèi)的的時(shí)間不確定定。為了在通通信過程中能能夠響應(yīng)用戶戶輸入,通常常在建立一個(gè)個(gè)或多個(gè)工作作者線程,在在后臺(tái)完成通通信任務(wù)。工作者線程向向運(yùn)行在UI線程中的用戶戶控件傳遞數(shù)數(shù)據(jù)時(shí),不能能直接對(duì)對(duì)控控件的屬性和和方法進(jìn)行調(diào)調(diào)用,而要先先定義一個(gè)委委托,再用控控件的Invoke方法,切換到到UI線程去執(zhí)行委委托所指向的的函數(shù),來更更新控件顯示示的內(nèi)容。在下面的程序序中,工作線線程每循環(huán)完完一次,就更更新UI線程中的控件件屬性,向用用戶報(bào)告當(dāng)前前步驟。程序序界面和后臺(tái)臺(tái)代碼如下::學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收?qǐng)D2.3.1工作者線程向向UI線程傳遞數(shù)據(jù)據(jù)privatevoidbtnRun_Click(objectsender,EventArgse){ThreadStartfunEntrance=newThreadStart(threadFun);Threadt=newThread(funEntrance);t.IsBackground=true;t.Start();}學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(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í)行行過程}學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收下面的程序在在工作者線程程的線程函數(shù)數(shù)中直接使用用lblReport.Text屬性,而沒有有用Invoke方法:privatevoidthreadFun(){for(inti=1;i<=5;i++){lblReport.Text="執(zhí)行到了第"+i+"步";Thread.Sleep(1000);}}在運(yùn)行時(shí)會(huì)捕捕獲到圖2.4.2所示的異常::學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收?qǐng)D2.3.2后臺(tái)線程向UI線程傳遞數(shù)據(jù)據(jù)學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收使用委托和Invoke方法會(huì)使代碼碼復(fù)雜度增加加,在實(shí)際應(yīng)應(yīng)用中,可以以用匿名委托托來簡化代碼碼:privatedelegatevoidcrossThreadDelegate();privatevoidthreadFun(){for(inti=1;i<=5;i++){crossThreadDelegatecdt=delegate//匿名委托(無無函數(shù)名showValue){lblReport.Text="執(zhí)行到了第"+i+"步";};this.Invoke(cdt);//指向委托指向向的函數(shù)Thread.Sleep(1000);}}學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收2.3.4任務(wù)實(shí)施1在工作者線程程中接收HSDZC電能綜合測(cè)試試儀的數(shù)據(jù)(1)設(shè)計(jì)界面在轉(zhuǎn)機(jī)性能測(cè)測(cè)試中需要讀讀取HSDZC電能綜合測(cè)試試儀采集到的的3個(gè)數(shù)值:輸入入功率、輸出出功率和功率率因數(shù),以測(cè)試電機(jī)效效率,此時(shí)測(cè)測(cè)試儀的是選選擇測(cè)量方式式1。程序設(shè)計(jì)時(shí)時(shí)的界面如圖圖2.3.3,用3個(gè)文本框分別別顯示輸入功功率、輸出功功率和功率因因數(shù),控件名名稱分別為txtSrgl、txtScgl和txtGlys。該界面是整整個(gè)鉆機(jī)性性能測(cè)試系系統(tǒng)主界面面的一部份份,為了便便于觀察和和調(diào)試,在在界面的右右邊以十六六進(jìn)制形式式顯示收到到的數(shù)據(jù)幀幀,程序運(yùn)運(yùn)行時(shí)的界界面如圖2.3.4所示。學(xué)習(xí)情景2.3單個(gè)串口設(shè)設(shè)備數(shù)據(jù)的的連續(xù)接收收?qǐng)D2.3.3電機(jī)效率測(cè)測(cè)試程序設(shè)設(shè)計(jì)時(shí)界面面學(xué)習(xí)情景2.3單個(gè)串口設(shè)設(shè)備數(shù)據(jù)的的連續(xù)接收收?qǐng)D2.3.4電機(jī)效率測(cè)測(cè)試程序運(yùn)運(yùn)行時(shí)界面面學(xué)習(xí)情景2.3單個(gè)串口設(shè)設(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è)個(gè)工作者線線程,線程程執(zhí)行函數(shù)數(shù)threadFun中的內(nèi)容。。threadFun在執(zhí)行時(shí)先先打開串口口,設(shè)置超超時(shí)毫秒數(shù)數(shù),并創(chuàng)建建數(shù)據(jù)接收收隊(duì)列recvBuf,然后就進(jìn)進(jìn)入while循環(huán)開始不不斷地接收收串口數(shù)據(jù)據(jù)并進(jìn)行分分析和顯示示。while循環(huán)受到bool型變量stop的控制,可可以通過設(shè)設(shè)置該變量量值為true,來結(jié)束線線程中的循循環(huán)。其中中用到recvBuf對(duì)象和getBlock方法,它們們的用法在在前一節(jié)已已經(jīng)進(jìn)行了了詳細(xì)說明明。學(xué)習(xí)情景2.3單個(gè)串口設(shè)設(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ù)幀幀長度為46字節(jié)學(xué)習(xí)情景2.3單個(gè)串口設(shè)設(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ù)數(shù)據(jù)據(jù)幀幀長長度度為為46字節(jié)節(jié)學(xué)習(xí)習(xí)情情景景2.3單個(gè)個(gè)串串口口設(shè)設(shè)備備數(shù)數(shù)據(jù)據(jù)的的連連續(xù)續(xù)接接收收(4)編編寫寫顯顯示示數(shù)數(shù)據(jù)據(jù)到到控控件件的的showData方法法在線線程程函函數(shù)數(shù)中中調(diào)調(diào)用用了了showData方法法顯顯示示數(shù)數(shù)據(jù)據(jù),,代代碼碼如如下下::privatedelegatevoidcrossThreadDelegate();privatevoidshowData(byte[]b){floatv;//跨線線程程訪訪問問UI控件件crossThreadDelegatecdt=delegate//匿名名委委托托{if(b==null)//沒有有接接收收到到數(shù)數(shù)據(jù)據(jù){txtSrgl.Text="Error";txtScgl.Text="Error";txtGlys.Text="Error";}else{學(xué)習(xí)習(xí)情情景景2.3單個(gè)個(gè)串串口口設(shè)設(shè)備備數(shù)數(shù)據(jù)據(jù)的的連連續(xù)續(xù)接接收收//以十十六六進(jìn)進(jìn)制制形形式式在在txtData文本框中顯示示數(shù)據(jù)幀的內(nèi)內(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);}學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(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)現(xiàn)了串口數(shù)據(jù)據(jù)接收、解析析和顯示的功功能,并且在在工作者線程程中接收和處處理數(shù)據(jù),在在此期間前臺(tái)臺(tái)的UI線程能響應(yīng)用用戶輸入。從從功能上看,,已經(jīng)能夠滿滿足用戶需求求,但是從代代碼的組織和和管理角度看看,該程序還還有比較大問問題:負(fù)責(zé)接接收和處理數(shù)數(shù)據(jù)的代碼和和負(fù)責(zé)顯示的的代碼混雜在在一起,不能能重復(fù)使用,,若增加一個(gè)個(gè)同類設(shè)備,,很多代碼還還要重寫,而而且給查看和和調(diào)試程序也也帶來較大困困難。下面用用面向?qū)ο蠓椒椒▽?duì)程序進(jìn)進(jìn)行重新設(shè)計(jì)計(jì)。學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(xù)接收(1)創(chuàng)建抽象類類CPassiveCOMHelperpublicclassCPassiveCOMHelper{publicintreadTimeOut,recvBufLength;//讀取超時(shí)毫秒秒數(shù),接收隊(duì)隊(duì)列大小protectedCRecvBufrecvBuf;//接收隊(duì)列privateboolstopFlag;//線程循環(huán)結(jié)束束標(biāo)志privatestringportName;//串口名稱privateintbaudRate,dataBits;//波特率,數(shù)據(jù)據(jù)位數(shù)privateStopBitsstopBits;//停止位privatebyte[]dataBlock;//一個(gè)完整的數(shù)數(shù)據(jù)幀學(xué)習(xí)情景2.3單個(gè)串口設(shè)備備數(shù)據(jù)的連續(xù)續(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)認(rèn)500毫秒秒讀讀取取超超時(shí)時(shí)this.recvBufLength=100;//默認(rèn)認(rèn)接接收收隊(duì)隊(duì)列列大大小小為為100字節(jié)節(jié)}學(xué)習(xí)習(xí)情情景景2.3單個(gè)個(gè)串串口口設(shè)設(shè)備備數(shù)數(shù)據(jù)據(jù)的的連連續(xù)續(xù)接接收收publicvoidstart()//啟動(dòng)動(dòng)線線程程{Threadt=newThread(newThreadStart(threadFun));t.IsBackground=true;stopFlag=false;t.Start();}publicvoidstop()//停止止線線程程循循環(huán)環(huán),,自自然然終終止止線線程程{stopFlag=true;}protectedvirtualbyte[]getBlock(List<byte>li)//需要要在在派派生生類類中中重重寫寫該該方方法法學(xué)習(xí)習(xí)情情景景2.3單個(gè)個(gè)串串口口設(shè)設(shè)備備數(shù)數(shù)據(jù)據(jù)的的連連續(xù)續(xù)接接收收publicbyte[]getData(){byte[]tmp=null;Monitor.Enter(this);//線程程同同步步::在在進(jìn)進(jìn)行行g(shù)et操作作時(shí)時(shí),,不不準(zhǔn)準(zhǔn)進(jìn)進(jìn)行行set操作作if(dataBlock!=null){tmp=newbyte[dataBlock.Length];dataBlock.CopyTo(tmp,0);}Monitor.Exit(this);returntmp;}privatevoidsetData(byte[]tmp)Monitor.Enter(this);//線程程同同步步::在在進(jìn)進(jìn)行行set操作作時(shí)時(shí),,不不準(zhǔn)準(zhǔn)進(jì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();}學(xué)習(xí)習(xí)情情景景2.3單個(gè)個(gè)串串口口設(shè)設(shè)備備數(shù)數(shù)據(jù)據(jù)的的連連續(xù)續(xù)接接收收catch{return;}bytefirst;byte[]bRecv;while(!stopFlag){try{sp.ReadTimeout=readTimeOut;first=(byte)sp.ReadByte();if(sp.BytesToRead+1>recvBuf.maxLength)//堆積數(shù)據(jù)據(jù)太多學(xué)習(xí)情景景2.3單個(gè)串口口設(shè)備數(shù)數(shù)據(jù)的連連續(xù)接收收(2)派生出出具體類類CHSDZC在CPassiveCOMHelper類中實(shí)現(xiàn)現(xiàn)了串口口打開、、關(guān)閉、、線程創(chuàng)創(chuàng)建、數(shù)數(shù)據(jù)接收收等基礎(chǔ)礎(chǔ)操作,,其中有有一個(gè)虛虛方法getBlock,需要在在派生類類中根據(jù)據(jù)具體情情況實(shí)現(xiàn)現(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ì)對(duì)HSDZC獲取數(shù)據(jù)據(jù)學(xué)習(xí)情景景2.3單個(gè)串口口設(shè)備數(shù)數(shù)據(jù)的連連續(xù)接收收protectedoverridebyte[]getBlock(List<byte>li){byte[]b=null;if(li.Count<46)returnb;//總長度不不足46字節(jié)//查找最后后一個(gè)完完整的數(shù)數(shù)據(jù)幀intp=li.Count;//從右向左左查找起起始標(biāo)志志“FFFFFFFFH””,獲取下下標(biāo)while((p=li.LastIndexOf(0xFF,p-1))!=-1)if(li.Count>=p+46)if(li[p+1]==0xFF&&li[p+2]==0xFF&&li[p+3]==0xFF)break;//已經(jīng)找到到,接收收循環(huán)if(p!=-1)//p為數(shù)據(jù)幀幀的起始始位置{學(xué)習(xí)情景景2.3單個(gè)串口口設(shè)備數(shù)數(shù)據(jù)的連連續(xù)接收收b=newbyte[46];li.CopyTo(p,b,0,46);//拷貝數(shù)據(jù)據(jù)幀到b數(shù)組}returnb;//返回找到到的完整整數(shù)據(jù)幀幀}(3)在UI模塊中使使用CHSDZC類實(shí)現(xiàn)數(shù)數(shù)據(jù)采集集在前面所所作工作作的基礎(chǔ)礎(chǔ)上編寫寫UI模塊就非非常輕松松了。在在UI模塊中不不用關(guān)心心串口通通信、線線程操作作等復(fù)雜雜問題,,只需要要?jiǎng)?chuàng)建CHSDZC對(duì)象并啟啟動(dòng)它即即可,當(dāng)當(dāng)有完整整的數(shù)據(jù)據(jù)幀收到到時(shí),會(huì)會(huì)引發(fā)DataReceived事件,并并自動(dòng)調(diào)調(diào)用hsdzc_DataReceived方法處理理數(shù)據(jù)。。不過這這里需要要注意的的是,hsdzc_DataReceived是個(gè)回調(diào)調(diào)函數(shù),,雖然包包含在Form6類中,但但是在工工作者線線程中進(jìn)進(jìn)行調(diào)用用,需要要跨線程程操作UI線程中的的文本框框等控件件,因此此把操作作控件的的代碼封封裝到一一個(gè)匿名名委托中中,并用用this.Invoke進(jìn)行調(diào)用用。學(xué)習(xí)情景景2.3單個(gè)串口口設(shè)備數(shù)數(shù)據(jù)的連連續(xù)接收收2.3.5考核要點(diǎn)點(diǎn)學(xué)習(xí)情景景2.3單個(gè)串口口設(shè)備數(shù)數(shù)據(jù)的連連續(xù)接收收2.3.6能力拓展展1.什么是委委托,委委托在什什么場(chǎng)合合使用,,如何使使用委托托?2.在什么情情況下需需要使用用多線程程技術(shù),,使用Thread類要引入入什么命命名空間間,如何何創(chuàng)建和和啟動(dòng)線線程?3.如何將工工作者線線程中的的數(shù)據(jù)顯顯示在UI線程的控控件中??4.安照說明明書里規(guī)規(guī)定的數(shù)數(shù)據(jù)格式式,設(shè)計(jì)計(jì)一個(gè)HSDZC電能綜合合測(cè)試儀儀的模擬擬程序((包含兩兩種測(cè)量量方式))。5.在圖2.3.3的窗體上上增加一一個(gè)Timer控件,并并結(jié)合1.1.4小節(jié)的任任務(wù)二,,將采集集到的輸輸入功率率、輸出出功率、、功率因因數(shù)值存存儲(chǔ)到Params集合中((不立即即顯示在在文本框框中),,每隔1秒鐘用用Params集合中中的值值刷新新文本本框的的內(nèi)容容9、靜夜四無鄰鄰,荒居舊業(yè)業(yè)貧。。12月-2212月-22Wednesday,December7,202210、雨中黃葉葉樹,燈下下白頭人。。。21:29:2821:29:2821:2912/7/20229:29:28PM11、以我獨(dú)獨(dú)沈久,,愧君相相見頻。。。12月-2221:29:2821:29Dec-2207-Dec-2212、故人人江海海別,,幾度度隔山山川。。。21:29:2821:29:2821:29Wednesday,December7,202213、乍見翻疑疑夢(mèng),相悲悲各問年。。。12月-2212月-2221:29:2821:29:28December7,202214、他鄉(xiāng)生白發(fā)發(fā),舊國見青青山。。07十二月月20229:29:28下午21:29:2812月-2215、比不不了得得就不不比,,得不不到的的就不不要。。。。十二月月229:29下下午午12月月-2221:29December7,202216、行行動(dòng)動(dòng)出出成成果果,,工工作作出出財(cái)財(cái)富富。。。。2022/12/721:29:2821:29:2807December202217、做做前前,,能能夠夠環(huán)環(huán)視視四四周周;;做做時(shí)時(shí),,你你只只能能或或者者最最好好沿沿著著以以腳腳為為起起點(diǎn)點(diǎn)的的射射線線向向前前。。。。9:29:28下下午午9:29下下午午21:29:2812月月-229、沒有失敗敗,只有暫暫時(shí)停止成成功!。12月-2212月-22Wednesday,December7,202210、很多事情情努力了未未必有結(jié)果果,但是不不努力卻什什么改變

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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)論