<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>
關(guān) 閉

新聞中心

EEPW首頁(yè) > 工控自動(dòng)化 > 設計應用 > 采用VXD技術(shù)實(shí)現實(shí)的通信

采用VXD技術(shù)實(shí)現實(shí)的通信

作者: 時(shí)間:2004-12-07 來(lái)源:網(wǎng)絡(luò ) 收藏
摘要:討論Windows虛擬設備驅動(dòng)()技術(shù),并采用此項技術(shù)示范性地做出應用于PC串口實(shí)時(shí)的虛擬驅動(dòng)程序,找到一種可以在PC中實(shí)現實(shí)時(shí)的途徑。

關(guān)鍵詞: 實(shí)時(shí) 串口

引言

在微軟的視窗操作系統中,系統內核掌管所有的應用程序,通過(guò)獨特的任務(wù)調度算法實(shí)現CPU的分時(shí)多任務(wù)處理方式。多任務(wù)處理對大多數用戶(hù)可能是件好事,但是對那些想把實(shí)時(shí)通信建立在Windows操作系統上的特殊用戶(hù)來(lái)說(shuō),操作界面的圖形化并不比MS-DOS的單任務(wù)更具吸引力。在視窗操作系統里可以進(jìn)行實(shí)時(shí)通信和控制碼?答案是:技術(shù)可以幫我們在獲取友好的人機界面的同時(shí)還擁有很強的實(shí)時(shí)性。

1 VXD技術(shù)解析

VXD技術(shù)可追溯到Windows3.1,它的引入就是要讓操作系統實(shí)現多工以及硬件資源的共享。為了支持多個(gè)MS-DOS任務(wù)同時(shí)執行,Windows98讓每個(gè)MS-DOS應用程序在各自的虛擬機(VM)上運行,各自互不相干;而所有的Widnows應用程序卻都在一個(gè)虛擬機上運行。圖1所示的結構框圖很好地說(shuō)明了Windows98的整體架構。

圖1中,由眾多的VXD組成系統級代碼處于最底層。其中,處于中心地位的是一名為VMM32的VXD,它負責協(xié)調和管理所有的VXDs。其它VXDs則通過(guò)消息機制(這個(gè)消息機制由VMM32.VXD來(lái)維護)彼此聯(lián)系。由所有VXDs開(kāi)放出的服務(wù)接口(API)組成了一個(gè)服務(wù)網(wǎng),它們彼此通過(guò)合作的方式,提供Windows98的系統底層驅動(dòng)服務(wù)。

從以上Windows98系統架構可以看出,要想在視窗平臺下獲取很強的實(shí)時(shí)性,僅靠提升應用程序線(xiàn)程優(yōu)先級的方法是不夠的。因為Win32應用程序代碼屬于Ring3級,而VXD代碼則屬于Ring0級;采用VXD撰寫(xiě)的實(shí)時(shí)通信程序可以完全不受代碼限制,可以直接對硬件進(jìn)行操作。VXD的這個(gè)特點(diǎn)正是實(shí)時(shí)通信建立所必須的。

設計實(shí)時(shí)通信的VXD前,先解釋以下幾個(gè)問(wèn)題:

①VMM32使用VPICD.VXD虛擬化每個(gè)硬件和軟件中斷。VMM32為每個(gè)虛擬機(VM)維護一個(gè)IDT結構,當中斷發(fā)生時(shí),CPU先保護中斷現場(chǎng),然后經(jīng)由當前VM的IDT把這個(gè)中斷引導至相應的中斷處理程式。

中斷的虛擬化,使我們有機會(huì )給每個(gè)中斷提供新的中斷處理函數,并可以讓多個(gè)硬件共享同一個(gè)中斷號。VPICD.VXD為我們提供這些服務(wù)。

②VMM有兩個(gè)調度器,用以在多個(gè)線(xiàn)程和VMs之間實(shí)現搶占式多工。主調度器負責選定下一個(gè)將被執行的線(xiàn)程。這個(gè)選擇可以是一個(gè),也可以是多個(gè)。然后,主調度器把選擇結果送給所謂的時(shí)間片調度器,并由后者完成各個(gè)應用程序間的時(shí)間片分配。調度器也時(shí)應用程序經(jīng)由呼叫Win32線(xiàn)程優(yōu)先調整API(如SetThreadPriority和SetPriorityClass等)做出回應。當中斷發(fā)生時(shí),VMM32自動(dòng)提升中斷處理函數所在VM之優(yōu)先級,保證中斷處理函數能及時(shí)被執行。

③VXD和Win32應用程序可直接通信。Win32應用程序可通過(guò)一個(gè)系統API(DevicelOControl(…))來(lái)呼叫位于底層的VXD為其服務(wù)。在呼叫VXD前,首先必須調用CreatFile(…)這個(gè)API加載該VXD(如果該VXD是一個(gè)靜態(tài)VXD,則不用加載)。所有的呼叫動(dòng)作其實(shí)都通過(guò)VMM32完成。VXD也可以通過(guò)消息方式和位于上層的Win32應用程序通信。She11.VXD為所有希望以消息機制和Win32應用程序通信的VXD提供了這一服務(wù)。

以上是編寫(xiě)一個(gè)串口通信驅動(dòng)需要的系統層面知識。對于Windows底層的了解。

2 用VXD實(shí)現一個(gè)實(shí)時(shí)串口通信驅動(dòng)

接下來(lái)用VXD一個(gè)實(shí)時(shí)串行通信的驅動(dòng)。這個(gè)VXD是一個(gè)動(dòng)態(tài)(Dynamic)VXD,當它的服務(wù)被呼叫時(shí),VMM32會(huì )動(dòng)態(tài)加載這個(gè)VXD。作者采用的工具是C+98DDK。當然也可以使用其它的工具,如MASM6.11(或更高版本)、VtoolsD。用C搭配DDK完成VXD構建的好處是,可以使用C語(yǔ)言完成絕大部分的程序,程序比較容易閱讀和維護。

用C來(lái)實(shí)現一個(gè)VXD驅動(dòng),需要準備如下條件:一個(gè).ASM的匯編語(yǔ)言接口文件(在其中定義VXD要處理的系統消息和輸出API),一個(gè).C的函數實(shí)現文件(在其中完成自己函數實(shí)體),一個(gè).DEF的定義文件(在其中定義VXD中各個(gè)段的別名并匯成一個(gè)DDB)和一個(gè).MAK檔(用來(lái)編譯并連接生成VXD,可有可無(wú))。在這里,僅給出用C實(shí)現的函數檔。至于其它的文件,可以從本文所列的參考書(shū)目或其它文獻中找到相關(guān)文檔的說(shuō)明。

這個(gè)串口通信驅動(dòng)程序的功能是:實(shí)時(shí)送出一個(gè)Byte的數據,實(shí)時(shí)接收一個(gè)Byte的數據。作為演示之用,并沒(méi)有加入其它代碼。該VXD驅動(dòng)主要由如下3個(gè)系統消息(由VMM32來(lái)維護和管理)處理函數組成,其代碼如下:

(1)OnSysDynamicDeviceInit()函數

BOOL OnSysDynamicDeviceInit()

{ //OnSysDynamicDeviceInit

irqhandle=VPICD_Virtualize_IRQ((DWORD)(irq4));

if(irqhandle= =0){

return FALSE;

}

return TRUE; //OnSysDynamicDeviceInit

}

該函數用來(lái)完成VXD初始化所做的工作。在本例中,由于實(shí)時(shí)監視串口中斷的需要,要給COM1的中斷安裝一個(gè)自定義的斷服務(wù)函數。98DDK已經(jīng)提供了這個(gè)函數的C語(yǔ)言版,其原型是HIRQ static VPICD_Virtualize_IRQ(PVID pvid),在vpicd.h中。該函數需要一個(gè)指針作為參數(指向名為VPICD_IRQ_Descriptor的結構體),函數傳回一個(gè)指向該虛擬IRQ的句柄(該句柄在后來(lái)的VPICD服務(wù)中需要提供)。VPICD_IRQ_Descriptor結構體的組成為:

typedef struct VPICD_IRQ_Descriptor{

USHORT VID_IRQ_Number; //IRQ號(0~15)

USHORT VID_Options; //標志位選項

ULONG VID_Hw_Int_Proc; //硬件中斷服務(wù)程序的地址

ULONG VID_Virt_Int_Proc; //虛擬中斷服務(wù)程序

ULONG VID_Mask_Change_Proc //Mask Change調用例程

ULONG VID_IRET_Proc; //IRET調用例程

ULONG VID_IRET_Time_Out; //在Vm的進(jìn)程優(yōu)先級提升之前的最大等待時(shí)間

ULONG VID_Hw_Int_Ref; //硬件中斷服務(wù)程序的數據存放地址

}VID;

其中只用到三位。在本例中需要聲明一個(gè)名為irq4的全局變量為VID結構,并付給如下初值:VID irq4={4,0,hwproc,0,0,0,0,500,0},表示將要虛擬化IRQ4,改變其中斷處理函數為void hwproc(void),該函數的原型如下:

void hwproc(void){

_asm{

mov dx,0x3f8

in al,dx

mov byte ptr [readin],al

clc

}

return;

}

在這個(gè)中斷處理中,僅僅從COM1的數據寄存器(地址為3F8h)中讀取接收到的數值,并把該數值存放在一個(gè)類(lèi)型為BYTE、名為readin的內存中。

(2)OnSysDynamicDeviceExit()函數

BOOL OnSysDynamicDeviceExit()

{

VPICD_Force_Default_Behavior(irqhandle);

//解除IRQ4虛擬化

return TRUE;

} //OnSysDynamicDeviceExit

該數提供了用于善后處理VXD在卸載時(shí)需要完成的事件。在本例中,和VXD初始化對應,需要解除對COM1的中斷IRQ4的虛擬化。作者也是用98DDK在vpicd.h中提供的外包函數void static_inline VPICD_Force_Default_Behavior(HIRQ hirp)。該函數唯一需要的參數便是使用VPICD_Virtualize_IRQ函數傳回的IRQ句柄。

(3)OnDeviceIoControl()函數

DWORD OnDeviceIoControl(PDIOCPARAMETERS p){

Switch (p->dwIoControlCode)

{

case 1: //端口寫(xiě)功能

if(!p->lpvOutBuffer||p->cbOutBuffer1)

{ //輸出緩存的有效性檢查

return ERROR_INVALID_PARAMETER;

}

if(serial_out((DWORD)(p->lpvInBuffer)))

{ //數據發(fā)送

*(BYTE*)(p->lpvOutBuffer)=*(BYTE*)(p->lpvInBuffer);

}

else{

*(BYTE*)(p->lpvOutBuffer)=0;

}

open_int(); //打開(kāi)com1中斷

return 0;

case 2: //端口讀功能

if(*(BYTE*)reading= =0x00)

{ //數據讀入

*(BYTE*)(p->lpvOutBuffer)=0x00;

return 0;

}

*(BTYE*)(p->lpvOutBuffer)=*(BYTE*)(readin);

return 0;

}

return 0;

}

return 0;

}

OnDeviceIoControl函數用來(lái)處理Win32應用程序對VXD的呼叫。Win32應用程序的呼叫會(huì )讓VMM32送給該VXD一個(gè)系統信息,并傳遞進(jìn)一個(gè)DIOCPARAMETERS結構的指針。該結構里包含Win32應用程序呼叫時(shí)傳遞進(jìn)來(lái)的各個(gè)參數。這個(gè)結構的組成如下:

Typedef stunct DIOCParams{

DWORD Internall; //指向客戶(hù)寄存器的指針

DWORD VMHande; //該VM的句柄

DWORD Internal2; //指向DDB結構的指針

DWORD dwIoConrolCode; //DeviceIoControl例程中呼叫的控制碼

DWOD lpvInBuffer; //DeviceIoControl例程呼叫所傳遞進(jìn)來(lái)的輸入緩沖區地址

DWORD cbInBuffer; //輸入緩沖區的大小

DWORD lpvOutBuffer; //DeviceIoControl例程呼叫所傳遞進(jìn)來(lái)的輸出緩沖區地址

DWORD cbOutBuffer; //輸出緩沖區的大小

DWORD lpcbBytesReturned; //拷貝到輸出緩沖區中的字節數(可以為NULL)

DWORD lpOverlapped; //DeviceIoControl例程呼叫所傳遞進(jìn)來(lái)的重疊I/O塊結構

DWORD hDevice; //Ring3層呼叫應用程序句柄

DWORD tagProcess; //例程標簽

}

DIOPARAMETERS;

其中,dwIoControlCode指明了Win32應用程序需要VXD提供的哪一項服務(wù)。在本例中采用一個(gè)switch-case語(yǔ)句作為服務(wù)入口,如下所示。其中服務(wù)1為讓串口送出一個(gè)字節,服務(wù)2為讀取一個(gè)已經(jīng)由串口接收的字節。函數open_int()是用來(lái)初始化串口以便接收字節數據;函數BOOL serial_out(DWORD pBuffer)是讓串口發(fā)出一個(gè)字節。它們的函數體分別如下:

BOOL serial_out(DWORD pBuffer){

if(pBuffer= =NULL){

return FALSE;

}

_asm {

pushfd

cli

push eax

push edx

mov dx,0x3fb ;設置COM1的波特率

mov al,0x83

out dx,al

mov dx,0x3f8

mov al,12

out dx,al

mov dx,0x3f9

mov al,0

out dx,al

mov dx,0x3fb ;設置COM1的線(xiàn)控項

mov al,3

out dx,al

mov dx,0x3f9 ;CMM1關(guān)中斷

mov al,0

out dx,al

mov dx,0x3fa ;關(guān)閉com1的FIFO功能

mov al,0

out dx,al

mov dx,0x3f8 ;字節發(fā)送

mov al,byte ptr [pBuffer]

out dx,al

pop edx

pop eax

popfd

sti

}

return TRUE;

}

serial_out這個(gè)函數體的實(shí)現是用匯編語(yǔ)言實(shí)現的。因為涉及到很多的端口提供以及CPU的標志(flag)和壓棧操作,因此考慮到用匯編語(yǔ)言編寫(xiě)會(huì )簡(jiǎn)化代碼。因為此串口傳輸中,用到了關(guān)閉中斷的指令(cli),所以,當寫(xiě)操作所要求完成的任務(wù)很多時(shí),此關(guān)中斷指令會(huì )讓程序的實(shí)時(shí)性很好地體現出來(lái),但cli指令有效時(shí)間過(guò)長(cháng)會(huì )導致系統問(wèn)題,所以還是要謹慎使用。

Void open_int(void){

_asm{

mov dx,0x3f9 ;COM1開(kāi)中斷

mov al,0x05

out dx,al

}

return;

}

open_int函數用來(lái)把PC串口的中斷設備按照需要設立起來(lái)。函數體很簡(jiǎn)單,僅改變了地址為3F9h的內容,意為設置Rx data ready和Line status中斷位,以便讓CPU可以及時(shí)在COM1的中斷服務(wù)程序里讀取串口接收到的字節。

以上涉及到串口輸入和輸出的函數體實(shí)現代碼中,用到了PC16550 UART的資料。

至此,一個(gè)可用于實(shí)時(shí)串口通信的VXD驅動(dòng)程序已經(jīng)完成。由于篇幅所限,不能將其它必要的文檔一同提出來(lái)討論。

3 Win32客戶(hù)測試程序

有了上述VXD驅動(dòng)程序,還需要搭配一個(gè)Win32客戶(hù)程序來(lái)進(jìn)行測試。在網(wǎng)絡(luò )補充版(http://www.dpj.com.cn)中,給出一個(gè)筆者在VC6下編制的一個(gè)控制臺應用程序片斷,以供參考。

現在編制VXD驅動(dòng)還沒(méi)有一個(gè)集成開(kāi)發(fā)環(huán)境(IDE)。本文的驅動(dòng)程序是用VC6.0自帶的編譯器編譯的。由于要編譯匯編文檔,所以還需要把一個(gè)MASM匯編器(要求6.0以上版本)及其相關(guān)文檔拷貝到VC6.0的vc98u30446目錄下。

4 結論

通過(guò)以上對VXD技術(shù)的簡(jiǎn)要分析以及一個(gè)用VXD實(shí)現的通信驅動(dòng)可以看出,在Windows操作系統中,采用VXD技術(shù),可以很好地克服由多工帶來(lái)的時(shí)延問(wèn)題,很好地解決了在Windows平臺下實(shí)時(shí)通信的問(wèn)題。



關(guān)鍵詞: VXD 技術(shù)實(shí)現 通信

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>