方韜,黃建國,戴志堅
(電子科技大學自動化工程學院 成都 611731)
示波表是在數字示波器技術的基礎上發展起來的一種新型便攜設備,覆蓋了臺式示波器的基本功能,可獨立完成對信號的捕獲、顯示、計算相關參數等功能,作用場合主要是現場檢測和維修使用。WinCE操作系統可擴展性好,有現成的USB和網口的驅動程序, 可以充分利用微軟開發環境EVC和基礎類庫MFC已有的模塊開發出友好的人機界面。基于WinCE平臺的數字存儲示波表,其強大的功能、良好的便攜性保證了其具有廣闊的市場前景。示波表選用了WinCE系統作為開發平臺,EVC4.0作為開發工具。
WinCE是一個由微軟公司自行開發的32位、多線程、多任務的嵌入式操作系統。WinCE繼承了Windows95、98的圖形界面。對于熟悉Windows操作的廣大用戶來說,WinCE易于學習和使用。WinCE具有結構化和模塊化的特點,它提供的應用程序編程接口API(Application Programming Interface)函數與Windows XP下的API接口一致,是Windows XP下API的一個子集。在WinCE下開發的應用程序可以方便地移植到WindowsXP操作系統。
EVC是Windows CE下的軟件開發工具,其編程支持WinCE下的API函數,支持微軟基礎類庫MFC。這些類庫提供的函數和PC平臺下的函數具有相同的接口。示波表工程中采用EVC4.0作為開發工具。
Windows編程本質是對各種消息進行響應,對圖形進行繪制也是如此。在程序代碼中,一般將繪制圖形的代碼放在OnPaint或OnDraw函數中,當系統產生WM_PAINT消息時,上述函數會自動進行消息響應,從而實現圖形的繪制。在圖形很少改變或者程序窗口很少刷新時,這樣的處理方法沒有任何問題,但是如果程序窗體的內容經常刷新,圖形就會出現閃爍。很多人認為出現這樣的現象是圖形刷新速度過快而造成的,實際上,在程序中,比如最小化最大化、移動窗體、覆蓋等等都會引起圖形的重繪。然而通過實驗,我們可以發現,刷新速度并不是造成圖形閃爍的最根本的原因。通過編寫一個刷新速度很慢的應用程序可以發現,即使程序窗口的刷新速度很慢,但是在每次刷新的時候仍然存在閃爍的問題,只是閃爍沒有快速刷新時那么明顯。在本質上,造成圖形閃爍的原因實際上是相鄰兩幀圖像之間存在的巨大差異。而造成這一差異的原因又在于EVC本身的處理機制。在EVC中,窗體每次刷新時,將自動調用OnEraseBkgnd函數,該函數的作用是利用系統背景色填充窗體繪圖區,在填充完了之后,系統才會重新調用繪圖代碼對窗口進行重繪。在默認情況下,系統背景色一般為白色,因此每次重繪時,相當于在相鄰兩幀圖像間插入了一幀全白的圖像。而白色一般與繪圖顏色差別很大,因此,這樣一擦一寫造成了圖象顏色的巨大反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。于是就看到了閃爍現象。要解決這一問題,首先直接能想到的方法就是禁用OnEraseBkgnd函數,避免系統對窗口進行白色填充。但是這樣的處理方法又會帶來新的問題,因為每次繪制圖像的時候都沒有將原來的圖像清除,造成了圖像的殘留,于是窗體重繪時,如果沒有重繪所有的區域,畫面往往會變得混亂。所以單純的禁止背景重繪是不夠的,還必須重新對窗體的所有區域進行重繪。由于要對所有區域進行重繪,傳統的方法可能就不夠迅速。
雙緩沖圖形刷新技術顧名思義是采用雙緩存實現的。傳統的繪圖方式實際上是一種單緩沖。在Windows中每一種設備都在內存中有一個設備描述表與其對應,這個設備描述表實際上就是一個內存緩沖區。傳統的繪圖中我們是將圖形繪制在設備描述表緩沖區中,然后由GDI自動地將設備描述表中的圖像拷貝到顯存中進行顯示。這樣一個自動的拷貝過程屏蔽了傳統的繪圖方式是單緩沖的實質,使我們感覺到是在直接操縱顯存一樣。雙緩沖圖形刷新技術在內存中有兩塊緩存,除了設備描述表以外還有一塊需要手動建立的與設備描述表緩沖區相兼容的后備緩沖區。繪圖過程中,首先將圖形繪制在后備緩沖區中,然后再手動地將后備緩沖區中的圖像拷貝到前端緩沖區中,再由GDI自動將前端緩沖區中的圖像拷貝到顯存完成圖形的顯示過程。在實際中,我們使用BitBlt函數。它可以支持圖形塊的復制,速度很快。我們可以先在內存中作圖,然后用此函數將做好的圖復制到前臺,同時禁止背景刷新,這樣就消除了閃爍。以上也就是雙緩沖繪圖的基本的思路。在EVC中,可以按照以下步驟來使用雙緩沖技術進行圖形的繪制:
(a)創建與窗口設備描述表(前端緩沖區)兼容的內存設備描述表(后端緩沖區)。
(b)創建與內存設備描述表相兼容的位圖并將該位圖選入內存設備描述表中。
(c)將圖形繪制在內存設備描述表中。
(d)將內存設備描述表中的內容拷貝到窗口設備描述表。
(e)釋放設備描述表句柄、位圖等資源。
示波表作為一種便攜式的示波器,需要實現示波器的全部功能,對波形的刷新率要求較高。基于WinCE的示波表軟件,其畫面的顯示原理同Windows下的繪圖。
示波表中,考慮到提高畫圖的效率,創建了兩個內存兼容DC,將固定的背景(顯示波形的網格以及顯示測量結果的分隔線)專門放在一個命名m_bitmapBack的位圖中,當需要重新繪制波形時,只需將該位圖貼到畫波形的位圖m_bitmapWave上即可,這樣大大節約了調用MoveTo、LineTo等API函數所消耗的時間。
在本工程中,波形刷新顯示時的畫圖專門在畫圖線程中實現,雙緩沖技術在工程中的應用如下:
(1) 在使能畫圖線程前先進行內存DC的初始化工作:
①創建兼容的內存DC。工程中創建了兩個內存DC,m_dcBack用來保存固定的背景,m_dcWave用來繪制波形數據。
CClientDC clientDC(this);
m_dcBack.CreateCompatibleDC(&clientDC);
m_dcWave.CreateCompatibleDC(&clientDC);
② 創建與內存DC兼容的位圖,并選入內存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) 在畫圖線程中實現波形的刷新顯示,流程圖如圖1所示。

圖1 畫圖線程流程圖
畫圖線程中,先等待線程事件,若事件為真(待采集到波形數據并轉換為屏幕上的像素點坐標時,將畫圖線程事件置真),則進行波形的繪制。波形的繪制分為兩個步驟:
① 將已經繪制好背景的背景DC貼到波形DC上,該部分實現每次刷新波形時都將上次的波形清除:
m_dcWave->BitBlt(22,32,500,400,
&m_ dcBack, 22, 32, SRCCOPY);
② 在畫圖DC上,根據得到的波形數據繪制波形。上層應用程序調用底層驅動獲得波形數據,將數據轉換成屏幕坐標后,將坐標畫到畫圖DC上。
DrawWave(&m_ bitmapWave);
在DrawWave函數中使用PolyLine函數,將波形數據繪制到畫圖DC上。
③將繪制好波形的畫圖DC貼到設備DC上,實現波形的刷新。
在②中完成了畫圖DC的繪制,之后調用Invalidate()函數,給窗口發送WM_PAINT消息,在消息處理函數OnPaint中,將畫圖DC貼到設備DC上面。實現如下:
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);
}
在軟件中加入雙緩沖技術繪圖后,波形刷新時示波表界面不會出現混亂,也不會出現閃屏的現象,同時也提高了波形刷新的速率,很好地實現了示波表功能所要求的顯示效果。示波表界面顯示如圖2所示。

圖2 示波表界面顯示
在WinCE系統中使用EVC進行界面編程可以方便地運用Windows編程技術,在實際應用中,為了實現對界面快速刷新的要求時,使用雙緩沖技術可以很好地解決這一問題。在基于WinCE平臺的示波表軟件中,由于對波形的刷新率要求較高,使用雙緩沖技術來實現波形的刷新,很好地達到了功能的要求。
[1]JeffreyRichter,Christophe Nasarre.Windows核心編程[M].葛子昂,譯.北京:清華大學出版社,2008.
[2]侯捷.深入淺出MFC[M].武漢:華中科技大學出版社,2001.
[3]譚鋒.在基于MFC的VC程序中縮放顯示位圖[J].內江科技,2007:32-36.
[4]周民揚.Visual C++ 界面編程技術[M].北京:北京希望電子出版社,2003.
[5]楊樂.測試儀器中的動態波形繪制[J].儀器儀表學報,2006:26-27.
[6]孫鑫,余安萍.VC++深入詳解[M].北京:電子工業出版社,2006.
[7]夏萍,潘宏俠,王芳.基于VC的BMP位圖伸縮顯示[J].電子測試,2009(12):27-29.
[8]高偉衛,楊勝強,張滿棟.基于VC++6.0基礎類庫的圖像顯示[J].現代電子技術,2002(1):36-40.