转:WinCE应用程序如何调用驱动程序

下面针对流式程序:
流式程序主要是对IO口进行控制的。下面主要是对LED的控制。
    在驱动程序里面有个xxx_iocontrol()函数(xxx为驱动的名字),这个函数主要是对IO口的控制,
你要对IO口实现怎样的控制都可以在这里编写。比如:
BOOL LED_IOControl(DWORD hOpenContext, //XXX_Open返回给上层的那个句柄
       DWORD dwCode, //IO操作码
       PBYTE pBufIn, //传入的Buffer,每个IO操作码都会定义自已的Buffer结构
       DWORD dwLenIn, //以字节记的大小
       PBYTE pBufOut, //分别为传出的Buffer,及其以字节记的大小
       DWORD dwLenOut, 
       PDWORD pdwActualOut)
{
 switch(dwCode)
 {
 case IO_CTL_GPIO_1_ON:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0x1<<4);
  break;
 case IO_CTL_GPIO_2_ON:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0x1<<5);
  break;
 case IO_CTL_GPIO_3_ON:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0x1<<6);
  break;
 case IO_CTL_GPIO_4_ON:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0x1<<7);
  break;
 case IO_CTL_GPIO_ALL_ON:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0xF<<4);
  break;
 case IO_CTL_GPIO_1_OFF:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0x1<<4);
  break;
 case IO_CTL_GPIO_2_OFF:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0x1<<5);
  break;
 case IO_CTL_GPIO_3_OFF:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0x1<<6);
  break;
 case IO_CTL_GPIO_4_OFF:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0x1<<7);
  break;
 case IO_CTL_GPIO_ALL_OFF:
  v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0xF<<4);
  break;
 default:
  break;
 }
    
 RETAILMSG(1,(TEXT("LED_Control:Ioctl code = 0x%x/r/n"), dwCode));
 return TRUE;

  调用它的是DeviceIoControl()在应用程序里面,实现对GPIO的控制(高低电平控制)
如:
void CFlowLEDDlg::OnLedOn() 
{
 // TODO: Add your control notification handler code here
 BOOL ret;
 
 ret=::DeviceIoControl(hFile,IO_CTL_GPIO_ALL_ON,NULL, 1,NULL,0,NULL,NULL);
 
 if(ret!=TRUE)
  
 {
  
  MessageBox(_T("关闭LED失败!"));
  
  MessageBox(_T("请打开GPIO驱动!"));
  
 }


 
}
看到没IO_CTL_GPIO_ALL_ON与LED_IOControl()语句是不是对应呢,当你按下该建后,
就会执行LED_IOControl()中的:
case IO_CTL_GPIO_1_ON:
v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&~(0x1<<4);
break;
也就灯亮。
解析:ret=::DeviceIoControl(hFile,IO_CTL_GPIO_ALL_ON,NULL, 1,NULL,0,NULL,NULL);
ret定义的是一个bool值,::是作用域标识符,它的意思是调用的全局函数。调用的系统的API
从当前窗口中得到该改窗口的值。


 当然在试验之前我们需要打开驱动,像上面一样,在底层驱动里面的函数为:
DWORD LED_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)
{
 v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT|(0xF<<4);  //这里是打开gpio的:5 6 7 8

 RETAILMSG(1,(TEXT("LED_Control: LED_Open/r/n")));
 return TRUE;
}

  同样在应用程序里面调用的是:CreateFile()函数来打开该驱动。
void CFlowLEDDlg::OnOpenGpio() 
{
 // TODO: Add your control notification handler code here
 hFile=CreateFile(TEXT("LED0:"),GENERIC_READ | GENERIC_WRITE,0, NULL,OPEN_EXISTING,0,0);
                 //若打开怎返回一个不为INVALID_HANDLE_VALUE的句柄。
 if(hFile==INVALID_HANDLE_VALUE)
 {
          MessageBox(_T("打开GPIO驱动失败!"));
 } 
 else
 {
   MessageBox(_T("打开GPIO驱动成功!")); 
 } 
  
}
其中:

 “LED0:”中的表示设备好“0”是必需的,不管你的设备当中是不是刚好只有一个,不然的话
会出现打开不了这个设备的情况。
   当用户程序调用CreateFile打开这个设备时,设备管理器就会调用此驱动程序的XXX_Open函数
同理:有打开驱动必然有关闭驱动, 
在底层驱动里面的函数为:
BOOL LED_Close(DWORD hOpenContext)
{
       v_pIOPregs->GPFDAT=v_pIOPregs->GPFDAT&(0xF<<4);
       RETAILMSG(1,(TEXT("LED_Control: LED_Close/r/n")));
       return TRUE;
}
在应用程序里面对应的是:
void CFlowLEDDlg::OnCloseGpio() 
{
 // TODO: Add your control notification handler code here
 if(hFile!=INVALID_HANDLE_VALUE)
 {
          CloseHandle(hFile);
   MessageBox(_T("关闭GPIO驱动成功!"));
  
 }
 
 else
 { 
    MessageBox(_T("关闭GPIO驱动失败!"));
 }

}

总结:
    用应用程序控制GPIO的时候,第一打开驱动,当我们按下打开驱动按键的时候,应用程序执行的
是CreateFile()函数,当CreateFile()打开设备管理器的时候,设备管理器就会调用XXX_Open()
函数打开此驱动程序
   关闭驱动的时候可以直接调用CloseHandle关闭这个设备句柄时,LED_Close()函数就会被设备
管理器调用来关闭驱动。
   当驱动打开后,就可以对GPIO进行操作了,当用户想叫那个LED亮的时候,按下此键,应用程序
执行DeviceIoControl()函数,通过其第二参数的返回值来调用底层驱动函数LED_IOControl()
函数。灯灭函数同理。

posted on 2017-04-24 19:56  humbird  阅读(249)  评论(0编辑  收藏  举报

导航