实验二线程同步调试实验.docx
《实验二线程同步调试实验.docx》由会员分享,可在线阅读,更多相关《实验二线程同步调试实验.docx(19页珍藏版)》请在冰豆网上搜索。
![实验二线程同步调试实验.docx](https://file1.bdocx.com/fileroot1/2023-1/28/5f3765aa-eca1-4636-87e2-f635f2096282/5f3765aa-eca1-4636-87e2-f635f20962821.gif)
实验二线程同步调试实验
实验十一驱动程序实验
[实验目的]
1、了解驱动程序的原理和功能;
2、掌握流式接口驱动程序的结构;
3、掌握编写流式接口的驱动程序的方法
4、熟悉EVC和VS.Net的开发环境;
[实验仪器]
1、装有PlatformBuilder、EVC和VS.Net开发平台的PC机一台
2、XSBase270实验开发平台一套
[实验原理]
1、硬件接口电路分析
XSBase目标板LED和七段数码显示接口电路如图6-1所示,74HC574为D锁存器,在时钟信号CLK作用下,该锁存器将输入信号进行锁存,即xQ=xD(x=1~8)。
从电路图中可以看出,LED和八段数码显示电路将74HC574的时钟信号输入端作为片选信号,其中LED显示的片选信号为LED_CS4、七段数码显示的片选信号为LED_CS1(另外还有一组七段数码显示未画出,参考原理图)。
在七段数码显示电路中,数据的高位(D7、D15:
即数码管的小数点dp段)用作七段数码的公共选通信号,通过控制PNP三极管来控制数码管的显示。
图6-1LED和七段数码显示接口电路
显示电路中的片选信号LED_CSx(x=1-4),由XSBase270目标板系统的处理器PXA270x的地址信号BA22~BA20通过3-8译码器LC138产生(如图2-2所示)。
图6-2片选信号产生电路
由3-8控制功能可知,当BA22、BA21、BA20=101时产生LED显示电路的片选信号LED_CS4,当BA22、BA21、BA20=010、011、100时分别产生七段数码显示电路的片选信号LED_CS1、LED_CS2、LED_CS3(另外2组八段显示电路参考系统提供的总电路图)。
根据分析,可以得出七段数码管和LED的片选信号为:
LED_CS1=0x10200000、LED_CS2=0x10300000、LED_CS3=0x10400000,LED_CS4=0x10500000。
2、流式接口驱动程序简介
驱动程序是对底层硬件的抽象。
应用程序开发者不需要真正理解底层驱动的工作原理,他们只需要通过WindowsCE提供的API函数,就可以直接与硬件进行交互。
WinCE的流式接口驱动程序以动态链接库的形式存在,由设备管理器(通常是device.exe或者gwes.exe)统一加载、管理和卸载。
与具有单独目的的内部设备驱动程序相比,所有流式接口驱动程序都是用同一接口并调用同一个函数集。
每个流式接口驱动程序必须实现一组标准的函数,用来完成标准的文件I/O函数和电源管理函数,这些函数提供给WinCE操作系统的内核使用。
这些函数通常叫做流式接口驱动程序的DLL接口,如表11-1所示:
(详细介绍参考实验三)
表11-1流式接口驱动程序要实现的DLL接口:
函数名称
描述
XXX_Close
在驱动程序关闭时应用程序通过CloseHandle函数调用这个函数
XXX_Deinit
当设备管理器卸载一个驱动程序时调用这个函数
XXX_Init
当设备管理器初始化一个具体设备时调用这个函数.
XXX_IOControl
上层的软件通过DeviceIoControl函数可以调用这个函数
XXX_Open
在打开一个设备驱动程序时应用程序通过CreateFile函数调用这个函数
XXX_PowerDown
在系统调用前调用这个函数
XXX_PowerUp
在系统从新启动前调用这个函数
XXX_Read
在一个设备驱动程序处于打开状态时由应用程序通过ReadFile函数调用
XXX_Seek
对设备的数据指针进行操作,由应用程序通过SetFilePointer函数调用
XXX_Write
在一个设备驱动程序处于打开状态时由应用程序通过WriteFile函数调用.
3、LED流式接口驱动程序的实现
由于在WinCE中流式接口驱动程序以DLL的形式存在,是运行在用户模式的动态链接库,所以既可以使用微软提供的EVC编写流式接口驱动程序,也可以使用PlatformBuilder(PB)来进行编写。
为了方便调试,通常采用PB来开发流式驱动程序。
下面具体介绍LED驱动程序为例介绍采用PB编写流式接口设备驱动程序的方法和步骤。
3.1流式驱动程序的创建步骤:
(1)打开PlatformBuilder。
在PlatformBuilder中选择“File”->“NewProjectorFile”,创建一个“WindowsCEDynamiclinklibrary”项目,项目的名称填写“LedDriver”(如图11-1所示)
图11-1WinCE驱动创建项目界面
(2)按OK按钮,在DLL的类型界面中(如图11-2所示)选中ASimpleWindowsCEDLLprojects,PlatformBuilder将生成DLL框架代码。
图11-2驱动程序的DLL类型选择
3.2LED流式驱动程序的源代码分析:
(1)变量定义
#defineLED_IOCTL_SET0x00000001//IO控制接口代号码
#defineLight_IOCTL_Set0x00000002
#defineLight_IOCTL_LShift0x00000003
#defineLight_IOCTL_RShift0x00000004
#defineLight_IOCTL_LRShift0x00000005
#defineLight_IOCTL_ShiftStop0x00000006
#defineLight_IOCTL_SetTime0x00000007
#defineLED_BASEADDR10x10200000//七段数码的物理地址
#defineLED_BASEADDR20x10300000
#defineLED_BASEADDR30x10400000
#definepLightIoBaseAddress0x10500000//Led物理地址
#defineBIT7(0x1<<7)
#defineBIT15(0x1<<15)
HANDLEm_hShiftEvent=NULL;//LED流水灯移动事件变量
BOOLm_bStop;//LED流水灯停止变量
UINTm_ShiftDir;//LED流水灯移动方向
UINTShiftTime;//LED流水灯时间间隔
unsignedcharShiftData;//LED流水灯赋值变量
(2)驱动程序初始化函数DEM_Init
驱动程序的初始化函数XXX_Init主要完成当用户使用一个设备的时候,设备管理器调用这个函数来对设备进行初始化。
这个函数并不是由应用程序调用的,而是通过设备管理器提供的ActiveDeviceEx()来调用。
该初始化函数主要完成LED和七段数码的物理地址到虚拟地址的转换。
DWORDDEM_Init(DWORDdwContext)
{
charblack=0xff;
RETAILMSG(1,(TEXT("Led_Init\r\n")));//从串口输出调试信息
if(!
LEDInit())
returnFALSE;
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
m_hShiftEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
if(m_hShiftEvent==NULL)
{
RETAILMSG(1,(TEXT("FailedtoCreatethread\r\n")));
returnFALSE;
}
*pLightReg=black;
ShiftTime=500;
m_bStop=FALSE;
m_ShiftDir=1;
returnTRUE;
}
BOOLLEDInit(void)
{charblack=0xff;
PHYSICAL_ADDRESSioPhysicalBase={LED_BASEADDR1,0};
v_pLEDBaseAddr[0]=(USHORT*)MmMapIoSpace(ioPhysicalBase,0x400,FALSE);
ioPhysicalBase.QuadPart=LED_BASEADDR2;
v_pLEDBaseAddr[1]=(USHORT*)MmMapIoSpace(ioPhysicalBase,0x400,FALSE);
ioPhysicalBase.QuadPart=LED_BASEADDR3;
v_pLEDBaseAddr[2]=(USHORT*)MmMapIoSpace(ioPhysicalBase,0x400,FALSE);
if(!
(pLightReg=(char*)VirtualAlloc(0,0x400,MEM_RESERVE,PAGE_READWRITE)))
{
RETAILMSG(1,(TEXT("VirtualAlloc()failed!
\r\n")));
returnFALSE;
}
if(!
VirtualCopy((PVOID)pLightReg,(PVOID)(pLightIoBaseAddress>>8),0x400,PAGE_READWRITE|PAGE_NOCACHE|PAGE_PHYSICAL))
{
VirtualFree((PVOID)pLightReg,0,MEM_RELEASE);
pLightReg=NULL;
RETAILMSG(1,(TEXT("VirtualCopy()failed!
\r\n")));
returnFALSE;
}
if(!
v_pLEDBaseAddr||!
pLightReg)
{
DEBUGMSG(1,(TEXT("VirtualcopyError,Errorcode=%u\r\n"),GetLastError()));
return(FALSE);
}
WRITE_PORT_USHORT(v_pLEDBaseAddr[0],0xffff);
WRITE_PORT_USHORT(v_pLEDBaseAddr[1],0xffff);
WRITE_PORT_USHORT(v_pLEDBaseAddr[2],0xffff);
*pLightReg=black;
returnTRUE;
}
(3)驱动程序卸载函数DEM_Deinit:
当设备管理器卸载一个驱动程序时调用驱动程序卸载函数XXX_Deinit,该函数完成对系统资源的回收。
BOOLDEM_Deinit(DWORDhDeviceContext)
{
UINTi=0;
RETAILMSG(1,(TEXT("DEM_Deinit\r\n")));
for(i=0;i<3;i++)
{
MmUnmapIoSpace(v_pLEDBaseAddr[i],0);
v_pLEDBaseAddr[i]=NULL;
}
if(pLightReg)
{
MmUnmapIoSpace(pLightReg,0);
pLightReg=NULL;
}
if(m_hShiftEvent)
CloseHandle(m_hShiftEvent);
returnTRUE;
}
(4)驱动程序的读写操作DEM_Read、DEM_Write:
当一个流式接口驱动程序已经打开后,可以使用ReadFile()函数和WriteFile()函数对这个设备进行读写操作。
该驱动程序的读操作完成将LED的亮灭的情况输出,应用程序通过ReadFile()函数,写操作函数对四个七段数码管进行点亮。
具体实现函数如下:
DWORDDEM_Read(DWORDhOpenContext,LPVOIDpBuffer,DWORDCount)
{
UINTtemp;
temp=(UINT)ShiftData;
RETAILMSG(1,(TEXT("LED_Read\r\nhOpenContext=%d;*pBuffer=%d;Count=%d\r\n"),hOpenContext,temp,Count));
*(UINT*)pBuffer=temp;
returnTRUE;
}
DWORDDEM_Write(DWORDhOpenContext,LPCVOIDpSourceBytes,DWORDNumberOfBytes)
{
INTbuf=*(INT*)pSourceBytes;
USHORTData;
RETAILMSG(1,(TEXT("DEM_Write\r\nhOpenContext=%d;*pSourceBytes=%d;NumberOfBytes=%d\r\n"),hOpenContext,buf,NumberOfBytes));
buf=buf%10000;
Data=NumData[buf/1000];
buf=buf%1000;
Data|=NumData[buf/100]<<8;
WRITE_PORT_USHORT(v_pLEDBaseAddr[1],~(Data|BIT7|BIT15));
buf=buf%100;
Data=NumData[buf/10];
buf=buf%10;
Data|=NumData[buf]<<8;
WRITE_PORT_USHORT(v_pLEDBaseAddr[2],~(Data|BIT7|BIT15));
returnTRUE;
}
(5)IO控制函数DEM_IOControl
XXX_IOControl通常用于向设备发送一个命令,应用程序使用DeviceIOControl函数来通知操作系统调用该函数。
LED驱动程序的DEM_IOControl函数主要完成对八个LED发光二极管的流水左移、流水右移、流水循环、流水停止、点亮设置、流水移动时间间隔进行控制,采用线程完成流水操作。
BOOLDEM_IOControl(DWORDhOpenContext,DWORDdwCode,PBYTEpBufIn,DWORDdwLenIN,PBYTEpBufOut,DWORDdwLenOut,PDWORDpdwActualOut)
{
charData;
HANDLEm_hShiftThread=NULL;
RETAILMSG(1,(TEXT("LED_IOControl\r\nhOpenContext=%d;dwCode=%d\r\n"),hOpenContext,dwCode));
m_hShiftThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)LedShiftThread,NULL,0,NULL);
switch(dwCode)
{
caseLight_IOCTL_LShift:
m_ShiftDir=1;
SetEvent(m_hShiftEvent);
break;
caseLight_IOCTL_RShift:
m_ShiftDir=2;
SetEvent(m_hShiftEvent);
break;
caseLight_IOCTL_LRShift:
m_ShiftDir=3;
SetEvent(m_hShiftEvent);
break;
caseLight_IOCTL_Set:
Data=*(char*)pBufIn;
*pLightReg=~Data;
break;
caseLight_IOCTL_ShiftStop:
m_bStop=TRUE;
break;
caseLight_IOCTL_SetTime:
ShiftTime=*(UINT*)pBufIn;
break;
}
CloseHandle(m_hShiftThread);
returnTRUE;
}
INTWINAPILedShiftThread(void)
{
UINTi=0;
WaitForSingleObject(m_hShiftEvent,INFINITE);
while
(1)
{
switch(m_ShiftDir)
{
case1:
ShiftData=0x01;
for(i=0;i<8;i++)
{
*pLightReg=~ShiftData;
Sleep(ShiftTime);
ShiftData=ShiftData<<1;
if(m_bStop)
{
*pLightReg=0xff;
m_bStop=FALSE;
return0;
}
}
break;
case2:
ShiftData=0x80;
for(i=0;i<8;i++)
{
*pLightReg=~ShiftData;
Sleep(ShiftTime);
ShiftData=ShiftData>>1;
if(m_bStop)
{
*pLightReg=0xff;
m_bStop=FALSE;
return0;
}
}
break;
case3:
ShiftData=0x01;
for(i=0;i<8;i++)
{
*pLightReg=~ShiftData;
Sleep(ShiftTime);
ShiftData=ShiftData<<1;
if(m_bStop)
{
*pLightReg=0xff;
m_bStop=FALSE;
return0;
}
}
ShiftData=0x80;
for(i=0;i<8;i++)
{
*pLightReg=~ShiftData;
Sleep(ShiftTime);
ShiftData=ShiftData>>1;
if(m_bStop)
{
*pLightReg=0xff;
m_bStop=FALSE;
return0;
}
}
break;
default:
m_bStop=FALSE;
return0;
break;
}
}
return0;
}
其他实现函数如:
DEM_Open、DEM_PowerDown、DEM_PowerUp、DEM_Seek、DEM_Close参考提供的源代码文档。
(6)添加导出函数的定义。
在PlatformBuilder菜单中,选择File->NewProjectorFile->FileTab->TextFile,文件名叫“LedDriver.def”,内容如下:
LIBRARY"LedDriver"
EXPORTS
DEM_Init
DEM_Deinit
DEM_Open
DEM_Read
DEM_Write
DEM_PowerDown
DEM_PowerUp
DEM_Seek
DEM_IOControl
DEM_Close
(7)编译驱动程序项目。
结束后选择“BuildOS”->“OpenBuildReleaseDirectory”,然后输入命令:
dumpbin/exportsLedDriver.dll,确保输出结果如图11-3,表示驱动程序的DLL函数被正确导出。
图11-3驱动程序的函数导出图
3.2LED流式驱动程序的加载:
(1)选择“BuildOS”->“OpenBuildReleaseDirectory”,利用文本编辑器notepad修改平台的注册文件platform.reg,在文件最后添加如下内容:
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\LedDriver]
"Dll"="LedDriver.Dll"
"Prefix"="DEM"
"Index"=dword:
1
"Order"=dword:
0
"FriendlyName"="LEDDriver"
这段注册表信息告诉系统,在系统启动的时候把LedDriver.dll加载到device.exe,驱动的前缀是DEM,下标索引是1,这样,应用程序中可以使用CreateFile(L"DEM"……)这样的方式来访问驱动程序了。
(2)驱动程序固化
选择“BuildOS”->“OpenBuildReleaseDirectory”,利用文本编辑器notepad修改平台的配置文件platform.bib,将驱动程序LedDriver.dll文件固化到映像文件中在文件,在platform.bib文件中具体添加内容如下:
LedDriver.dll$(_FLATRELEASEDIR)\LedDriver.dllNKSH
③、生成映像文件
选择“BuildOS”->“MakeRun-TimeImage”生成映像文件,然后下载到目标板中。
4、LED流式接口驱动程序的应用测试
利用VS.net编写一个驱动程序的应用测试程序DriverApp。
具体实现如下:
●打开设备
voidCDriverAppDlg:
:
OnBnClickedbtnopendevice()
{
TCHARFileName[10]=TEXT("DEM1:
");
m_hFile=CreateFile((LPCTSTR)&FileName,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ,
NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(m_hFile==NULL){
MessageBox(_T("打开LED设备失败!
"),_T("系统信息"),MB_OK|MB_ICONINFORMATION);
}
}
●LED流水灯左移
voidCDriverAppDlg:
:
OnBnClickedbtnlshift()
{
if(m_hFile)
{
if(!
DeviceIoControl(m_hFile,Light_IOCTL_RShift,NULL,0,NULL,0,NULL,NULL))
{
MessageBox(_