时间:2022-11-02 01:26:43
开篇:写作不仅是一种记录,更是一种创造,它让我们能够捕捉那些稍纵即逝的灵感,将它们永久地定格在纸上。下面是小编精心整理的12篇驱动程序设计,希望这些内容能成为您创作过程中的良师益友,陪伴您不断探索和进步。
关键词:wince 驱动程序;开发;设计
1 引言
WINCE和Windows 98或Windows 2000不同,它可以工作在12种不同的处理器体系结构、180余种CPU上;同时,WINCE是一个实时操作系统(实时系统的意义就是输入的指令不必进入队列就可以马上处理,过去我们使用的DDS就是实时系统),可以满足应用程序所需要的实时性要求。
Windows CE的模块化设计使得它能够在大量的平台上定制使用,从客户电子设备到专用的工业控制器。由于它是模块化的,因而我们可以使用满足平台系统需求的最小软件模块和组件集合来设计嵌入式系统平台,从而使内存用量最小,但最大可能地提高操作系统的性能。因此外围扩展设备就必须要有硬件驱动才能正常工作。
和其它的操作系统一样,Windows CE也提供设备驱动软件,这些软件的目的是驱动内部和外围的硬件设备,或为它们提供接口。设备驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备或者为应用程序提供设备服务。
Windows CE支持广泛的基于各种CE平台的设备驱动程序。也提供一些用于驱动程序开发的模型(model) ,其中包括来自其它操作系统的驱动程序模型(model),因为这些丰富多变的驱动程序模型, Windows CE适应大部分的内部和外围设备口Microsoft Windows CE设备驱动程序工具包配备了文档资料,这些文档资料使得你能够为Windows CE创建设备驱动程序。目前,Windows CE提供了四种设备模型,其中两种是专用于Windows CE的模型,另外两种外部模型来自其它操作系统。
2 驱动程序开发简介
2.1 开发工具
Windows CE驱动可以使用Platform Builder或者Visual Studio开发,但是开发人员一般都使用Platform Builder开发设备驱动程序,对于部分驱动也会使用Visual Studio开发,应用程序开发人员更多的使用Visual Studio开发驱驱动程序。作为BSP(Board Support Package)的一部分进行整体编译开发。
2.2 驱动分类
2.2.1 按加载方式和接口类型分类
1) 本机驱动程序(Built-In Drivers)
通常由GWES加载,驱动接口一般都是定制的(Custom Purpose)。
2) 流驱动程序(Stream Drivers)
通常由Device Manager加载,驱动接口是标准的流式接口。
3) 混和型驱动程序
同时有定制式和流驱动两套驱动接口,但是和系统交互只使用流式驱动接口,比如PC卡槽驱动。
2.2.2 按驱动层次分类
1) 层次型驱动程序(Layered Driver)
> MDD(Model Device Driver),与硬件无关,面向上层应用程序,一般由微软建立统一框架;
> PDD(Platform Dependent Driver),针对具体硬件平台的操作代码,一般由驱动开发商实现MDD和PDD之间通过标准的设备驱动服务供应商接口DDSI连接。
2) 独立型驱动程序(Monolithic Driver)
> 独立驱动程序包含了MDD面向上层应用和PDD面向硬件平台两方面的代码;
> 适用于操作不复杂的驱动;
> 减少了MDD和PDD传递之间传递信息的开销,实时性更强;
3 流驱动程序的实现
流驱动程序必须实现一套标准接口,流驱动程序适用于IO操作,这也是嵌入式系统中最常见的设备驱动,操作接口和文件系统操作相似,通过CreateFile,ReadFile,WriteFile,IOControl函数等来操作应用程序和流驱动交互,可以把设备当作文件操作。
3.1 文件前缀名确定
根据文件前缀名在系统中必须唯一这一特点,在定义文件前缀名必须是三个字母,若有多个同类设备,由后缀一个阿拉伯数字区分,例如COM1,LPT3等等。文件前缀名将会在驱动的标准接口函数中体现,比如XXX_Init,XXX_Close等。
3.2 通用函数
根据设备的不同,所需函数不同,通用函数如下所示:
1) XXX_Init:通知设备管理器为设备初始化分配资源;
2) XXX_Deinit:通知设备管理器回收设备初始化时分配的资源;
3) XXX_Open:打开设备。应用程序调用CreateFile时,通过文件系统映射为XXX_Open;
4) XXX_Close:关闭设备。应用程序调用CloseFile时,通过文件系统映射为XXX_Close;
5) XXX_PowerUp:设备上电时,操作系统调用该函数完成必要的上电操作;
6) XXX_PowerDown:设备掉电时,操作系统调用该函数完成必要的关机操作
7) XXX_Read:从打开的设备文件中读取数据,可以通过ReadFile映射;
8) XXX_Write:向打开的设备文件写数据,可以通过WriteFile映射;
9) XXX_Seek:文件定位,根据设备情况决定是否支持;
10) XXX_IOControl:IO操作扩展,可以根据设备情况来决定支持何种特殊的操作模式。
3.3 DEF文件建立
流驱动一般以DLL形式存在,DEF文件定义了DLL需要导出的接口集,因此DEF文件的名称与设备驱动名称相同。
3.4 写注册表
在wince中任何设备的识别都是通过注册表来实现的,因此必须在注册表中添加具体的设备驱动项,以便系统识别。具体方法如下:
在注册表中增加驱动程序入口点,找到注册表项,注册项位于注册表的Root Key下,一般为[HKEY_LOCAL_MACHINEDriversBuiltInSampleDrv],建立必要的子键和键值,“Prefix”和“DLL”是两个重要,而且是必须的键,分别描述了设备前缀名和驱动程序的动态连接库名,然后根据具体设备的需要建立驱动程序需要的其子他键。
4 调试驱动程序
驱动程序编写完毕后,就应该进行硬件的调试。具体方法如下:
4.1 调试区信息(Debug Zone)
调试区一般和WinCE的控制台调试工具Cesh.exe配合调试,在不打断OS运行情况下,进行驱动的实时调试,利用宏开关,可以选择需要输出的调试区信息,可以得到进程,线程和调试状态信息。并且可以利用IDE环境,动态选择开关调试区信息,但是打印驱动程序输出调试信。必须借助于至少一种外设显示调试信息,比如串口或者网卡或者其他通过调用RETAILMSG或者DEBUGMSG完成,不影响OS的运行,保证驱动程序运行的真实性,动态输出设备的状态信息,调试相对简单,也是最广泛使用的一种调试方法。
4.2 核心调试工具(Kernel Debugger)
核心调试工具将会禁止所有硬件中断,挂起操作系统,因此可以单步调试OS或者核心代码,可以访问堆栈信息,但是必须在Platform的环境下,利用至少一种外设进行通信。
4.3 硬件辅助调试方法
利用硬件调试工具可以观察物理设备的真实状态,一般常用的方法可以利用JTAG工具实时查看CPU内部寄存器,利用逻辑分析仪或者示波器实时查看物理外设的输入输出状态。利用指示LED来显示驱动程序实时状态信息。
4.4 Visual Studio调试
可以利用VS内置的调试工具进行单步跟踪,状态调试等。
5 测试驱动程序
驱动程序经过调试以后就需要对驱动的功能进行测试。其常用的方法如下:
1) 写一个应用程序来测试驱动程序的正确性
2) 模拟各种可能发生的硬件输入状态来测试驱动程序的正确性
3) 利用Windows CE自带的测试工具CETK来测试驱动程序的性能和完备性
6 驱动程序的集合和
6.1 驱动程序集成
驱动程序经过调试和测试确定其正确性后,就可以对驱动程序进行集成了。具体过程如下:
1) 在BSP的Driver目录下建立新的驱动文件夹MyDrv
2) 实现MyDrv驱动以及相关的DEF文件
3) 如果需要用到硬件中断资源,修改原BSP中的相关中断处理函数OEMInterruptEnable,OEMInterruptDisable,OEMInterruptDone,OEMInterruptHandler
4) 在Platform.reg中,增加驱动程序相关项
5) 在Platform.bib中,增加驱动程序的相关注册表项MyDrv.Dll$(_FLATRELEASEDIR)MyDrv.dll NK SH
6.2 驱动程序
驱动程序进过集成以后就可以使用了,具体的过程如下所示:
1) 利用CAB Wizard生成.cab驱动包
2) 直接提供驱动程序文件夹以及相关注册表项和修改说明
7 总结
本为详细的介绍了,wince下驱动开发的流程,介绍了驱动程序开发到的详细过程,并详细说明了各个部分的实现和操作方法,使是初学者对wince下驱动程序的开发流程和一般的开发工具有了初步的了解。
关键字 Windows系统 驱动程序 通知应用程序 设计 方法
中图分类号: TP316 文献标识码:A
1 前言
操作系统的稳定性及可移植性是务必要优先确保的,为此Windows操作系统不支持应用程序直接访问系统的硬件资源,而是必须借助于相应的设备驱动程序。设备驱动程序可以直接操作硬件,假如应用程序和设备驱动程序之间实现了双向通信,也就达到了应用程序控制底层硬件设备的目的。
2 通知应用程序设计四种方法
鉴于设备驱动程序通知应用程序的重要性,本人结合一些经验,对它进行了总结,归纳出5种方法摘要:异步过程调用(APC)、事件方式(VxD)、消息方式、异步I/O方式和事件方式(WDM)。下面分别说明这几种方式的原理。
2.1 异步过程调用(APC)
Win32应用程序使用CreateFile()函数动态加载设备驱动程序,然后定义一个回调函数backFunc(),并且将回调函数的地址%26amp;backFunc()作为参数,通过DeviceIoControl()传送给设备驱动程序。回调函数的输入参数是由设备驱动程序填入的,回调函数在这里主要是对消息进行处理。
2.2 事件方式(VxD)
首先,Win32应用程序创建一个事件的句柄,称其为Ring3句柄。由于虚拟设备驱动程序使用事件的Ring0句柄,因此,需要创建Ring0句柄。用LoadLibrary()函数加载未公开的动态链接库Kernel32.dll,获得动态链接库的句柄。然后,调用GetProcAddress(), 找到函数OpenVxDHandle()在动态链接库中的位置。接着,用OpenVxDHandle()函数将Ring3事件句柄转化为Ring0事件句柄。Win32应用程序用CreateFile()函数加载设备驱动程序。
2.3 消息方式
Win32应用程序调用CreateFile()函数动态加载虚拟设备驱动程序。加载成功后,通过调用DeviceIoControl()函数将窗体句柄传送给VxD,VxD利用这个句柄向窗体发消息。当条件满足时,VxD调用SHELL_PostMessage()函数向Win32应用程序发送消息。SHELL_PostMessage()函数的第一个参数为Win32窗体句柄,第二个参数为消息ID号,第三、四个参数为发送给消息处理函数的参数,第五、六个参数为回调函数和传给它的参数。Win32应用程序收到消息后,对消息进行处理。
2.4 事件方式(WDM)
Win32应用程序首先创建一个事件,然后将该事件句柄传给设备驱动程序,接着创建一个辅助线程,等待事件的有信号状态,自己则接着干其他事情。设备驱动程序获得该事件的句柄后,将它转换成能够使用的事件指针,并且把它寄存起来,以便后面使用。
3 结语
在目前流行的Windows操作系统中,设备驱动程序是操纵硬件的最底层软件接口。它向上提供和硬件无关的用户接口,向下直接进行I/O、硬件中断、DMA和内存访问等操作。它将应用程序和硬件细节屏蔽开来,使软件不依靠于硬件并且可在多个不同的平台之间移植。这4种方法都经过实际测试。测试结果表明,它们都能够达到设备驱动程序通知应用程序的目的。
参考文献
[1] 李和平. 基于DSP的ICT图像重建系统探究. 北京摘要: 北京航空航天大学机械工程及自动化学院, 2002
【关键词】USB 设备驱动 Linux
1 USB总线原理
USB 协议是1994年底由康柏、IBM、英特尔等几家公司联合提出来的外部总线接口协议。USB就是英文中Universal Serial Bus(通用串行总线)的缩写。USB总线具有其他总线所不具备的如:热插拔、数据传输可靠、扩展方便、成本低等一系列特点,因此在嵌入式系统中被广泛使用。
一个USB系统一般是由一个USB主机控制器、一个或多个USB集线器和一个或多个USB设备节点组成。USB系统的物理连接具有层次性。USB总线连接USB设备和USB主机,是一种星型拓扑结构。USB的拓扑结构如图1所示。
在一个USB系统传输数据的过程中有两个非常重要的概念,就是USB传输模式和USB描述符。USB传输模式是指USB设备传输数据的形式。USB设备支持四种传输模式:控制传输模式、同步传输模式、中断传输模式和批量传输模式。控制传输模式是用来处理USB主端口到USB从端口的数据传输,主要是设备控制指令、设备查询状态指令和确认指令。同步传输模式是指传输和时间关系密切的信息所使用的一种传输方式,是一种周期的、连续的单向传输方式。中断传输模式这类传输模式主要用于传输非周期性的、自然发生的、数据量很小的信息,这类数据传输的方向是从设备到主机,适用于键盘、鼠标、操纵杆等设备上。最后一种是批量传输模式,该模式适用于大量的、对时间没有要求的数据传输,如U盘或者移动硬盘等设备。
USB设备在逻辑上分为几个层次,分别是设备层(Device)、配置层(Config)、接口层(Interface)、端点层(Endpoint)。各个层次都有与之相对的描述符,分别是设备描述符、配置描述符、接口描述符和端点描述符。
2 Linux下的USB驱动框架
USB设备的设备描述符在Linux系统中用usb_device_descriptor结构体表示,它描述了USB设备的一般信息。配置描述符用usb_config_descriptor结构体表示,它给出了USB设备的配置信息。接口驱动程序是在一个配置内给出一个接口信息,它在Linux中由usb_interface_descriptor结构体表示。端口描述符被主机用来决定每个端口的带宽需求,它在Linux系统中由usb_endpoint_descriptor结构体表示。
编写一个USB驱动程序,是从usb_driver结构体开始的。Linux中模块加载函数调用usb_register()和usb_unregister()从而对usb_driver结构体进行加载与卸载。如果某个设备信息与该驱动中usb_device_id usb_mouse_id_table 结构体的信息相一致,则会调用usb_driver中探测成员函数probe(),将初始化USB断点信息,并对设备做一些初始化工作,分配urb结构体,准备数据传输。其urb处理大致框架结构如图2所示。
当鼠标设备在用户空间打开时,将提交 probe 函数构建的 urb 请求块,urb 将开始为传送数据而忙碌了。urb 请求块就像一个装东西的“袋子”,USB 驱动程序把“空袋子”提交给 USB core,然后再交给主控制器,主控制器把数据放入这个“袋子”后再将装满数据的“袋子”通过 USB core 交还给 USB 驱动程序,这样一次数据传输就完成了。
3 结束语
由于USB简单方便快捷等优点,许多外接设备会越来越青睐USB接口,这是一种发展的趋势。Linux系统具有开源、安全等特性,用户也在急剧增加。届时,会有越来越多的USB驱动加入Linux内核之中。
参考文献
[1]Jonathan Corbet,Alessandro Rubini,Greg Kroah-Hartman等.LINUX设备驱动程序[M].北京:中国电力出版社,2006.
[2]Universal Serial Bus Specification Compaq,Intel,Mi―crosoft,NEC Revision 1.1.September 23,1998.
[3]温卡特斯瓦兰.精通Linux驱动程序开发[M].北京:人民邮电出版,2009.
[4]胡晓军,张爱成.USB接口卡发技术[M].西安:西安电子科技大学出社,2005:15-17.
作者简介
徐海林(1989-),男,江苏省南通市人。现为安徽理工大学计算机科学与工程学院学生。
关键词:PCI总线设备驱动程序WDM模式DriverStudio
PCI总线规范是为提高微机总线的数据传输速度而制定的一种局部总线标准。在设计自行开发的基于PCI总线的数据传输设备时,需要开发相应的设备驱动程序。通常开发PCI设备驱动程序有多种模式,在Windows2000环境下,主要采用WDM模式。本文针对自行开发的基于PCI总线的CCD视频信号传输控制卡,编写了符合WDM模式的驱动程序。
1WDM模式驱动程序
1.1WDM模式(WindowsDriverModel)
Windows2000对驱动程序的编写不再基于以往的Win3.x和Win9x下的VxD(虚拟设备驱动程序)结构,而是基于一种新的驱动模型——WDM(WindowsDriverModel)。
WDM为Windows98/2000/XP操作系统的设备驱动程序的设计提供了统一的框架。WDM来源于WindowsNT的分层32位设备驱动程序模型(layered32-bitdevicedrivermodel)。它支持更多的特性,如即插即用(PnP)、电源管理、WMI和NT事件。
1.2设备驱动程序
设备驱动程序是操作系统的一个组成部分,它由I/O管理器(I/OManager)管理和调动。Windows2000操作系统下的I/O管理器功能描述如图1所示。
I/O管理器每收到一个来自用户应用程序的请求就创建一个I/O请求包(IRP)的数据结构,并将其作为参数传递给驱动程序。驱动程序通过识别IRP中的物理设备对象(PDO)来区别是发送给哪一个设备。IRP结构中存放请求的类型、用户缓冲区的首地址、用户请求数据的长度等信息。驱动程序处理完这个请求后,在该结构中填入处理结果的有关信息,调用IoCompleteRequest将其返回给I/O管理器,用户应用程序的请求随即返回。访问硬件时,驱动程序通过调用硬件抽象层的函数实现。
1.3DriverStudio工具简介
NuMegaLab公司开发的DriverStudio是一整套开发、调试和检测Windows平台下设备驱动程序的工具软件包。它把DDK(DeviceDevelopmentKit)封装成完整的C++函数库,根据具体硬件通过向导生成框架代码,并且提供了一套完整的调试和性能测试工具SoftICE、DriverMonitor等。
2应用实例
本文利用PCI专用接口芯片PCI9052设计了一个数据传输控制卡。卡上主要的芯片有PCI9052、FIFO(CY7C4221)、CPLD(MAX7064S)和A/D转换器(MAX1197)。传输卡硬件框图如图2所示。面阵CCD得到的视频信号经过调理电路,生成的视频调理信号通过A/D转换器进行数字化处理,送入FIFO中。在CPLD的控制下,数据经过PCI9052送入PCI总线,再传送到计算机内存中,并显示在监视器上。驱动程序必须实现如下几个基本功能:(1)硬件中断;(2)能支持应用程序获取数据;(3)能根据外部FIFO(CY7C4221)的状态启动或停止突发传输。
在数据输入过程中,最重要的是对数据进行实时控制,因此需要硬件中断。在中断程序中,根据外部FIFO状态完成数据的读入。
2.1用DriverWizard生成驱动程序框架
DriverStudio中的DriverWorks软件为开发WDM程序提供了一个完整的框架。它包含一个可快速生成WDM驱动程序框架的代码生成向导工具DriverWizard,而且还带有许多类库。在用DriverWizard生成的程序框架中写入相对于设备的特定代码,编译后即可得到所需的驱动程序。
在利用DriverWorksV2.7的向导DriverWizard完成驱动程序的框架时共有11个步骤,其中关键步骤有:
(1)在第四步中选中PCI,并在VendorID和DeviceID中分别输入厂商号和设备号,还需填入PCISubsystemID和PCIRevisionID。这四项可以用网上的免费软件PCITree或PCIView浏览PCI设备,用这两个软件也可以得到BAR0~BAR5的资源分配情况和中断号。
(2)第七步IRP队列排队方法,它决定了驱动程序检查设备的方式。本设计选SystemManaged,则所有的IRP排队都由系统(即I/O管理器)完成。
(3)第九步是最关键的一步。首先在Resources中添加资源,在name中输入变量名,在PCIBaseAddress中输入0~5的序列号。0~5和BAR0~BAR5一一对应。在设置中断对话框中,在name栏写入中断服务程序的名称,选中创建中断服务程序ISR?穴CreateISR?雪,不选创建延迟程序调用DPC(CreateDPC),选中MakeISR/DPCclassfunctions,使ISR/DPC成为设备类的成员函数。
其次选中Buffer以选取读写方式,用于描述与I/O操作相关的数据缓冲区。本设计需要快速传送大量数据,因此采用DirectI/O方式。
(4)在第十步中,需要加入与应用程序或者其他驱动程序通信的I/O控制代码参量。
2.2驱动程序模块框图和代码分布
PCI设备驱动程序模块包括配置空间的访问模块、IO端口模块、内存读写模块和终端模块等。各模块之间是对等的。驱动程序模块框图如图3所示。
驱动程序初始化模块代码段放在#pragmacode_seg(″INT″)和#pragmacode_seg()之间。在系统初始化完成后,这部分代码从内存中释放,防止占用系统宝贵的内存资源。#pragmacode_seg()之后是驱动程序和系统的许多模块的实现部分。这部分在驱动程序运行后不会从内存中释放。
2.3驱动程序主要模块的实现
(1)配置空间的访问模块
DriverWorks的KPciConfiguration类封装了访问PCI设备配置空间的所有操作。首先初始化这个类的实例:
KpciConfigurationPciConfig()m_Lower.TopOfStack());
/?觹m_Lower是KpnpLowerDevice类的对象。m_LowerTopOfStack()返回当前设备堆栈顶部的设备对象。*/
初始化完后可以直接利用成员函数ReadHeader/WriteHeader函数访问所有的配置寄存器。
为了确定映射空间的类型和大小,先向目标基地址寄存器写入0Xffffffffh,然后回读该寄存器的值。如果最低位为1,表示映射于I/O空间,反之为存储空间;如果映射于存储空间,从第四位开始计算0的个数可以确定内存空间的大小;如果是I/O方式,从第二位开始计算0的个数可确定I/O空间的大小,最大为256字节。如果设备的存储空间超过256字节,要实现设备的整个存储部分的访问,就必须采用内存映射。
(2)I/O操作模块
Driverworks的KIoRange类封装了I/O端口访问的操作。部分代码如下:
{……
KIORangeDevIoPort();//创建实例
NTSTATUSstatus=DevIoPort().Initialize(pResListTranslated,pResListRaW,PciConfig.BaseAddressIndexToOrdinal(0));
/*第一个参数为转换后的资源列表指针;第二个参数为原始资源列表指针;第三个参数中的0为I/O口对应的基地址,用来转换成特定端口资源的序数?*/
If(NT_SUCCESS(status))
{……
DevIoPort.inb(0,LineBuf1,10);
/*成功初始化后可分别用KIoRange类的成员函数inb(/outb)从端口中读/写字节*/
}
else{Invalidate();returnstatus;
/*未能初始化成功,错误信息在status中*/
{
……}
(3)内存读写模块
DriverWorks的KMemoryRange类封装了端口访问的操作。
status=m_MemoryRange().Initialize(pResListTranslated,pResListRaw,PciConfig.BaseAddressIndexToOrdinal(0));
此函数的参数、意义及具体用法与I/O端口的操作基本相同。
内存对象也用来发送控制字,以控制CPLD的开始和停止等。实际上控制字是通过PCI9052发送的。该控制字地址已被映射成PCI的内存空间。所以定义一个指向内存空间的内存对象,通过该对象即可发送控制字。
(4)中断模块
在中断模块,首先要激活PCI9052中断使能位,然后判断硬件中断响应是否产生,如果有,则进行突发传输,读入FIFO中的数据。
BOOLEANTranCard::Isr_MyIrq(void)
{if(//中断未产生)
{……
returnFALSE;}
else
{/*如果产生硬件中断,设置命令寄存器,进行突发数据传输*/
returnTRUE;}
}
为了将硬件中断与编写的中断服务程序连接在一起,采用InitializeAndConnect方法,部分代码如下:
NTSTATUSTranCardDevice?押?押OnStartDevice(KIrpI)
{……
status=m_MyIrq.InitializeAndConnect(
pResListTranlated,
LinkTo(Isr_MyIrq),
This;)
……}
2.4驱动程序的调用
编写驱动程序本身不是最终目的,最终目的是调用驱动程序管理资源,并为用户应用程序使用。驱动程序加载以后,它的许多进程处于Idle状态,实际上需要用户应用程序去调用激活。应用程序利用Win32API直接调用驱动程序,实现驱动程序和应用程序的信息交互。
首先用CreateFile()打开设备,获得一个指向设备对象的句柄。使用CreateFile函数时应注意:由于驱动程序是*.sys,所以第一个参数应该是这个设备对象的标志连接(symboliclink)。该标志连接名有一个设置数据文件搜索路径的数字号,而这个数字号通常是零。如果这个连接名是″TranCard″,则传递给CreateFile的宇符串就是:″\\\\.\\TranCard0″。例如:
HANDLEhDevice=CreateFile(″\\\\.\\TranCard0″)GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL?,OPEN_EXISTING,0,NULL);
然后用DeviceIoControl()进行数据的传送。最后用CloseHandle()关闭设备句柄。
下面是应用DeviceIoControl()程序片段。
{……
m_b=DeviceIoControl(hDevice,TRANCARD_IOCTL_
RECEIVE(buffer,sizeof,buffer,NULL,0,&buffersize,NULL);
……}
2.5驱动程序的调试
采用SoftICE、DriverMonitor作为调试工具,基本调试过程如下:(1)使用symbolloader加载驱动程序,然后使用SoftICE跟踪调试,确认驱动程序正常加载;(2)对核心的中断响应程序代码,用SoftICE中的Genint命令产生虚拟中断,单步跟踪中断;(3)硬件发送大量的数据,通过查看内存的数据,确认数据传输是否正确。
关键词:光缆检测;USB;接口;CY7C68013
引言
随着人们对通信的要求越来越高,光通信以其独特的优势而越来越普及,与此同时光缆检测也变得非常重要,为适应对预设光缆线路的可用状态实时监测和管理需求,要求光缆线路监测系统能够对预设通信光缆进行拓扑管理、告警管理、统计分析管理、安全管理、资源管理和系统自维护。
光缆检测系统和计算机之间的接口设计是该系统的一个重要组成部分。RS-232接口曾经取得过巨大成功,但是随着计算机与设备的发展,RS-232串行端口逐渐成为通信的瓶颈。而USB则突破原有接口的限制,不仅具备较高的通信速率,而且其弹性化设计可以取代各种设备所使用的接口,在计算机接口中也占据着越来越明显的优势。
Cypress公司的CY7C68013芯片内部是增强型51单片机,控制简单,并实现了标准的USB1.1和USB2.0协议,而且成本较低,用于光缆检测系统是一个很好的选择,然而,其实现架构较为复杂。本文重点分析和讨论了其固件程序、驱动程序等开发过程,实践表明,本文的方法达到了预期设计目的,效果较好。
光缆检测系统
图1是光缆线路检测硬件模块框图,由DTE接口单元、主控处理单元和PSTN接口单元组成。
DTE接口单元:提供了RS-232接口,USB接口。USB符合1.1和2.0协议。
主控处理单元:是系统的核心模块。主要功能为:从DTE接口单元接收命令,并通过调制解调后发送到远端监测站;从PSTN接口接收远端监测站的信号,解调后发送到DTE。
PSTN接口单元:提供了分别用于轮询和中断两路PSTN标准接口。
本文采用从底层到上层的结构来叙述如何使USB设备完成光缆检测系统和计算机之间数据传输的基本功能。
USB设备接口设计
USB设备接口设计主要包含两方面的内容:USB芯片和光缆检测系统之间的接口;USB芯片和计算机之间的接口设计。其中USB芯片和光缆检测系统之间的接口可分为固件配置程序设计和接口时序设计;USB芯片和计算机之间的接口可分为驱动程序设计以及驱动程序和应用程序之间的通信。
固件配置程序
USB传输类型包括中断传输(interrupt)、批量传输(bulk)、等时传输(iso)、控制传输(control)四种类型,四种类型的相关特性:数据最大长度、数据周期性、发生错误是否重传、可得到的最大带宽等都存在较大区别。根据光缆检测系统和计算机之间数据交互的特点,CY7C68013被配置为slave、异步、bulk模式。图2是固件程序的框架结构,只完成数据读写的功能,不对数据进行任何处理。
要实现最基本的数据读写功能只需要在TD_Init函数中进行配置,由于篇幅原因这里仅列举比较重要的一些寄存器的配置情况(表1)。
这里仅仅配置了端点2和端点6,端点2配置为写设备地址,端点6配置为读设备地址,两个端点都设置为4个缓冲区,缓冲区大小设置为512bytes,两个端口都设置为自动方式,这样设置可以使得读写数据非常方便,大大减少开发时间和复杂性。
接口时序设计
异步slavefifo写时序设计
外部主控器进程如下:
IDLE:当写事件发生时,转到状态1。
状态1:指向IN FIFO,激活FIFOADR[1:O],转向状态2。
状态2:如果FIFO满标志为1(1:FIFO不满;0:FIFO满),则转向状态3,否则停留在状态2。
状态3:传送总线驱动数据。传送一个数据,激活SLWR,转向状态4。
状态4:如果有更多的数据要写,则转向状态2,否则转向IDLE。
实现异步从属FIFO读和实现异步从属FIFO写大同小异,这里不再赘述。
驱动程序设计
驱动程序设计主要包括驱动程序设计、用来安装驱动程序的inf文件设计。Cypress公司为了使用户使用简单,已经完成了大部分工作,用户只需要对其驱动程序和inf文件作一些必要的修改就可以实现需要的功能。用户可以去掉Cypress公司提供的部分不需要的功能,同时需要对USB设备描述符、配置描述符、接口描述符、端点描述符和串描述符进行修改。
固件驱动程序的功能是使计算机认识自己的USB设备,因此需要对设备进行固件程序配置,固件配置程序可以在Cypress公司提供的框架下进行修改,主要是对端点和选择模式相关的寄存器进行配置,然后通过提供的hex2c将生成的十六进制文件转换为一个数组,并将该数组替换驱动程序中的firmware[],用DDK进行编译产生固件驱动程序。计算机通过搜索注册表中的设备VID和PID来识别USB,如果存在EEPROM或者是FLASH,则这个VID和PID可以开发人员自己定制。如果没有EEPROM则VID必须为04b4,PID必须为8613,否则设备将无法被识别。
下载固件驱动程序后,需要下载通用驱动程序,通用驱动程序可以完成需要设备完成的一系列功能。通用驱动程序可以直接使用Cypress公司提供的通用驱动程序。配置的时候VID和PID必须和inf文件中通用驱动程序的VID和PID一致。
lnf文件的编写
所有的USB设备都至少具有一个VID和PID,VID和PID通过设备描述符表提交给Windows系统,同时,Windows系统使用INF文件将某一个VID和PID绑定到某一设备驱动程序。这样,Windows系统在知道了设备的VID和PID后,就通过存储在INF文件中的信息查找该设备的驱动程序。第一次安装后,VID和PID信息就保存在注册表中,以后当该设备重新插上时,系统就会在注册表中很快的查找该设备的驱动程序信息。
固件驱动程序的VID和PID必须为04b4和8613(如果有EEPROM则可以定制),固件驱动程序主要是用来自动加载固件配置;通用驱动程序的VID和PID必须和固件程序中配置的一致;
读写测试的C语言程序
操作设备之前需要安装驱动程序,此时需要把sys文件和inf文件分别拷贝到系统文件夹system32\drivers和inf下,然后依次选择驱动程序目录文件进行安装即可,驱动程序安装成功后就可以对设备进行访问。访问过程通常分为三个阶段:打开设备、操作设备、关闭设备。
打开设备可以通过符号链接名方式,用CreateFile函数可以以同步方式打开设备,获取设备句柄。操作设备通过DeviceIoControl函数可以完成,由于接口时钟不同,所以要用异步方式对设备进行读写,否则设备读写将会出现错误;读取设备时采用直接程序控制方式,即CPU不断查询设备的FULL状态位,当有数据到达时该位变为低电平,CPU就开始读取数据。设备操作完成后通过CloseHandle函数关闭设备句柄。
通用串行总线(Universal Serial Bus,即USB)以其方便的即插即用和热插拔特性,以及较高的传输速率,成为PC领域广为应用的外设连接规范。目前,国内外普遍采用的是USB1.1规范,它支持两种传输速率:1.5Mbps和12Mbps,主要应用在低速传输要求的场合。2000年的USB2.0规范提供了480Mbs的传输速率,以满足更快的数据传输要求。
为了使MPEG视频卡快速地向PC机传送大量的数据,我们在设计MPEG视频卡与PC机的接口时采用USB2.0技术。对USB的设计与开发,我们是基于CYPRESS公司的EZ-USB FX2系列的CY7C68013芯片及其FX2开发包。
1、 硬件设计
传统的采用PCI接口的MPEG视频卡, 不但占用了有限的PCI插槽,安装不方便,而且不支持热插拔和即插即用。所以,在本设计中,我们选用USB2.0接口芯片对传统的MPEG视频卡进行了改进。
改进后的USB2.0接口的方案如图1所示。
该USB2.0接口的MPEG视频卡的工作原理为:音视频信号经AK4550音频处理芯片及AA7113视频处理芯片进行A/D转换,将模拟信号转换成8bit的PCM格式的数字信号,传入SZ1510音视频压缩采集芯片进行处理,将编码调制PCM格式的数据转化为符合格式MPEG-1的混合影视文件,最后MPEG-1数据经USB接口芯片送给PC机作进一步的处理,如存储、显示等。
设计中,我们选用的USB接口芯片是EZ-USB FX2 系列的CY7C68013芯片。该芯片是针对USB2.0的,而且和USB1.1兼容,它支持两种传输速率:全速(Full_speed)12Mbps和高速(High_speed)480Mbps,它不支持低速(Low_speed)1.5Mbps。该芯片的内部结构如图2所示。
CY7C68013-128AC内部集成了一个增强的8051内核,它既与标准的8051兼容,又有诸多的改进:最高工作频率48MHZ,一个指令周期只需4个时钟周期,比标准的8051平均提高了2.5倍;2个UARTS端口;3个定时/记数器;扩展的中断系统及其更多I/O口等。CY7C68013内部集成的USB2.0的SIE能完成大部分USB2.0协议的处理工作,减少了用户对繁杂的USB协议的处理。另外,用户在开发时,可以利用GPIF和FIFO方式实现与高速外围设备之间的逻辑连接,并进行高速数据的传输。在该改进方案中,我们选用的是GPIF方式,实现和Z1510之间的通信。
2、 软件设计
USB 软件设计包括三方面的工作:固件(Fireware)设计,驱动程序设计和主机端应用程序的设计。
(1) 固件设计
设计中,我们考虑到MPEG视频卡要求快速地持续地传送大量数据,并对数据的完整性要求不太高,我们采用ISO传输方式。另外,我们让CY7C68013工作在GPIF模式下的FIFO Read方式,最多可以传输4G byte(WORDWIDE=0)或word(WORDWIDE=1)。外设的数据由于不需8051的处理,我们采用自动打包的方式(AUTOIN=1),直接从FIFO到SIE,这样有利于提高传输速率。其主要实现代码如下:
void TD_Init( )
{
CPUCS = 0X01;
file://CLKSPD[1:0]=10; for 48MHz operation.
GpifInit( );
……
SYNCDELAY;
EP6CFG = 0XDA;
file://端点配置: 同步IN方式、缓冲大小1024字节
SYNCDELAY;
FIFORESET = 0X80;
// activate NAK_ALL to avoid race conditions
SYNCDELAY;
FIFORESET = 0X06; file://reset, FIFO 6
SYNCDELAY;
FIFORESET = 0X00; file://deactivate NAK_ALL
SYNCDELAY;
EP6FIFOCFG = 0X0D; file://wordwide=1
SYNCDELAY;
……
}
(2) 驱动程序设计
在WINDOWS平台下,USB 驱动程序由三部分组成:USB设备驱动程序,USB总线驱动程序和USB主控制器驱动程序,它们必须遵循WIN32驱动程序模型(WDM)。其中,WINDOWS操作系统已经提供了处于驱动程序栈底的USB总线驱动程序和USB主控制器驱动程序。而USB设备驱动程序由设备开发者编写,它通过向USB总线驱动程序发送包含URB(USB Request Block)的IRP(I/O Request Packet),来实现USB外设之间的信息交换。当主机应用程序要对USB设备进行I/O操作时,它调用Windows API函数对Win32子系统进行Win32调用,由I/O管理器将此请求构造成一个合适的IRP,并把它传递给USB设备驱动程序。USB设备驱动程序接受到这个IRP后,根据IRP中包含的具体操作代码,构造响应的URB并把它放到一个新IRP中,然后把此IRP传递到USB总线驱动程序,USB总线驱动程序根据IRP中所包含的URB执行响应的操作,并把操作结果通过IRP返还给USB设备驱动程序。USB设备驱动程序接受到此IRP后,将操作结果通过IRP返还I/O管理器。最后,I/O管理器将此IRP中操作结果返还给应用程序,至此应用程序对USB设备的一次I/O操作完成。
开发USB设备驱动程序,可采用Numega公司的开发包Driver Works和 Microsoft公司的2000DDK,并以VC++6.0作为辅助开发环境。Driver Works提供的驱动向导,,可根据用户的需要,自动生成代码框架。减少了开发的难度,缩短了开发的周期。
在CYPRESS公司的EZ-USB FX2开发包中,有一个通用的驱动程序,该程序可不加修改经DDK编译后直接使用。在本设计中,由于时间关系,我们采用的就是这个通用驱动程序(GPD)。
(3) 应用程序设计
USB主机应用程序是计算机中完成特定功能的程序,其关键是实现从USB 外设读取或发送特定数量的数据,USB标准设备请求和特定的命令等。另外,可以对数据做进一步的处理,如:存储、显示、快速傅立叶变换等。在WINDOWS 2000下,我们所使用的应用程序开发工具是VC++6.0。
关键字:JDBC;数据库;MySql
Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成。JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序。然而各个开发商的接口并不完全相同,所以开发环境的变化会带来一定的配置变化。
一、连接各种数据库方式速查表
下面罗列了各种数据库使用JDBC连接的方式,可以作为一个手册使用。
1. Oracle8/8i/9i数据库(thin模式)
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID
String user="test"; String password="test";
Connection conn= DriverManager.getConnection(url,user,password);
2. DB2数据库
Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
String url="jdbc:db2://localhost:5000/sample"; //sample为你的数据库名
String user="admin"; String password="";
Connection conn= DriverManager.getConnection(url,user,password);
3. Sql Server7.0/2000数据库
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb";String user="sa"; String password="";
Connection conn= DriverManager.getConnection(url,user,password);
4. Sybase数据库
Class.forName("com.sybase.jdbc.SybDriver").newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB为你的数据库名
Properties sysProps = System.getProperties();
SysProps.put("user","userid");
SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);
5. MySQL数据库
Class.forName("org.gjt.mm.mysql.Driver").newInstance(); String url="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB 为数据库名
Connection conn= DriverManager.getConnection(url);
6. access数据库直连用ODBC的
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};DBQ="+application.getRealPath("/Data/ReportDemo.mdb");
Connection conn = DriverManager.getConnection(url,"","");
Statement stmtNew=conn.createStatement() ;
二、JDBC连接MySql方式
下面是使用JDBC连接MySql的一个小的教程
1. 查找驱动程序
MySQL目前提供的java驱动程序为Connection/J,可以从MySQL官方网站下载,并找到mysql-connector-java-3.0.15-ga-bin.jar文件,此驱动程序为纯java驱动程序,不需做其他配置。
2. 动态指定classpath
如果需要执行时动态指定classpath,就在执行时采用-cp方式。否则将上面的.jar文件加入到classpath环境变量中。
3. 加载驱动程序
trClass.forName(com.mysql.jdbc.Driver);
System.out.println(Success loading Mysql Driver!);
}catch(Exception e){System.out.println(Error loading Mysql Driver!);e.printStackTrace();}
4. 设置连接的url
jdbc:mysql://localhost/databasename[?pa=va][&pa=va]
三、以下列出了在使用JDBC来连接Oracle数据库时可以使用的一些技巧
1. 在客户端软件开发中使用Thin驱动程序
在开发Java软件方面,Oracle的数据库提供了四种类型的驱动程序,二种用于应用软件、applets、servlets等客户端软件,另外二种用于数据库中的Java存储过程等服务器端软件。在客户机端软件的开发中,我们可以选择OCI驱动程序或Thin驱动程序。OCI驱动程序利用Java本地化接口(JNI),通过Oracle客户端软件与数据库进行通讯。Thin驱动程序是纯Java驱动程序,它直接与数据库进行通讯。为了获得最高的性能,Oracle建议在客户端软件的开发中使用OCI驱动程序,这似乎是正确的。但我建议使用Thin驱动程序,因为通过多次测试发现,在通常情况下,Thin驱动程序的性能都超过了OCI驱动程序。
2. 关闭自动提交功能,提高系统性能
在第一次建立与数据库的连接时,在缺省情况下,连接是在自动提交模式下的。为了获得更好的性能,可以通过调用带布尔值false参数的Connection类的setAutoCommit()方法关闭自动提交功能。
3. 在动态SQL或有时间限制的命令中使用Statement对象
在执行SQL命令时,我们有二种选择:可以使用PreparedStatement对象,也可以使用Statement对象。无论多少次地使用同一个SQL命令,PreparedStatement都只对它解析和编译一次。当使用Statement对象时,每次执行一个SQL命令时,都会对它进行解析和编译。这可能会使你认为,使用PreparedStatement对象比使用Statement对象的速度更快。然而,我进行的测试表明,在客户端软件中,情况并非如此。因此,在有时间限制的SQL操作中,除非成批地处理SQL命令,我们应当考虑使用Statement对象。
【摘要】 我们从软件技术的角度,论述了在Windows XP环境下基于PCI总线数据采集卡实现实时测控所需要的关键技术、软件体系结构和开发方法。遵循本文所讨论的技术路线,开发了DFQ系列多方位牵引床的测控软件,提高了被控系统的控制精度和可靠性,增强了系统的可用性。
【关键词】 PCI总线;WDM设备驱动程序;软件体系结构;计算机测量与控制
Abstract:The key techniques, software architecture and development method used to implement real-time measurement and control based on PCI bus data acquisition card in Windows XP environment are discussed from the viewpoint of software technology. The measurement and control software for DFQ multidimensional traction bed are developed according to the techniques provided in this paper,the precision, high reliability and better usability of the object system are improved.
Key words:PCI Bus;WDM device driver;Software architecture;Computer measurement and control
1 引 言
计算机测控技术在生产实践中有着广泛的应用。基于计算机技术的测控系统主要分为两种类型。一类是以各种单片机、可编程逻辑芯片为核心组成的测控系统,这类测控系统一般适用于功能要求相对简单的被控对象,可独立构成测控系统,或以PC机作为上位机构成两级级联的测控系统,此时PC机一般负责界面处理。一类是以PC机为核心构成的测控系统,PC机通过数据采集卡及接口电路连接到被控对象。由于PC机具有高性能、易用性、可扩展性和丰富的软件资源等,此类系统可适用于功能要求较为复杂的被控对象。
Windows XP是一个多任务的并能够满足实时要求的操作系统,是目前PC机普遍采用的操作系统之一。PCI总线是高性能的局部总线,支持高速数据传输,是PC机上流行的总线接口标准。我们从软件技术的角度,讨论了在Windows XP操作系统下,基于PCI总线数据采集卡,在工业现场实现实时数据测控的关键技术,包括实时I/O端口读写和定时数据采集的实现方法。本研究的技术已成功应用于DFQ多方位牵引床的软件研发,取得了良好的效果。由于是在Windows XP操作系统下采用实时测控技术,最终设计完成的牵引床系统功能丰富,控制精确,可靠性高,具有良好的用户界面。
2 系统的关键点和技术难点
Windows XP是一个多用户、多任务的操作系统。由于允许多个任务并发执行以及允许多个用户同时登录操作系统,安全性和稳定性是Windows XP操作系统设计的主要目标之一。在Windows XP操作系统下,计算机的运行状态被强制为用户态和核心态两种状态。对于一个程序,在一个确定的时刻,要么在用户态执行,要么在核心态执行。在用户态运行的程序处于系统最低的中断请求级(interrupt request level,IRQL)上,随时可以被具有更高中断请求级的中断请求所打断[1]。因此,为了能够在给定的时间约束内发出控制信号和采集数据,满足系统的实时性要求,提高系统可靠性,必须使得测控程序能够在核心态执行。
其次,为了满足自身的稳定性,Windows XP将对硬件的访问封装在了系统底层。用户态的应用程序不能直接访问硬件资源,包括读写I/O端口和内存,响应中断,执行DMA操作等。在Windows XP下,程序只有转入核心态,并通过系统调用才能直接访问硬件资源。显然,若能够获得直接访问硬件的能力,则可明显提高测控程序的实时性和效率。
综上所述,在Windows XP操作系统下,测控软件要获得本质上的实时性和高可靠性,必须具有在操作系统核心态运行的能力。设备驱动程序是Windows XP留给用户的允许用户获得核心态运行能力的唯一开发接口[1]。WDM(windows driver model)驱动程序模型是Windows XP下的设备驱动程序的模型之一,测控软件可借助WDM驱动程序实现所要求的实时性和高可靠性。
3 系统组成和开发环境
如图1所示,牵引床控制系统由PC机、PCI总线数据采集卡、外围接口电路和牵引床四部分组成[2]。PCI总线数据采集卡是通用的标准模块,可供选择的产品很多,本系统使用凌华公司的PCI 9111数据采集卡[3]。接口电路完成模拟信号和数字信号的调理和传输。
系统测控程序由上层主程序和下层设备驱动程序两部分组成。主程序完成系统的总体逻辑功能和界面交互,运行于操作系统的用户态。设备驱动程序采集数据,完成牵引床的各种基本控制动作,运行于操作系统的核心态。主程序和驱动程序之间通过事件通知的机制完成通信联络,驱动程序向下调用操作系统的系统服务完成基本控制动作。
软件开发环境由Windows XP DDK(Driver Develo
pment Kit)、DriverStudio 3.1和Visual C 6.0组成。Visual C 6.0是系统主程序和驱动程序的集成开发调试环境,DriverStudio 3.1和Windows XP DDK用于编译生成驱动程序。
4 测控程序设计
我们本节论述测控程序设计的几个关键问题,包括访问PCI 9111数据采集卡,读写I/O端口,定时中断的实现方法和主程序与驱动程序的通信共四部分。
4.1 访问PCI 9111数据采集卡
PCI 9111是一块集成的多功能数据采集卡,具有数字量输入输出、模拟量输入输出、定时计数的基本功能,支持软件查询方式、中断方式、DMA方式多种数据传输方式,AD采样频率最高支持100 KHz。PCI 9111板卡上使用PCI 9052[4]作为PCI总线接口芯片,支持PnP即插即用功能,用户无需手工设置板卡使用的硬件资源(如IO基地址、中断请求号等),这些硬件资源由计算机的PnP子系统自动分配。用户通过基地址BASE加偏移量的IO端口读写方式,访问PCI 9111的各寄存器,实现对PCI 9111的控制命令写入和数据输入输出。因此,要访问PCI 9111,必须首先要获得PnP子系统分配给PCI 9111的基地址。
根据PCI总线规范,PnP子系统分配给PCI设备的基地址,存储在PCI接口芯片的BAR0~BAR5共六个PCI配置寄存器(PCI configuration registers,PCRs)中。对于PCI 9111板卡而言,BAR1中存储的是PCI 9052芯片局部配置寄存器(local configuration registers,LCRs)的起始地址,BAR2中存储的是局部地址空间0的基地址,即PCI 9111板卡寄存器的基地址BASE。
PnP子系统为PCI设备分配的硬件资源,由操作系统的PnP管理程序通知给PCI设备的设备驱动程序。在DriverStudio的WDM设备驱动程序框架下,该信息以IO请求包(Irp)的形式传递给驱动程序设备类(是KPnpDevice的子类)的OnStartDevice()成员函数。在OnStartDevice()函数中,通过如图2中的代码,可获得BAR1寄存器和BAR2寄存器的值。
NTSTATUS DfqDevice::OnStartDevice(KIrp I)
{
……
PCMRESOURCELIST pResListRaw=I.AllocatedResources();
PCMRESOURCELIST pResListTranslated=I.TranslatedResources();
KPciConfiguration PciConfig(mLower.TopOfStack());
//BAR1
mIoLCR.Initialize(pResListTranslated, pResListRaw,
PciConfig.BaseAddressIndexToOrdinal(1));
//BAR2
mIoPortRange.Initialize(pResListTranslated, pResListRaw,
PciConfig.BaseAddressIndexToOrdinal(2));
……
}
图2 初始化mIoLCR和mIoPortRange
Fig 2 Initialization of mIoLCR and mIoPortRange
在图2所示的代码中,mIoLCR和mIoPortRange都是DfqDevice类的KIoRange类型的成员变量。图2所示代码实际上是使用BAR1和BAR2寄存器的值分别对mIoLCR和mIoPortRange进行了初始化。mLower是DfqDevice类的KPnpLowerDevice类型的成员变量,该成员变量指向代表PCI设备的底层物理设备对象。
4.2 读写IO端口
一旦初始化mIoPortRange和mIoLCR,进行IO端口读写就非常容易。使用KIoRange类的成员函数inx()/outx(),可完成对指定端口的读写,其中x可为b、w、d,分别表示8位数据、16位数据和32位数据。于是,调用m_IoPortRange对象的IO读写成员函数,可访问PCI 9111板卡的各寄存器;调用mIoLCR对象的IO读写成员函数,可访问PCI 9052芯片的各局部配置寄存器。参照PCI 9111的用户手册[3],就可以方便地完成PCI 9111数据采集卡的数字量输入、数字量输出、软件查询式AD转换和模拟量输出功能。
4.3 定时中断
对于实时过程监控,最为关键的是能够定时检测被控对象的状态,一旦达到预定义的条件,则发出相应的控制命令。这就需要设备驱动程序能够提供精确的定时中断。
PCI 9111板卡上提供了8254定时/计数器,可用于实现定时中断。通过编程设置PCI 9111,可令8254定时/计数器的输出作为中断源发起定时中断请求。在中断服务程序内,可以完成AD数据采集(从而实现定时中断式AD转换)、数字量数据输入输出等各种定时执行的任务。对于中断式AD转换,也可以编程设置PCI 9111,令8254定时/计数器的输出作为AD转换触发信号,而AD转换器的AD转换结束信号作为中断源发起中断请求。由于AD转换器是定时触发,此时亦可实现定时中断式AD转换。
要使得驱动程序能够响应来自PCI 9111的硬件中断,首先需要编写在设备类里的中断服务程序链接到PnP子系统,分配给PCI 9111的中断请求号(IRQ)上。代码见图3。
NTSTATUS DfqDevice::OnStartDevice(KIrp I)
{
……
mInterrupt.InitializeAndConnect(pResListTranslated, LinkTo(ISR), this);
……
}
图3 链接中断服务程序到系统分配的中断请求号
Fig 3 Link interrupt service routine to interrupt request number of
system distribution
图3的代码中,mInterrupt是定义在DfqDevice类中的KInterrupt类型的中断对象。ISR是DfqDevice类的成员函数,即实际的中断服务程序。
由于Windows XP是一个多任务的操作系统,在编写中断服务程序时,要考虑留给其他程序执行的机会,因此,在中断服务程序中,通常完成当前最为紧迫的任务。由于多个物理设备可能共享同一个中断请求号,因此在中断服务程序中,首先判断所响应的中断请求是否来自PCI 9111。若不是,则立即返回,以节省时间。然后清除硬件中断,以便下一次中断请求能够正常产生(而不被阻塞)。然后针对具体被控对象的定时执行的任务。
在DFQ牵引床控制软件中,编程使PCI 9111板卡的8254定时技术芯片每160 μs产生一次中断。在每次中断中完成AD数据采集和数字量输入,检测当前动作的执行情况。当AD采样值达到主程序设定要求时,即牵引床动作到位,中断服务程序及时发出动作结束信号。牵引床的每个动作的执行都在频率为6 KHz的AD采样监视之下完成。首先,由于AD采样频率高,牵引床动作(如距离、角度等)的执行非常精确。牵引床动作的实际误差基本不受测控软件的影响,而主要取决于牵引床本身的机械结构所带来的误差。其次,由于牵引床的动作控制信号是在设备驱动程序中发出的,而设备驱动程序具有比任何Windows线程更高的中断请求级(IRQL),牵引床工作的可靠性明显提高。在连续长时间的测试以及大量用户的反馈中,牵引床系统几乎没有出现错误动作。
值得提出的是,由于PCI 9111的AD转换频率最高可达100 KHz,因此在实际使用中,8254的定时常数可以设置得比160 μs更低,如十微秒级,这样可以完成对于更加快速控制过程的实时监控。另外,在许多系统中,人们也使用Windows提供的软件定时器或编写已有驱动程序的回调函数实现过程监控,但这并不能从根本上满足实时要求。其原因为:(1)软件定时器工作在用户态,不具有严格的实时性。(2)由于受Windows操作系统线程调度模型的制约,软件定时器和回调函数只能实现毫秒级或十毫秒级的定时,不能满足高速的实时测控要求。因此,设备驱动程序设计的方法保证了数据采集和过程监控的实时性、高精度和可靠性。
4.4 主程序和设备驱动程序的通信
主程序和设备驱动程序是功能相对独立的两个程序,它们之间通过通信联络完成控制命令和数据的传输。主程序和设备驱动程序之间通信的典型方法有异步IO、事件通知等[3,5]。DFQ牵引床系统采用事件通知的方法完成主程序和设备驱动程序之间的通信。
在此,以牵引床的一个基本动作的执行过程为例,说明主程序和设备驱动程序之间的通信。首先,主程序调用SDK函数 CreateEvent(NULL, FALSE, FALSE, NULL)创建事件句柄hEvent,其中第二个参数FALSE表示所创建的事件为自动重置事件,第三个参数FALSE表示事件的初始状态为无信号状态。然后主程序调用SDK函数DeviceIoControl()向设备驱动程序发出控制命令,命令参数中含有事件句柄hEvent。最后,主程序调用SDK函数WaitForSingleObject()等待事件hEvent变为有信号状态,从而主程序线程进入阻塞状态。设备驱动程序在控制命令处理函数中通过new(NonPagedPool) KEvent(hEvent, OBJECTTYPEALLACCESS)创建KEvent类对象pEvent,然后启动动作执行,并中断对动作进行定时监控。当检测到动作执行到位(或遇到异常情况中止)后,设备驱动程序调用pEvent->Set()将事件对象hEvent设置为有信号状态。此时主程序线程作系统唤醒,继续向下执行。主程序可进一步访问设备驱动程序获得动作的执行情况以做出相应的处理。
事件通知的方法,在保证牵引床动作执行的实时性、可靠性和精确性的同时,还符合多任务系统的设计原则,主程序和设备驱动程序并不会持续长时间独占CPU而影响计算机整体性能。这是因为:(1)在牵引床动作执行期间,主程序因调用WaitForSingleObject()而一直处于阻塞状态,并没有获得执行。(2)在牵引床动作执行期间,设备驱动程序通过定时中断的方法,只是每隔设定的一段时间(在牵引床系统中设置为160 μs),检测一次动作的执行情况,设备驱动程序也没有在动作执行期间独占CPU。这样,CPU就会有充足的时间执行其他的程序。于是,可在主程序中进一步使用多线程技术,实现更为复杂的逻辑控制功能。如牵引床的快速牵引、复合牵引等各种治疗功能就是使用多线程技术实现的。
5 结束语
本研究从操作系统底层的角度,对Windows XP操作系统的实时测控技术进行了研究和探讨。通过WDM设备驱动程序设计的方法,使程序获得在系统核心态执行的能力,从而实现实时过程监控。以DFQ牵引床系统为例,剖析了在Windows XP操作系统下,基于PCI总线数据采集卡进行实时过程监控的关键技术。遵循本文的技术路线,我们设计了DFQ牵引床系统的测控软件,产品质量检测和实际应用均表明,DFQ牵引床工作可靠性高,动作完成精确到位,测控软件具有良好的易用性。本研究所论述的实时测控技术可适用于一般的控制系统。
参考文献
[1]尤晋元,史美林.Windows操作系统原理[M]. 北京:机械工业出版社,2001.
[2]刘传永,张明,王艳萍,等.双中心重合式脊柱治疗机的研制[J].生物医学工程研究,2006,25(1):55-57
[3]ADLINK Technology.PCI-9111 DG/HR multi-functions data acquisition card User's guide[EB/OL].adlinktech.com/PD/Download/adlinktechnology-index.php.2008-01-10.
[4]武安河,邰铭,于洪涛.Windows 2000/XP WDM设备驱动程序开发[M]. 北京:电子工业出版社,2003.
由于工作关系,我经常涉及PC机与设备接口的工作,从PC机这方面要做的工作看来,主要是通过接口处理设备的中断,通过I/O端口或内存地址与外设互相传递数据。从计算机原理的角度看,所要达到的目的很简单,那么如何编写程序完成上述功能呢?
目前国内流行的PC操作系统有三种:DOS,Win95/98系列,WindowsNT。DOS是单用户、单任务操作系统,由于PC机硬件处理速度不断提高,基于单用户、单任务的操作系统越来越不能充分发挥硬件的功能,现在只应用于一些老式PC及其它个别场合,有逐渐被淘汰的趋势;Win95/98系列和WindowsNT属于多任务操作系统,不论从其原理还是界面上看,这两种操作系统都比DOS有着无可比拟的优越性,这两种操作系统虽然在界面和操作上及其相似,但其内部实现的诸多方面有许多区别,有些区别是本质上的。Win95/98设计目标是针对一般家庭用户,安全性及可靠性存在许多薄弱环节,就可靠性而言,Win95/98系列不能很好的防止多任务环境中某个进程的非法操作导致系统中其它程序甚至整个系统的崩溃,而WindowsNT在这方面及其它诸多方面设计的相当严谨。这两种操作系统是Microsoft公司同一时期的产品,但针对不同的使用群,所以在一些重要场合及生产实践中应该选择WindowsNT作为计算机的操作系统,此外,从发展趋势来看,WindowsNT已经成为定型产品,具有相对稳定性。
在不同操作系统下编写驱动程序是有很大区别的,在DOS平台上,应用程序和设备驱动程序之间没有标准的接口,它们在外部表现为一个扩展名为EXE的文件,驱动程序的作用被柔和在应用程序中,这样,应用程序为了使用不同厂商的同一类设备,必须了解这些设备在接口上具体的硬件实现,同时,对于一个特定型号的硬件产品,所有支持它的应用软件中对于控制整个设备动作的这部分代码,可能被多次重写。这种情况不适应硬件及应用软件的飞速发展。Windows系统在这方面,进行了根本性改进,把控制设备动作的这部分代码独立出来,提出了设备驱动程序的概念,驱动程序是应用程序和硬件设备之间的一个桥梁,应用程序与驱动程序之间有明确的接口,应用程序通过与驱动程序交换信息,达到控制外设的目的。接口定义的操作是面向设备的,这就是说,在应用程序的设计中,并不用关心对外设操作的具体硬件实现,只是对驱动程序发出一系列指令既可;驱动程序接受来自上层应用程序的指示,具体操纵实际硬件,完成用户功能。具体实现上,Win95/98系列与WindowsNT又有所区别,WindowsNT是严格按照上述思路设计的;而Win95/98系列不那么严格,其支持上述思路,但同时应用程序也可以绕过驱动程序直接访问实际物理I/O,这样做,增加程序设计的灵活性,但同时,对系统可靠性造成一定隐患。这也正是Win95/98系列可靠性低于WinNT的原因之一。
WindowsNT设备驱动程序的组成原理
WindowsNT操作系统结构分为用户模式和内核模式,用户模式下的编程为应用程序的设计,而开发设备驱动程序,则属于内核模式下的编程,内核模式组件包括NTExecutive(ExXxx),内核(KeXxx),硬件抽象层(HalXxx)。其层次如图2-1所示,其中NTExecutive包括几个独立的软件组件,它们是系统服务接口(ZwXxx),对象管理器(ObXxx),配置管理器,进程管理器(PsXxx),安全监视器(SeXxx),虚拟空间管理器(MemXxx),本地进程调用,I/O管理器(IoXxx)。内核模式的系统服务并不是全部公开的,而是提供了一系列开发设备驱动程序需要的函数(上文括号内为函数形式,函数手册参见[2]Kernel-ModeDrivers-Reference章节),换言之,这些函数功能是所有内核模式的系统服务功能的子集。
驱动程序由一系列相对独立的函数组成,由I/O管理器根据需要调用这些函数,对于一个需要处理中断的最简单的驱动程序也需要由以下几个函数构成:
1.DriverEntry()运行于PASSIVE_LEVEL
驱动程序入口点,当驱动程序被手动或自动装入系统后,驱动程序从这点开始执行,主要用于定位硬件资源,建立指向其它驱动程序函数的指针等其它初始化工作。
2.XxUnload()运行于PASSIVE_LEVEL
用于驱动程序从系统卸出之前,释放由驱动程序占用的所有系统资源。
3.XxIsr()运行于DIRQL
中断服务程序。
4.XxDpcForIsr()运行于DISPATCH_LEVEL
中断服务程序后处理程序,以排队方执行不太关键代码的执行,由于排队机制及优先级,不会造成代码拥塞从而提高中断服务程序的响应并且提高系统总体I/O吞吐率。
5.XxOpen()运行于PASSIVE_LEVEL
处理应用程序Win32函数CreateFile()请求。
6.XxClose()运行于PASSIVE_LEVEL
处理应用程序Win32函数CloseHandle()请求。
7.XxDispatch()运行于PASSIVE_LEVEL
处理应用程序Win32函数DeviceIoControl()请求,通过一系列自定义命令,驱动程序与应用程序交换特定的信息。
WindowsNT使用一个抽象化的CPU优先级方案,IRQL代表中断请求级,任一时刻CPU总处在某一级上,这个数越大,表示当前的任务重要性越大,如表2-1所示,从上至下IRQL越来越小。所有上述驱动程序的函数及内核模式函数都必须运行于各自的IRQL级上,如果违反这一调用规定,会造成系统崩溃。例如,中断服务程序(XxIsr)运行于DIRQL及上,那幺在编写中断服务程序时,只能调用允许在这一级运行的内核模式函数(并不是所有内核模式函数都能运行于DIRQL级)。至于每个内核模式函数运行级别的说明,详见[2]Kernel-ModeDrivers-Reference章节。
WindowsNT是一多任务系统,许多设备的驱动程序同时存在系统中,这样各个设备所占用的资源(中断,I/O及RAM地址空间)很有可能冲突,如果设备驱动程序在运行之前不进行‘探测’而使用自己硬件设备的资源,有可能和系统内其它设备占用的资源冲突,后果不堪设想。WindowsNT通过注册表管理硬件资源的占用信息,作为内核模式信任的组件,驱动程序使用硬件资源之前必须遵循‘查询-申请-使用-释放’的原则
WindowsNT设备驱动程序的编写步骤与实例
现以一实际例子简要说明设备驱动程序的开发步骤,本例以CINRAD天气雷达测试卡实际应用为原型,加以简化、抽象。
第一步,了解被控设备的接口情况。
本例为一ISA卡,占用PC机9号中断,I/O地址360H及RAM地址D0228H分别一个字空间。
第二步,确定驱动程序的功能。
驱动程序每当9号中断达到时,检查运行标志变量RunFlag(为一BOOL变量),如果等于TRUE,中断累积计数器counter(为一unsignedshort变量)增一,把这个值写入RAM地址D0228H,再从这个地址读出,如果读出值等于写入值,把这个值写入I/O地址360H,这个地址的内容会驱动板卡上的LED显示,把写入值显示出来;如果读出值不等于写入值,设置运行标志变量FALSE。如果运行标志变量等于FALSE,什幺也不做,返回。
第三步,定义驱动程序与应用程序的软件接口。
本例定义两个接口命令:
IOCTL_IOCardA_START:应用程序设置驱动程序内部的运行标志变量等于TRUE。
IOCTL_IOCardA_READ:应用程序查询驱动程序内部的中断累积计数器的值。
第四步,画流程图。这里列举本例实现的几个主要流程图,(图略)。
系统传给驱动程序入口函数系统定义的‘设备驱动对象’DrObj,通过初始化这个对象的一些成员变量,把驱动程序其它函数与这个对象联系起来。
ISA卡为非即插即用设备,事先把资源占用信息手工添加注册表如下:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IOCardA\parameters]
"IRQ"=dword:00000009
"IOSPAN"=dword:00000004
"IOAdd"=dword:00000360
"RAMAdd"=dword:000d0228
"RAMSPAN"=dword:00000002
其中IOCardA以下各子键及其值为自定义,设备驱动程序利用相应函数检索出这些值。
(3)每个设备驱动程序可以创建若干系统定义的‘设备对象’,本例根据需要只创建了一个‘设备对象’Dev。‘设备对象’其中一个成员变量为指向一非分页的物理内存块DeviceExtension,这块内存大小及内容为用户自定义,由于Dev或DeviceExtension对象会被系统传给驱动程序的其它函数,这样驱动程序各函数通过访问这块内存区,实际上达到互相传递信息的功能。本例在这里存储设备硬件资源信息及RunFlag和中断计数器counter,这些数值在DriverEntry()初始化后,供驱动程序的其它函数使用。
图3-2为中断服务程序IOCardAIsr()流程图。操作系统接受中断,连同DeviceExtension等参数传给中断服务程序,中断服务程序利用这些参数,实现要求功能。
图3-3为IOCardADispatch()流程图,这个函数用于处理来自上层应用程序的命令。上层应用程序通过以下程序段设置驱动程序中RunFlag值为TRUE,从而启动中断服务程序开始计数。
BOOLcmd=TRUE;
hTest=CreateFile(...);//打开设备
DeviceIoControl(hTest,//设备句柄
IOCTL_IOCardA_START,//命令
&cmd,sizeof(BOOL),//输入缓冲区地址及大小
NULL,0,&c,NULL);
CloseHandle(hTest);//关闭设备
上层应用程序通过以下程序段查询当前的中断计数器的值并存于变量w中。
unsignedshortw;
hTest=CreateFile(...);
DeviceIoControl(hTest,
IOCTL_IOCardA_READ,//命令
NULL,0,
&w,sizeof(unsignedshort),//输出缓冲区地址及大小
&c,NULL);
CloseHandle(hTest);
其中DeviceIoControl()执行后,操作系统调用IOCardADispatch()函数,如流程图所示,这个函数内部通过一个开关语句,根据命令执行相应的分支。驱动程序与应用程序通过此函数接换数据时,操作系统提供4种可选数据缓冲方式,本例由于数据I/O量比较小,故选用‘缓冲I/O’(METHOD_BUFFERED)。过程是,I/O管理器首先分配一个非分页池,它的大小为调用者输入缓冲区和输出缓冲区的较大者,第一段程序为sizeof(BOOL),第二段程序为sizeof(unsignedshort),它的地址存到IRP(I/O请求包)的AssociatedIrp.SystemBuffer域中,然后把输入数据拷贝到这个池中,在第一段程序中cmd的值TRUE被拷贝到池中,这样驱动程序通过RtlCopyBytes()函数再把池中的值拷贝到驱动程序的RunFlag中。IOCardADispatch()函数执行完,I/O管理器把池中的内容拷贝到调用者的输出缓冲区,在第二段程序中,驱动程序通过RtlCopyBytes()函数把counter的值拷贝到池中,从而最终传递到应用程序变量w中。
第五步,编程。在编写设备驱动程序的同时,要编写一个简单的应用程序用于测试设备驱动程序的一些功能。
第六步,驱动程序的载入。
驱动程序C语言源程序经过编译、连接生成扩展名为SYS的文件,本例为IOCardA.sys,把这个文件拷贝到\WINNT\system32\drivers\系统目录下,同时手工添加如下信息到注册表:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\IOCardA]
"ErrorControl"=dword:00000001
"Start"=dword:00000003
"Type"=dword:00000001
要保证IOCardA子键名与驱动程序文件名一致,其中Type=1表示此驱动程序为内核模式驱动程序,Start=3表示此驱动程序手动载入,ErrorControl=1表示当驱动程序发生错误时,日志记录错误并显示一个消息框。这样当Windows重新启动后,通过使用控制面板中的Device小应用程序,从列表中找到IOCardA设备名,按Start按钮,于是,设备驱动程序就驻留内存并在底层开始工作了。
第七,调试。设备驱动程序没有界面,完全在系统底层运行,为了观察驱动程序的运行状态,WindowsNTDDK提供windbj.exe程序用于设备驱动程序的调试,调试设备驱动程序需要两台CPU体系结构完全相同的计算机,一台为‘宿主机’,运行windbj.exe程序,另一台为‘目标机’,运行设备驱动程序,两台计算机用串口线连好,进行一系列软件设置(参见[1]第17章),就可以开始调试了,从‘宿主机’可以控制及观察‘目标机’上驱动程序的运行情况。最常用的调试手段是在驱动程序中必要的位置加入DbgPrint()函数,这个函数可以把指定信息输出到‘宿主机’windbg.exe窗口中,通过分析这些信息,可以了解驱动程序当前的运行情况。
结束语
WindowsNT是一个复杂而严密的系统,驱动程序的开发不可避免的涉及现代操作系统理论及其它许多计算机理论,内涵相当广泛,本文围绕着开发实践从一定深度探讨了WindowsNT设备驱动程序开发最基本的知识及一般方法,希望对读者有所帮助,对于复杂,特殊应用的实现及编程技巧,有待于读者在各自实际应用中不断探索。
参考文献
【关键词】ARM;矩阵键盘;linux驱动;TQ2440
1.引言
ARM微处理器已广泛应用于工业控制、消费类电子产品、通信系统等领域。矩阵键盘是一种常用的键盘形式,它将按键设计成M行N列,这样共需M+N根信号线,却可驱动M×N个按键,大大节约了I/O资源。本文介绍了一种利用TQ2440开发板的GPIO口扩展5×4矩阵键盘的方法,并将所有按键重新布局成手持终端的键盘形式,方便操作。
2.硬件设计
本设计扩展5行4列的矩阵键盘,如图1所示。其中行线ROW1-ROW5连接S3C2440的中断引脚EINT8,EINT9,EINT11,EINT13,EINT14[1]。这些中断引脚本身连有10kΩ的上拉电阻,把中断引脚电平拉高,确保按键空闲时不会触发中断。列线COL1-COL4连接S3C2440的普通I/O口GPF3,GPF4,GPG7,GPG10。这里需要注意的问题是:确保行线所用的中断在Linux的其他设备中均未使用到,否则会引起该驱动程序或其他驱动程序初始化失败。
图1 5×4矩阵键盘电路原理图
考虑到手持终端设备按键的常用性与操作的方便性,只取矩阵键盘的前18键,并将它们重新布局为图2的形式。其中Ent键具有二重功能,即确认功能(短按)和开关机功能(长按),此功能将在驱动程序中实现。
图2 键盘布局
3.矩阵键盘的Linux驱动程序设计
3.1 键盘驱动总体概述
驱动程序是操作系统内核和硬件设备之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,使应用程序可以像操作普通文件一样操作硬件设备[2]。驱动程序没有main函数,它以一个模块初始化函数作为入口,并且它完成初始化之后不再运行,等待系统调用。
驱动程序是linux内核的一部分,所以在程序编写上要采用linux的表达方式。首先将列I/O端口定义为数组:col_table [] = { S3C2410_GPF3,S3C2410_GPF4, ...},行I/O端口定义为结构型:
button_irqs [] ={ {IRQ_EINT8,S3C2410_GPG0,S3C2410_GPG0_EINT8, 0,"R1"},
{IRQ_EINT9,S3C2410_GPG1,S3C2410_GPG1_EINT9, 1,"R2"},
...}。//中断号(irq),引脚(pin),引脚设置,序号,名称
矩阵键盘是作为Linux的一个字符设备注册到系统中的。我们首先向系统注册矩阵键盘设备,包括设备号,设备名及file_operations结构体;file_operations结构体的成员函数是字符设备驱动程序设计的主体内容,这些函数实际会在应用程序进行Linux的open()、write()、read()、close()等系统调用时最终被调用[3]。用户对键盘没有写操作,其file_operations结构体的成员函数为open()、read()、close()、poll()。
中断的注册和行列初始化在打开键盘时(即open()函数中)实现。注册中断包括:中断号,中断入口程序,中断方式,中断名和代号。关键语句为:request_irq(button_irqs[i].irq,buttons_interrupt,IRQ_TYPE_EDGE_FALLING,button_irqs[i].name,(void *)&button_irqs[i])。IRQ_TYPE_EDGE_FALLING意思为下降沿触发。然后再进行行列初始化:设置行线为中断,使能上拉,在linux中其表达方式为:
s3c2410_gpio_cfgpin(button_irqs[i].pin,S3C2410_GPIO_SFN2); //设置第i行引脚为中断
s3c2410_gpio_pullup(button_irqs[i].pin,1); //第i行引脚上拉
设置列线为输出,置低电平。语句表达同理,由于篇幅所限,这里不再一一列出。
read()函数实现从设备中读取数据。该函数实现无按键按下时程序进入休眠,关键代码:
static DECLARE_WAIT_QUEUE_HEAD (button_waitq); //生成一个等待队列头队列,名为button_waitq
static volatile int ev_press = 0; //置1,表示有键按下
ev_press为0时执行语句:wait_event_interruptible(button_waitq,ev_press),程序即进入休眠。ev_press为1时把数据从内核空间复制到用户空间,关键语句:copy_to_user(buff,(const void *)key_values,min(sizeof(key_values),count)); //buff为用户空间的指针,key_values为内核空间指针,最后一个参数为从内核空间向用户空间拷贝数据的字节数,我们取实际大小与用户指定大小中的最小值。数据复制成功时返回零;出错时返回没有复制成功的数据字节数。
close()函数实现关闭矩阵键盘设备,释放已注册的中断,关键语句:free_irq (button_irqs[i].irq,(void *)&button_irqs[i])。
Poll()函数实现轮询,如果没有按键数据,调用linux的poll_wait函数等待;如果有按键数据,则select函数会立刻返回。
3.2 中断处理及键盘扫描程序
中断处理函数的名称为上面注册的buttons _interrupt。具体程序流程如图3所示。当有按键按下时,该键所在行列导通。列的低电平将该行电平拉低,进而触发中断。然后,进入中断处理函数。由于按键存在抖动的问题,单靠一次中断的触发就判定有按键按下是不可靠的,所以采用定时器延时10ms后再进入键盘扫描函数。
本设计的键盘扫描程序采用先确定行再确定列的方法,最后对行列进行一定的运算即得键值。首先确定行:逐行扫描,判断是否有行引脚为低电平。若有,保存该行值(row)。继续确定列:逐列置低电平,当该列为按下所在列时,才会使该行再次为低电平,从而确定列(column)。再对行列进行运算:k=row*4+column,则将矩阵键盘的每一键对应为键号0—19。键盘布局为图2所示形式后,我们只取矩阵键盘的前18键(键号0—17),键值保存为k+1。对于Ent键,通过按下的时间长短区分是确定功能还是开关机功能,按下时间小于0.5秒为确认功能,按下时间大于1.6秒为开关机功能,时间在0.5秒—1.6秒的视为无效操作。计时方法为:若该行仍为低电平且整数cnt小于1700:延时1ms,cnt++;根据cnt值即得按下时间。开关机功能保存为第18键号,键值19。
图3 键盘扫描程序流程图
4.驱动程序的测试
测试程序属于上层应用程序,直接调用键盘驱动程序提供的接口即可实现度键盘的操作。我们调用open()函数实现矩阵键盘设备的打开,再调用read()函数即可将键盘数据读取出来并保存到自己定义的数组中,最后使用printf()函数将测试结果显示出来。
按本文介绍的方法设计的矩阵键盘,已成功运用到笔者的项目中,键盘输入的正确率和反应时间均符合设计要求。
5.总结
本文介绍了一种直接从ARM的I/O口扩展矩阵键盘的方法,它无需增加其它接口元器件,设计快速实用,并实现了在Linux系统下的驱动,为ARM嵌入式设备扩展手持终端式键盘提供了一种解决方案。
参考文献
[1]胡章勇,蒋朝根.Linux的键盘驱动与Qt/E的键盘映射[J].单片机与嵌入式系统应用,2008(9):35.
[2]李俊.嵌入式Linux设备驱动开发详解[M].北京:人民邮电出版社,2008:17.
关键词:CY7C68013A; 通用串行总线; VC++6.0; 固件; 上位机
中图分类号:TP368.1 文献标识码:A
文章编号:1004-373X(2010)13-0190-04
Design of USB Control System Based on CY7C68013A
ZHAO Tie-jun
(Equipment Power Department, China Coal Beijing Coal Mining Machinery Co. Ltd., Beijing 102400, China)
Abstract: With the increasing development of the communication technology, the universal serial bus (USB) as a new interface technology that makes the connection of PCs with peripheral equipments very simple has been extensively adopted. The feature of USB2.0 is introduced firstly, and then the overall plan for designing the control system by using CY7C68013A is presented. The function of the system firmware and the design of drive program are discussed in detail. The key issues which should be taken more attention during the system design are proposed. The control system firmware is programmed with C language. The control interface on PC is developed under the VC++6.0 development environment. The experiment indicates that the whole system runs perfectly well.
Keywords: CY7C68013A; USB; VC6.0; firmware; PC
0 引 言
通用串行总线 (Universal Serial Bus,USB)作为计算机上的新型接口技术,越来越受到人们的青睐。与以前的RS 232,RS 485,ISA,PCI和并行接口等接口相比,USB避免了接口体积大、接口规范不统一、不支持热插拔等缺陷,具有使计算机与外部设备连接十分方便的优点[1-2]。目前,很多设备都开始使用USB接口来实现,如鼠标、键盘、打印机等。在实际设计工作当中,也越来越多地采用了USB技术,如数据采集等[3-4]。USB的设计和应用已经成为现代电子设计中一个非常重要的部分。
1 USB 2.0特点
USB是一种高效、快速、价格低廉、体积小的新型串行通信接口,其最大的特点是支持热插拔,可以在不重新启动计算机的情况下直接将USB外部设备连接到计算机并开始通信。
USB具有以下主要特点[2]:
(1) 节省系统资源。在计算机中,系统为USB主控制器分配一根中断控制线和一些输入/输出地址,USB再为外部设备分配惟一的地址。
(2)可以提供电源。计算机上的USB接口可以向外部设备提供一定的电力支持,其输出电流最小值为100 mA,最大值为500 mA,输出电压为5 V。
(3) 良好的兼容性。USB规范已经有USB 1.0,USB 1.1,USB 2.0,无线USB等多个版本的协议,这些协议都有很好的向下兼容性。
(4) 共享式接口。USB采用“链”式的连接方式,同时支持多个设备的连接,一个USB主控制器最多可以连接126个外部设备。
2 CY7C68013A的主要特点
CY7C68013A是Cypress公司的EZ-USB FX2LP系列低功耗版本单片机,具有和8051兼容的CPU和指令系统,同时包括USB接口和完整的USB 2.0协议引擎,并且提供了完善的固件及主机程序开发包。该单片机的CPU采用的是增强型8051内核,比标准的8051的速度快,硬件资源更为丰富,功能更强大。主要具有以下特点[5-6]:
(1) 具有第二个数据指针;
(2) 具有第二个USATRT;
(3) I2C总线接口;
(4) 8个额外的中断(INT2~INT6,WAKEUP,T2,USART1);
(5) CPU时钟可以运行在12 MHz,24 MHz,48 MHz。
3 控制系统设计
基于USB的控制系统设计主要包含两个方面的内容,分别为固件程序的开发和上位机(主机)控制界面的设计。CY7C68013A芯片采用的是一种软配置模式,即程序和数据都存放在内部RAM中,并从RAM中开始执行。
3.1 启动模式的选择
EZ-USB在没有固件的情况下列举为一个缺省的USB设备,并且将其固件和描述符等下载到EZ-USB后,开始执行固件程序,此时模拟一个物理上的断开重新连接过程[6-7]。在列举为一个USB设备时,根据芯片有没有连接E2PROM,以及E2PROM中第一个字节值的不同,其处理方式有很多。主要有:不连接E2PROM的缺省设备列举、C0加载、C2加载等启动方式。在此系统的设计过程中,采用第一种方式,即芯片没有连接任何片外存储器,USB的描述符以及VID,PID和DID等均由芯片内置的逻辑提供,然后根据驱动程序中提供的VID,PID和DID把主机上对应的固件程序下载到片内的RAM中,并执行固件代码。该方式具有硬件连接简单,节省器件等特点。
3.2 硬件系统框图
整个系统的硬件框图如图1所示。可以看出USB控制系统在整个系统中起到桥梁作用,用于连接上位机和外部设备。
图1 系统硬件框图
上位机发送控制指令给USB设备,信息处于下行状态,解码后用来控制设备执行相应功能。上位机需要从外设获得信息(如数据采集),信息处于上行状态,由USB设备负责控制外设并将数据传送到上位机,由上位机分析、显示。
3.3 固件程序设计
在固件中,主要实现芯片设备的控制,以及对USB设备的功能描述等任务,同时负责与上位机通信,响应上位机的标准请求和自定义请求。
描述符主要是让上位机了解USB功能设备的基本配置信息和能力,如端点、接口等。在此主要使用标准描述符来说明USB设备,如设备描述符、配置描述符、接口描述符、端点描述符、设备限定描述符等。在该设备中,这些描述符的层次结构如图2所示。
图2 描述符层次图
系统中使用了2个配置描述符,分别为高速配置和全速配置,┟扛霆配置使用1个接口,并对应1个接口描述符,每个接口应用了4个端点,对应4个端点描述符。同时端点配置为块传输模式,2、4端点为OUT,6、8端点为IN,最大数据包长度为512 B,上位机通过0端点来操作、控制USB设备。设备描述符中VID=0x04B4,PID=0x1304,用于指示设备供应商和产品信息,并用于上电时帮助主机加载合适的驱动程序,进而下载相应的固件程序。固件中对标准请求的响应部分,主要是让上位机能够对描述符进行读取和写操作。自定义请求响应主要实现上位机发送控制命令,来使能USB功能设备、以及执行相应的功能的目的,如DR_SendData,DR_ ReadData。
固件设计流程图如图3所示。
图3 固件设计流程图
用户初始化设备部分放在TD_Init()子程序中,负责整个USB设备的初始化过程。在定向描述符之后,需要把所用中断打开,并开启8051全局中断EA=1。由于EZ-USB设备启动需要重列举,因而需要通过设置和判断USBCS寄存器的RENUM和DISCON位来模拟设备物理上的断开和连接过程。用户设备控制功能的实现放在TD_Poll()子程序中,同时主循环中的SetupCommand()子程序用于接收、分析上位机的控制信号,响应上位机请求(标准请求和用户自定义请求)。
3.4 上位机界面设计
为了能够很好地控制USB设备,需要编写上位机控制界面。界面程序在VC++6.0环境下开发,该环境具有编程简单、快捷等的特点,便于开发可视化程序[8-9]。Cypress公司为EZ-USB系列芯片提供了开发库CyAPI.lib,使用其中的控制函数类,可以在VC++6.0环境下开发界面程序[10]。建立MFC(exe)工程后,在工程中加入CyAPI.lib,并且在主文件头部添加EZ-USB开发环境中提供的CyAPI.h,cyioctl.h头文件。利用库中的控制函数,如VendorID,ProductID等,可以获取USB设备的描述信息,同时也可以编写相关的控制功能程序。
3.5 系统设计中关键问题
(1) 一个设备只能有一个设备描述符,可以有多个配置描述符,多个接口描述符,以及多个端点描述符。
(2) 设备描述符中VID,PID要与驱动中的相一致,否则不能自动加载相应的固件程序。
(3) 固件程序必须转换为.spt格式,用于固件加载的驱动程序和固件程序应放在一个文件夹。
(4) 端点0为缺省控制端点,其可设置最大数据包长度为64 B,在设备描述符中wMaxPacketSize字段描述。
(5) 传输模式有中断传输、块传输、同步传输、控制传输四类,需根据自己设计需求选择,同时注意最大数据包长度的设置。
4 驱动程序
对于USB设备,Windows操作系统要想对其实现操作,必须借助于驱动程序来实现。主机和驱动程序直接通信,交换数据,而驱动程序则和硬件资源进行通信,从而很好地控制USB设备。Cypress提供的开发环境中自带了相关的驱动程序CyLoad.sys和CyUSB.sys,可以直接使用,缩短了系统的开发周期。其中CyLoad.sys用于主机向USB设备下载固件程序,CyUSB.sys实现主机和固件程序通信。为了在CyLoad.sys的帮助下实现固件的自动下载,固件程序CyLoad.HEX必须转换为适合自动下载的CyLoad.spt文件,并且与CyLoad.sys一起放在CyLoad文件夹下,拷贝到系统system32目录下。在安装文件CyUSB.inf中设置的PID,VID必须和描述符中的一致,使得能够自动加载对应固件。
5 实 验
实验系统,采用CY7C68013A-56pin作为USB设备芯片,实现控制LED和读取I/O数据功能。
由于芯片采用33 V电压供电,因此可以从主机USB口取电,经LM317电压调整芯片转换为33 V,也可外接33 V电压供电。在PD口接LED,显示TD_Poll(void)实现的功能(灯亮/灭间隔300 ms),┒PA口LED用于显示判断主机发送数据。PB口接高/低电平,用于主机读取该口数据,可以验证主机接收数据的正确性。
初始化子程序:
void TD_Init(void)
{
BREAKPT &= ~bmBPEN;
OED=0xFF;//设置PD口为输出
}
外设功能子程序:
void TD_Poll(void)
{
IOD=0x00; //D口输出低电平
EZUSB_Delay(300);
IOD=0xFF;// D口输出高电平
EZUSB_Delay(300);
}
自定义请求响应发送数据子程序:
BOOL DR_SendData(void)
{
EP0BUF[0]=0xB1;//发送数据自定义请求码
EP0BCH=0;
EP0BCL=2;
EZUSB_Delay(100);
OEA=0xFF;//PA口为输出
IOA=EP0BUF[1];
EP0CS |= bmHSNAK;
return(TRUE);
}
自定义请求响应接收数据子程序:
BOOL DR_ReadData(void)
{
OEB=0x00;//PB口为输入
EP0BUF[0]=0xB2;//接收数据自定义请求码
EP0BUF[1]=IOB;
EP0BCH=0;
EP0BCL=2;
EP0CS |= bmHSNAK;
return(TRUE);
}
主机控制界面运行如图4所示。
界面中的USB Information分类框中为USB描述相关信息,由主机通过标准请求获得。Operation分类框中为主机向USB设备PA口发送数据,以及从USB设备的PB读取数据的
情况。
图4 主机控制界面
6 结 语
采用CY7C68013A实现USB控制系统,无论在固件程序编写、主机控制界面开发,以及设备驱动程序的使用等方面,都具有简单、方便的优点。系统采用设备固件存放在主机上的方法,不但简化了硬件设计,节约元器件成本,而且也提高了设备的可靠性。同时,此法对以后固件升级或更改设备功能,也十分简便,只需把固件修改好并放到主机相应位置,在USB设备再次插入主机时,就可以实现固件自动更新。文中给出一些设计过程中需要注意的关键问题,对于USB控制设备的设计具有一定的指导作用。上述系统和程序经过实际运行,工作稳定、可靠。
参考文献
[1]李英伟,王成儒.USB 2.0原理与工程开发[M].北京:国防工业出版社,2007.
[2]胡晓军,张爱成.USB接口开发技术[M].西安:西安电子科技大学出版社,2005.
[3]钱峰.EZ-USBFX2单片机原理编程及应用[M].北京:北京航空航天大学出版社,2006.
[4]周立功.PDIUSBD12 USB固件编程与驱动开发[M].北京:北京航空航天大学出版社,2003.
[5]薛园园.USB应用开发技术大全[M].北京:人民邮电出版社,2007.
[6]Cypress. EZ-USB FX2LPTM USB microcontroller datasheet[ EB/OL] . [ 2009-05-20] . .
[7]Cypress. EZ-USB FX2 technical reference manual[ EB/OL] . [ 2009-03-18] . .
[8]周晓云.程序设计基础――可视化及VC++实现[M].北京:高等教育出版社,2004.
关键词:电阻电容检测;微处理器;usb;visual b + +
基于usb接口虚拟在线电阻电容测试的方法其总体设计思想为:将电阻电容的参数值转换成与之成正比关系变化的电压输出,经模数(a/d)转换,然后送pc机进行数据及信息处理,在pc机上进行数据和信息显示。最终完成电阻电容的在线测试与显示。
一、电阻电容测试原理
电阻电容的参数测试在电子设计中是至关重要的,目前其测试基本上都采用直接测量的方式,即用万用表直接测试元件的两端以测得元件参数。但通常设计者们在电路设计初期只能通过理论分析计算需要的电子元件的参数,在实际的设计中,需要测试更换一些电路板上的电子元件。但此时元件已经焊接在电路板上,特别像电阻电容往往都不是分立的元件,直接测试将会造成极大的误差。传统的做法是焊开原器件再测量,以避免受板上其他元器件的影响。
二、visual b + + 6.0
visual b++6.0是微软公司推出的一种开发环境,以其强大功能友好的界面,32位面向对象的程序设计而受广大软件开发者的青睐,被广泛应用于各个领域。
应用程序用visual b+ +开发环境在windows xp系统下编写,对usb接口的电阻电容测试仪进行打开、读写、关闭等操作都通过调用系统api函数完成。应用程序首先调用creat file得到usb设备的句柄,然后利用device io control 函数提交一个i/o控制代码,通过设备句柄打开连接驱动的输入输出缓冲。
三、通用串行总线(usb)及其接口芯片
通用串行总线(usb)是一种简单的计算机外围接口标准。在早期的计算机系统上常用串口或并口连接外围设备。每个接口都需要占用计算机的系统资源(如中断,i/o地址,dma通道等)。无论是串口还是并口都是点对点的连接,每添加一个新的设备,就需要添加一个isa/eisa或pci卡来支持,同时系统需要重新启动才能驱动新的设备。usb总线是intel、dec、microsoft、ibm等公司联合提出的一种新的串行总线标准,主要用于pc机与外围设备的互联。usb总线具有低成本、使用简单、支持即插即用、易于扩展等特点,已被广泛地用在pc机及嵌入式系统上。
四、usb协议栈驱动程序及设备驱动程序需实现的功能
usb协议栈驱动程序需实现的功能:提供与设备驱动程序的接口;读取并解析usb设备描述符,配置描述符;为usb设备分配唯一的地址;使用默认的配置来配置设备;支持基本的usb命令请求;连接设备与相应的驱动程序;转发设备驱动程序的数据包。
设备驱动程序需实现以下功能:提供与应用程序的接口;读取并解析usb设备特有的描述符,获得设备提供的传输通道;发送设备特有的和基本的usb命令请求;通过设备提供的传输通道与设备进行数据传输;通过usb命令请求重新配置设备。
五、结论
系统测试时选定若干电阻和电容的测试结果如表1所示。
数据中3号代表数字变化,数据不能读出。通过测试结果与实际值的对比,本测试仪已达到设计时的技术指标,基本满足测试人员的测试要求。