介绍了在vb开发环境下,对pci设备进行底层访问的两种方法:一种是通过用用户自己编写的动态连接库(dll)实现,二是利用windriver提供的vb运行库编写直接访问硬件接口函数,并对两种方法行了比较。
vb集成化编程语言一种功能强大而容易上手的开发工具,在用户界面、数据库、多媒体、网络编程等方面,vb可谓得心应手。然而vb有限的硬件编程能力以又使得许多硬件开发者对此深感无奈。尤其在工业控制,测控技术等领域,自行设计开发的i/o卡,数据采集卡等在win32下的驱动常常需要借助ddk,vtooisd等工具进行艰苦而又长期的内核模式开发。本文介绍了在vb开发环境下访问pci设备的方法。对于其他设备,方法与此大同小异。
在vb开发环境下,用户要访问诸如数据采集卡之类硬件上的pci设备,一般来说有两种途径:一是直接访问,即用vb直接编写访问pci设备的接口函数(这种方法要有相关软件的支持);二是间接访问,即vb调用其它编程语言(如汇编,c/c++等)写的底层驱动模块(一般封装成动态连接库dll的形式)实现。
1 pci总线的配置空间
pci规范定义了三种地址空间,除了存储器和i/o地址空间外,为支持pci设备系统资源的自动配置,还定义了配置地址空羊。
pci总线的配置空间由256个字节组成,分为预定首区和设备关联区。预定首区包括开始64个字节,对所有的pci设备来说,都必须支持该区的设置;设备关联区的寄存器有不同的的pci设备厂家自己定义。
配置空间的预定的首区分两个部分,前16个字节的定义对各类pci设备而言都是相同的,后48个字节空间根据设备支持的功能有不同的分配。首区类型定义了该空间的分配情况(目前只有一种类型00h)。表1是首区的组织结构。
所有的pci设备必须支持首区的供应商id、设备id、指令和状态区。对于其他寄存器的使用可根据设备的楞能来选择。对于不同的pci设备,其供应商id由pci
sig分配以确保唯一性,而设备id则由供应商自己分配。
2 pci设备的配置过程
pci总线的配置空间规范保证了所有pci设备对“即插即用”的支持。
系统在上电后,“即插即用”bios通过隔离算法读取每一个“即插即用”设备的资源申请数据,并分配相应的系统资源,同时检查资源的冲突情况,然后引导、加载操作系统,并将控制权交给操作系统;如果加载的是“即插即用”操作系统(windows
95及以后版本),那么操作系统将接管系统的资源管理权,它首先从bios读取“即插即用”设备的资源配置信息,并仲载资源冲突情况,然后配置bios尚未配置的“即插即用”设备,将设备的配置信息写入配置管理器,最后激活无资源冲突的“即插即用”设备,装载相应的设备驱动程序。
对于pci设备来说,系统完成引导之后,除了将资源的分配写入系统的配置管理器外,还写入了相应的pci配置寄存器。程序可以通过直接读取设备的配置寄存器来得到设备的i/o,存储器等资源配置情况。
3 vb下pci设备的访问
驱动程序访问pci设备的过程一般包括扫描pci总线,相找指定的pci设备,确定i/o等资源分配情况,进行i/o、存储器、中断以及dma等操作。vb本身并不能实现上述对pci设备的访问过程,下面介绍在vb下通过其他途径实现对pci设备的访问。
3.1 vb直接访问
windriver为vb只提供了非常有限的i/o访问能务(如串口通信),在vb下直接访问pci设备时需要借助其它软件。目前windriver是keftech公司主推产品,是许多pci厂家所推荐的首选驱动器程序开发工具。
windriver为vb 4.0以上版本提供了一个类模块(windriver.cls),利用这个类模块,用户可以手工编写自己需的接口函数来访问相应的设备。下面以具体例子来说明windriver.cls的使用方法。
3.1.1 扫描pci总线得到指设备的数目
利用windriver.cls提供的应用程序接口函数(apis),编写一个扫描pci总线,获得指定pci设备数目的函数下:
function getcardsnum (dwvendorid as)
long, dwdeviceid as long) as integer
dim pciscan as wd_pci_scan_cards
dim hwd as long
hwd = wd_open()
if hwd =invalid_handle_value then
msgbox “设备打开出错”
exit function
end if
pciscan.searchid.dwvendorid =
dwvendorid
pciscan .searchid.dwdeviceid =
dwdeviceid
wd_pciscancards hwd, pciscan
wd_close (hwd)
getcardsnum = pciscan.dwcards
end function
该函数可以通过输入参数:pci设备的供应商id和设备id得到所需的pci设备数目。如查找amcc公司的pci适配芯片s5933,则输入参数为:&h10e8和&h4750。
下面例子用于读写s5933的pci配置寄存器。在工程的全局模块中需要先定义下列数据结构,同时设备必须处于打开状态。
type amcc_innterrupt
int as wd_interrupt
hthread as long
trans(o to 1)as wd_transfer
end type
type amcc_addr_desc
dwlocalbase as long
dwmask as long
dwbytes as long
dsaddr as long
dwaddrdirect as long
flsmemory as boolean
end type
type amcc_struct
hwd as long
cardlock as wd_card
pcislot as wd_pci_slot
cardreg as wd_card_register
addrdesc(0 to ad_pci_bars-1)as
amcc_addr_desc
fuseint as boolean
int as amcc_interrupt
end type
3.1.2 读写pci配置寄存器
完成以上数据结构的定义后,用下面的函数可写s5933的pci配置寄存器内容。
function amcc_readpcireg (hamcc as
amcc_setruct, dwreg as long)
dim pcicnf as wd_pci_config_dump
dim dwval as pvoid
pcicnf.pcislot = hamcc.pcislot
pcicnf.pbuffer = dwval
pcicnf.dwoffer = dwreg
pcicnf.dwbytes = 4
pcicnf.flsread = true
wd_pciconfigdump hamcc.hwd, pcicnf
amcc_readpcireg = dwval
end function `读函数
sub amcc_writepcireg (hamcc as
amcc_struct, dwreg as long, dwdata as pvoid)
dim pcicnf as wd_pci_config_dump
pcicnf.pcislot = hamcc.pcislot
pcicnf.pbuffer = dwval
pcicnf.dwoffer = dwreg
pcicnf.dwbytes = 4
pcicnf.flsread = false
wd_pciconfigdump hamcc.hwd, pcicnf
end sub `写过程
参数说明:
hamcc 设备打开后系统分配的句柄
dwreg 读写的pci配置寄存器
dwval 读出的寄存器数据
dwdata 写入寄存器的数据
以上例子仅仅是抛砖引玉。windrar.cls类模块提供了功能极为强大的底层驱动的api函数,用户通过编写相应的驱动模块可以方便地实现对各类硬件的i/o、存储器映射、中断以及dma等操作,同时可以实现win32下物理内存空间的申请、读写等处理。另外对于实时性要求较高的设备,windriver提供的“内插”(plug-in)特性可以让程序的相关模块运行于ring 0内核模式(kernel mode),以提高性能。
开发完成的底层驱动模块既可直接为vb的应用程序调用,也可以在vb下封装成dlls供其它的win32开发工具调用。
3.2 自定义dll访问
dll使vb的功能得到极大的增强,使得vb的应用范围不断扩大,使用更加灵活。vb通过调用自定义dll可以实现对硬件的底层访问。下面用例了说明vb对dll的调用及dll的编写过程。
3.2.1 dll的功能和编写
本例中的dll通过扫描pci总线,得到总线上s5933接口芯片的数目,打开指定设备,向s5933的输入邮箱子中写入命令字,然后从输出邮箱1中读取返回数据,最后关闭设备。
extern “c” _declspec (dllexport)
int _stdcall getcardsnum()
{
afx_manage_state (afxgetstaticmodulestate());
int cards;
cards=amcc_countcards (0x10e8,0x4750);
return cards;
} //此函数得到s5933的数目;
extern “c” declspec (dllexport)
dword_stdcall send-
command(int cardnum, dword dwcmd)
{
afx_manage_state (afxgetstaticmodulestate());
dword data;
if (amcc_open (&hamcc, 0x10e8,0x4750,
card-
num, 0)) //打开指定设备
{
amcc_writeregdword(hamcc, omb1_addr);
dwcmd); //写入命令字
do{
data=amcc_readregdword(hamcc,mbff_addr);
}while((data&0x000f0000)==0x00000000);
//等待输入邮箱1满
data=amcc_readregdword(hamcc,imb 1_addr);
//读取返回数据
if(hamcc) amcc_close(hamcc)
//关闭设备
return data;
else
{afxmessagebox(“打开设备失败!”);
return 0;}
程序中用到的函数包含在windriver的api函数库中,在vc++下编译时加上头文件:
#include “amcclib.h”
#include “amcclib.c”
同时在def文件中列出dll的导出函数名,生成的dll即可为vb即可为vb所调用。读者也可用其它工具编写驱动模块,最后封装成dll即可。
2.2.2 vb调用dll
vb调用动态连接库(dll)时,首先声明dll,然后即可像调用vb的语句或函数一样使用dll中的例程。下面介绍vb调用上例生成的dll(假设文件名为test.dll)。
声明
public declare function getcardsnum lib
“test.dll”()
as integer
public declare function sendcommand lib
“test.dll”
(byval dwcmd as long) as long
在声明时需要注意:dll的路径;参数传递的方式;参数的类型。
另外,vb遵从_stdcall的参数传递约定,而vc++默认_cdecl的传递约定,因此在dll中的导出声明需采用_stdcall的装饰符。
调用
一旦声明后,在vb的应用程序中就可调用dll中的例程。如:
private sub form_load()
dim cardsnum as integer
cardsnum = getcardsnum()
msgbox“系统中有”+ str(cardsnum)+“块s5933插卡!”
end sub
windriver包括了诸如amcc、altera、plx、galileo、v3、plda等公司pci芯片的专用c/c++的
api函数库,其中包含了i/o读写,内存映射,中断处理以及dma等底层驱动的函数,可以非常方便地用vc++,bc++以及c++builder等工具编译成dlls供vb调用。
本文提供了两种在vb的开发环境下访问pci设备的方法。第一种方法需要有windriver的vb运用库支持,可以在vb环境下直接编写所需的接口函数,但对windrar。cls类模翰中定义的内核数据结构要有较深的了解;第二种方法具有一定的灵活性、普遍性,编写的dll的工具较多,dll除了可用于vb外,还可用于其他的win32开发工具,有较强的适应性。
以上方法在北京航空航天大学测控技术研究所研制的phd2000高速并行数据采集系统中得到实际应用,取得了良好的效果。
2020年第四季度全球前十大晶圆代工厂营收排名
节卡机器人JAKA C系列协作机器人重磅发布
威纶通HMI+KNX:先进且稳定的HMI人机界面解决方案分析
第二届"Factory Tour"精彩继续,热浪来袭! 来一场全新的暑期少年游!
什么是上拉电阻
PCI设备两种底层访问方法的实现及比较分析
眼科与AI,让技术服务于临床
iOS10.3最新消息:iOS10.3耗电怎么办?iOS10.3.2第四个测试版更新,重大改变的是电池
“数字”赋能农业生产,打造新疆多个数字化高标农田示范基地
运算放大器基本电路大全!
苏宁极物小Biu蒸汽洗烘一体机评测 这才是极致性价比
C&K宣布为游戏控制器和游戏配件设计者提供各种各样的开关组合
怎样用Javascript控制Arduino Uno
常见PLC自动程序的流程编写
ikbcg108机械键盘怎么样 Mac的最佳搭档
realme Q5系列发布会,推出Q5i、Q5及Q5 Pro三款新手机
氧化皮处理机的价值所在
四部门明确App收集个人信息范围
STM32F407串口通信基本内容
回弹力测试仪和回弹测试仪的对比,它们的区别是什么