方韜,黃建國(guó),戴志堅(jiān)
(電子科技大學(xué)自動(dòng)化工程學(xué)院 成都 611731)
示波表是在數(shù)字示波器技術(shù)的基礎(chǔ)上發(fā)展起來的一種新型便攜設(shè)備,覆蓋了臺(tái)式示波器的基本功能,可獨(dú)立完成對(duì)信號(hào)的捕獲、顯示、計(jì)算相關(guān)參數(shù)等功能,作用場(chǎng)合主要是現(xiàn)場(chǎng)檢測(cè)和維修使用。WinCE操作系統(tǒng)可擴(kuò)展性好,有現(xiàn)成的USB和網(wǎng)口的驅(qū)動(dòng)程序, 可以充分利用微軟開發(fā)環(huán)境EVC和基礎(chǔ)類庫(kù)MFC已有的模塊開發(fā)出友好的人機(jī)界面?;赪inCE平臺(tái)的數(shù)字存儲(chǔ)示波表,其強(qiáng)大的功能、良好的便攜性保證了其具有廣闊的市場(chǎng)前景。示波表選用了WinCE系統(tǒng)作為開發(fā)平臺(tái),EVC4.0作為開發(fā)工具。
WinCE是一個(gè)由微軟公司自行開發(fā)的32位、多線程、多任務(wù)的嵌入式操作系統(tǒng)。WinCE繼承了Windows95、98的圖形界面。對(duì)于熟悉Windows操作的廣大用戶來說,WinCE易于學(xué)習(xí)和使用。WinCE具有結(jié)構(gòu)化和模塊化的特點(diǎn),它提供的應(yīng)用程序編程接口API(Application Programming Interface)函數(shù)與Windows XP下的API接口一致,是Windows XP下API的一個(gè)子集。在WinCE下開發(fā)的應(yīng)用程序可以方便地移植到WindowsXP操作系統(tǒng)。
EVC是Windows CE下的軟件開發(fā)工具,其編程支持WinCE下的API函數(shù),支持微軟基礎(chǔ)類庫(kù)MFC。這些類庫(kù)提供的函數(shù)和PC平臺(tái)下的函數(shù)具有相同的接口。示波表工程中采用EVC4.0作為開發(fā)工具。
Windows編程本質(zhì)是對(duì)各種消息進(jìn)行響應(yīng),對(duì)圖形進(jìn)行繪制也是如此。在程序代碼中,一般將繪制圖形的代碼放在OnPaint或OnDraw函數(shù)中,當(dāng)系統(tǒng)產(chǎn)生WM_PAINT消息時(shí),上述函數(shù)會(huì)自動(dòng)進(jìn)行消息響應(yīng),從而實(shí)現(xiàn)圖形的繪制。在圖形很少改變或者程序窗口很少刷新時(shí),這樣的處理方法沒有任何問題,但是如果程序窗體的內(nèi)容經(jīng)常刷新,圖形就會(huì)出現(xiàn)閃爍。很多人認(rèn)為出現(xiàn)這樣的現(xiàn)象是圖形刷新速度過快而造成的,實(shí)際上,在程序中,比如最小化最大化、移動(dòng)窗體、覆蓋等等都會(huì)引起圖形的重繪。然而通過實(shí)驗(yàn),我們可以發(fā)現(xiàn),刷新速度并不是造成圖形閃爍的最根本的原因。通過編寫一個(gè)刷新速度很慢的應(yīng)用程序可以發(fā)現(xiàn),即使程序窗口的刷新速度很慢,但是在每次刷新的時(shí)候仍然存在閃爍的問題,只是閃爍沒有快速刷新時(shí)那么明顯。在本質(zhì)上,造成圖形閃爍的原因?qū)嶋H上是相鄰兩幀圖像之間存在的巨大差異。而造成這一差異的原因又在于EVC本身的處理機(jī)制。在EVC中,窗體每次刷新時(shí),將自動(dòng)調(diào)用OnEraseBkgnd函數(shù),該函數(shù)的作用是利用系統(tǒng)背景色填充窗體繪圖區(qū),在填充完了之后,系統(tǒng)才會(huì)重新調(diào)用繪圖代碼對(duì)窗口進(jìn)行重繪。在默認(rèn)情況下,系統(tǒng)背景色一般為白色,因此每次重繪時(shí),相當(dāng)于在相鄰兩幀圖像間插入了一幀全白的圖像。而白色一般與繪圖顏色差別很大,因此,這樣一擦一寫造成了圖象顏色的巨大反差。當(dāng)WM_PAINT的響應(yīng)很頻繁的時(shí)候,這種反差也就越發(fā)明顯。于是就看到了閃爍現(xiàn)象。要解決這一問題,首先直接能想到的方法就是禁用OnEraseBkgnd函數(shù),避免系統(tǒng)對(duì)窗口進(jìn)行白色填充。但是這樣的處理方法又會(huì)帶來新的問題,因?yàn)槊看卫L制圖像的時(shí)候都沒有將原來的圖像清除,造成了圖像的殘留,于是窗體重繪時(shí),如果沒有重繪所有的區(qū)域,畫面往往會(huì)變得混亂。所以單純的禁止背景重繪是不夠的,還必須重新對(duì)窗體的所有區(qū)域進(jìn)行重繪。由于要對(duì)所有區(qū)域進(jìn)行重繪,傳統(tǒng)的方法可能就不夠迅速。
雙緩沖圖形刷新技術(shù)顧名思義是采用雙緩存實(shí)現(xiàn)的。傳統(tǒng)的繪圖方式實(shí)際上是一種單緩沖。在Windows中每一種設(shè)備都在內(nèi)存中有一個(gè)設(shè)備描述表與其對(duì)應(yīng),這個(gè)設(shè)備描述表實(shí)際上就是一個(gè)內(nèi)存緩沖區(qū)。傳統(tǒng)的繪圖中我們是將圖形繪制在設(shè)備描述表緩沖區(qū)中,然后由GDI自動(dòng)地將設(shè)備描述表中的圖像拷貝到顯存中進(jìn)行顯示。這樣一個(gè)自動(dòng)的拷貝過程屏蔽了傳統(tǒng)的繪圖方式是單緩沖的實(shí)質(zhì),使我們感覺到是在直接操縱顯存一樣。雙緩沖圖形刷新技術(shù)在內(nèi)存中有兩塊緩存,除了設(shè)備描述表以外還有一塊需要手動(dòng)建立的與設(shè)備描述表緩沖區(qū)相兼容的后備緩沖區(qū)。繪圖過程中,首先將圖形繪制在后備緩沖區(qū)中,然后再手動(dòng)地將后備緩沖區(qū)中的圖像拷貝到前端緩沖區(qū)中,再由GDI自動(dòng)將前端緩沖區(qū)中的圖像拷貝到顯存完成圖形的顯示過程。在實(shí)際中,我們使用BitBlt函數(shù)。它可以支持圖形塊的復(fù)制,速度很快。我們可以先在內(nèi)存中作圖,然后用此函數(shù)將做好的圖復(fù)制到前臺(tái),同時(shí)禁止背景刷新,這樣就消除了閃爍。以上也就是雙緩沖繪圖的基本的思路。在EVC中,可以按照以下步驟來使用雙緩沖技術(shù)進(jìn)行圖形的繪制:
(a)創(chuàng)建與窗口設(shè)備描述表(前端緩沖區(qū))兼容的內(nèi)存設(shè)備描述表(后端緩沖區(qū))。
(b)創(chuàng)建與內(nèi)存設(shè)備描述表相兼容的位圖并將該位圖選入內(nèi)存設(shè)備描述表中。
(c)將圖形繪制在內(nèi)存設(shè)備描述表中。
(d)將內(nèi)存設(shè)備描述表中的內(nèi)容拷貝到窗口設(shè)備描述表。
(e)釋放設(shè)備描述表句柄、位圖等資源。
示波表作為一種便攜式的示波器,需要實(shí)現(xiàn)示波器的全部功能,對(duì)波形的刷新率要求較高?;赪inCE的示波表軟件,其畫面的顯示原理同Windows下的繪圖。
示波表中,考慮到提高畫圖的效率,創(chuàng)建了兩個(gè)內(nèi)存兼容DC,將固定的背景(顯示波形的網(wǎng)格以及顯示測(cè)量結(jié)果的分隔線)專門放在一個(gè)命名m_bitmapBack的位圖中,當(dāng)需要重新繪制波形時(shí),只需將該位圖貼到畫波形的位圖m_bitmapWave上即可,這樣大大節(jié)約了調(diào)用MoveTo、LineTo等API函數(shù)所消耗的時(shí)間。
在本工程中,波形刷新顯示時(shí)的畫圖專門在畫圖線程中實(shí)現(xiàn),雙緩沖技術(shù)在工程中的應(yīng)用如下:
(1) 在使能畫圖線程前先進(jìn)行內(nèi)存DC的初始化工作:
①創(chuàng)建兼容的內(nèi)存DC。工程中創(chuàng)建了兩個(gè)內(nèi)存DC,m_dcBack用來保存固定的背景,m_dcWave用來繪制波形數(shù)據(jù)。
CClientDC clientDC(this);
m_dcBack.CreateCompatibleDC(&clientDC);
m_dcWave.CreateCompatibleDC(&clientDC);
② 創(chuàng)建與內(nèi)存DC兼容的位圖,并選入內(nèi)存DC中。
GetClientRect(&rect);
m_rectBack.SetRect(rect.left,rect.top, rect.right, rect.bottom);
m_bitmapBack.CreateCompatibleBitmap(&clientDC,m_rectBack.Width(),m_rectBack.Height());
m_bitmapWave.CreateCompatibleBitmap(&clientDC,m_rectBack.Width(), m_rectBack.Height());
m_dcBack.SelectObject(&m_ bitmapBack);
m_dcWave.SelectObject(&m_ bitmapWave);
(2) 在畫圖線程中實(shí)現(xiàn)波形的刷新顯示,流程圖如圖1所示。
圖1 畫圖線程流程圖
畫圖線程中,先等待線程事件,若事件為真(待采集到波形數(shù)據(jù)并轉(zhuǎn)換為屏幕上的像素點(diǎn)坐標(biāo)時(shí),將畫圖線程事件置真),則進(jìn)行波形的繪制。波形的繪制分為兩個(gè)步驟:
① 將已經(jīng)繪制好背景的背景DC貼到波形DC上,該部分實(shí)現(xiàn)每次刷新波形時(shí)都將上次的波形清除:
m_dcWave->BitBlt(22,32,500,400,
&m_ dcBack, 22, 32, SRCCOPY);
② 在畫圖DC上,根據(jù)得到的波形數(shù)據(jù)繪制波形。上層應(yīng)用程序調(diào)用底層驅(qū)動(dòng)獲得波形數(shù)據(jù),將數(shù)據(jù)轉(zhuǎn)換成屏幕坐標(biāo)后,將坐標(biāo)畫到畫圖DC上。
DrawWave(&m_ bitmapWave);
在DrawWave函數(shù)中使用PolyLine函數(shù),將波形數(shù)據(jù)繪制到畫圖DC上。
③將繪制好波形的畫圖DC貼到設(shè)備DC上,實(shí)現(xiàn)波形的刷新。
在②中完成了畫圖DC的繪制,之后調(diào)用Invalidate()函數(shù),給窗口發(fā)送WM_PAINT消息,在消息處理函數(shù)OnPaint中,將畫圖DC貼到設(shè)備DC上面。實(shí)現(xiàn)如下:
void COscCtrl::OnPaint()
{
EnterCriticalSection(&m_csBitmapWave);
CPaintDC dc(this);
dc.BitBlt(0,0,m_rectBack.Width(), m_rectBack.Height(), &m_dcWave, 0, 0, SRCCOPY);
LeaveCriticalSection(&m_csBitmapWave);
}
在軟件中加入雙緩沖技術(shù)繪圖后,波形刷新時(shí)示波表界面不會(huì)出現(xiàn)混亂,也不會(huì)出現(xiàn)閃屏的現(xiàn)象,同時(shí)也提高了波形刷新的速率,很好地實(shí)現(xiàn)了示波表功能所要求的顯示效果。示波表界面顯示如圖2所示。
圖2 示波表界面顯示
在WinCE系統(tǒng)中使用EVC進(jìn)行界面編程可以方便地運(yùn)用Windows編程技術(shù),在實(shí)際應(yīng)用中,為了實(shí)現(xiàn)對(duì)界面快速刷新的要求時(shí),使用雙緩沖技術(shù)可以很好地解決這一問題。在基于WinCE平臺(tái)的示波表軟件中,由于對(duì)波形的刷新率要求較高,使用雙緩沖技術(shù)來實(shí)現(xiàn)波形的刷新,很好地達(dá)到了功能的要求。
[1]JeffreyRichter,Christophe Nasarre.Windows核心編程[M].葛子昂,譯.北京:清華大學(xué)出版社,2008.
[2]侯捷.深入淺出MFC[M].武漢:華中科技大學(xué)出版社,2001.
[3]譚鋒.在基于MFC的VC程序中縮放顯示位圖[J].內(nèi)江科技,2007:32-36.
[4]周民揚(yáng).Visual C++ 界面編程技術(shù)[M].北京:北京希望電子出版社,2003.
[5]楊樂.測(cè)試儀器中的動(dòng)態(tài)波形繪制[J].儀器儀表學(xué)報(bào),2006:26-27.
[6]孫鑫,余安萍.VC++深入詳解[M].北京:電子工業(yè)出版社,2006.
[7]夏萍,潘宏俠,王芳.基于VC的BMP位圖伸縮顯示[J].電子測(cè)試,2009(12):27-29.
[8]高偉衛(wèi),楊勝?gòu)?qiáng),張滿棟.基于VC++6.0基礎(chǔ)類庫(kù)的圖像顯示[J].現(xiàn)代電子技術(shù),2002(1):36-40.