四、硬件中断驱动程序开发实例 在笔者设计的24自由度仿人型机器人实时仿真和控制系统中,为了提高系统的可移植性,首先通过VxD修改PC基板上CMOS中的可编程计数器以获得2KHz的系统08中断频率,并截获此中断来进行实时调度。通过对此基本定时信号的调度以获得诸如对外部多通道的模拟量进行采集、控制算法处理、控制结果输出以及实时屏幕刷新等多任务的定进信号[4]。这种方法不需要用户提供附加的硬件定时器。开发中选定Windows 98作为软件开发平台,为了充分利用32位CPU和操作系统的处理能力,选择Microsoft Visual C++ 6.0作为应用层(ring 3)开发工具,应用程序是基于MFC。而VxD是通过VtoolsD 2.04编写的。Ring 0级调试工具为NuMega公司的SoftIce 3.23。本文将对Ring 0和Ring 3两层软件的设计加以说明。 1.Ring 0级硬件中断VxD的设计
在使用QuickVxD生成框架代码的过程中,在Device Parameters选单中应选中Dynamically Loadable以使得驱动程序能够动态加载。在Windows 95 control messages选单中选中W32-DEVICEIOCONTROL消息、SYS-DYNAMIC-DEVICE-INIT消息及SYS-DYNAMIC-DEVICE-EXIT消息。这些消息的处理函数通过以下VxD的实现代码加以说明:
#include #include"winioctl.h" #define DEVICE-CLASS IrqtestDevice #define IRQTEST-DeviceID UNDEFINED-DEVICE-ID #define IRQTEST-Init-Order UNDEFINED-INIT-ORDER #define IRQTEST-Major 1 #define IRQTEST-Minor 0 #define w32IF-PASS-EVENT CTL-CODE (FILE-DEVICE-UNKNOWN, 1,METHOD-NEITHER,FILE-ANY-ACCESS) #define RTC-IRQ8//实时时钟使用的IRQ #define STATREG-A 0xA #define STATREG-B 0xB #define STATREG-C 0xC #defing ENABLE-INTERRUPT 0x40 #define WM-MY-MESSAGE 0x0410//自定义消息 BOOL -stdcall RTCInt-Handler(VMHANDLE hVM,IRQHANDLE hIRQ);//时钟中断服务程序 VOID WriteCMOS(BYTE reg,BYTE value); BYTE ReadCMOS(BYTE reg); class IrqtestDevice:public VDevice{ prblic; virtual BOOL OnSysDynamicDeviceInit(); virtual BOOL OnSysDynamicDeviceExit(); virtual DWORD OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams);}; class IrqtestVM:public VVirtualMachine{ public; IrqtestVM(VMHANDLE hVM);}; class IrqtestThread:public VThread{ public: IrqtestThread(THREADHANDLE hThread);}; //IRQTEST.cpp-main module for VxD IRQTEST #define DEVICE-MAIN #include"irqtest.h" #undefDEVICE-MAIn Declare-Virtual-Device(IRQTEST) VPICD-HWInt-THUNK RTCInt-Thunk;handler//中断Thunk EVENTHANDLE hEvent;//Handle of timer event IRQHANDLE RTCIRQHandle;//Handle for virtual IRQ BYTE SavedStatusRegisterA; BYTE SavedStatusRegisterB;//保存RTC设置寄存器 DWORD TickCounter;//中断计数器 DWORD*PostMsghWnd;//Ring3层应用程序的hWnd HANDLE hWnd; IrqtestVM::IrqtestVM(VMHANDLE hVM) VVirtualMachine(hVM){} IrqtestThread::IrqtestThread(THREADHANDLE hThread) VThread(hThread){} BOOL IrqtestDevice::OnSyaDynamicDeviceInit(){ VMHANDLE hVM; hVM=Get-Cur-VM-Handle(); BYTE statreg; DWORD status; DWORD RTClockFreqIndex; |
//挂接硬件中断需要调用虚拟可编程中断控制器(VPICD)来通知Windows此VxD负责处理此IRQ。在这里我们只用到了VPICD提供的五个不同的与IRQ相关的通知事件之一,即实际的硬件中断事件。 struct VPICD-IRQ-Descriptor IRQdesc;//此结构将被传入VPICD-Virtualize-IRQ例程进行初始化,以下是参数设置。IRQdese.VID-IRQ-Number=RTC-IRQ;//将要被虚拟的IRQ IRQdesc.VID-Options=0;//保留 //为了在此结构中设置中断服务例程的地址,我们将服务例程thunk的地址传递给VPICD-Thunk-HWInt,它将负带将thunk初始化并返回它的地址
IRQdesc.VID-Hw-Int-Proc=(DWORD)VPICD-Thunk-HWInt (RTCInt-Handler,&RTCInt-Thunk); IRQdesc.VID-IRET-Time-Out=500; //此结构的其它变量在这里没有用到。 //通过VPICD-Virtualize-IRQ服务将已定义结构传入VPICD,VPICD分配IRQ并返回其句柄 RTCIRQHandle=VPICD-Virtualize-IRQ(&IRQdesc); if(RTCIRQHandle==0)returnFALSE;//虚拟化失败 //保存初始RTC状态寄存器以便退出时恢复现场 SavedStatusRegisterA=ReadCMOS(STATREG-A); SavedStatusRegisterB=ReadCMOS(STATREG-B); RTClockFreqIndex=6;设置中断频率,见下文说明; statreg=(SavedStatusRegisterA & ~0xF)|(RTClockFreqIndex & 0xF); WriteCMOS(STATREG-A,statreg); //设置RTC状态寄存器使得status register flags to enable it to assert its IRQ statreg=ReadCMOS(STATREG-B); statreg|=ENABLE-INTERRUPT; WriteCMOS(STATREG-B,statreg); ReadCMOS(STATREG-C); TickCounter=0;//初始化中断计数器 //保证IRQ在PIC中未被屏蔽 VPICD-Physically-Unmask(RTCIRQHandle); return TRUE; } BOOL IrqtestDevice:OnSysDynamicDeviceFxit(){ //恢复现场; Cancel-Global-Event(hEvent); WriteCMOS(STATREG-A,SavedStatusRegister A); WriteCMOS(STATREG-B,SavedStatusRegister B); VPICD-Physically-Mask(RTCIRQHandle); VPICD-Force-Default-Behavior(RTCIRQHandle); return TRUE; } DWORD IrqtestDevice::OnW32DeviceIoControl (PIOCTLPARAMS pDIOCParams) { switch(pDIOCParams->dioc-IOCtICode){ case DIOC-OPEN;//CreateFile {hWnd =0;//Ring 3层应用程序主窗口句柄初始化 return 0;} case W32IF-PASS-EVENT: PostMsghWnd=(DWORD*)pDIOCParams->dioc-InBuf; hWnd=(HANDLE)*PostMsghWnd;//获得主窗口句柄 return 0; default:return-1;} return 0;} BOOL -stdcall RTCInt-Handler(VMHANDLE hVM,IRQHANDLE hIRQ){ //在中断服务例程中,对中断计数器计数并向Ring 3层应用程序发送自定义消息; if(hWnd&&(TickCounter%100==0)){ SHELL-PostMessage(hWnd,WM-My-MESSAGE,0,0,NULL,NULL);} TickCounter++; ReadCMOS(STATREG-C);//清除RTC状态标志 VPICD-Phys-EOI(hIRQ);//指定VPICD清除此中断 return TRUE;//thunk将清除进位 } |
//篇幅所限,针对COMS端口操作的两个函数ReadCMOS(BYTE reg)和WriteCMOS(BYTE reg,BYTE value)的源程序略,请参考VtoolsD连机帮助中的CHIME例子。
2.Ring 3级主应用程序设计
将生成的VxD放入主应用程序的工作目录中,用CreateFile()函数动态加载VxD。
hDevice=CreateFile("////.//irqtest.vsd",0,0,0,OPEN-ALWAYS,FILE-FLAG-DELETE-ON-CLOSE,0); 需要挂接中断时,调用DeviceIoControl()将主程序窗口的句柄传递给正运行的VxD。 Main-CWnd=AfxGetMainWnd(); inBuf[0]=Main-CWnd->m-hWnd; if(! DeviceIoControl(hDevice,W32IF-PASS-EVENT,inBut,sizeof(PVOID),RetInfo,sizeof (RetInfo),&cbBytesRetumed,NULL)) AfxMessageBox("DeviceIoCtl Failed!"MB-OK);//与VxD通讯失败
然后在自定义消息处理函数中加入自己的实时处理代码。需要说明以下几点:
在VxD的中断处理函数中可以加入对实时性要求最高的代码,原则上应尽快返回以提高中断频率和避免重入; 中断频率的选择参数n有以下选择: n 频率(Hz) n 频率(Hz) 1 256 7 512 2 128 10 64 3 8192 11 32 4 4096 12 16 5 2048 13 8 6 1024 14 4 |
本文介绍的方法同样适用于编写其他普通硬件中断VxD。 在中断频率较高的数据采集系统中。可以设置双缓冲区来实现实时中断与处理线程的同步。
五、结论 本文在对PC和Windows 9X和9X进行了细致的研究之后,分析了在其上构造实时系统的方法,并通过详细的应用示例给出了具体的说明。本文使用的方法具有通用性和易用性,在笔者设计的24自由度仿人型机器人控制系统中运行良好。本文介绍的方法对于开发Windows 9X实时控制系统具有实际的参考价值。  
说明:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
2/2 首页 上一页 1 2 |