HID设备打开

来源:互联网 发布:python cmdb django 编辑:程序博客网 时间:2024/06/04 18:14

如何与HID设备通讯(二)

三、读写HID设备的步骤

  读写HID设备步骤如下:

①、得到系统HID设备结构数组指针
②、对设备进行遍历
③、得到指定HID设备的句柄
④、readfile/writefile进行读写

  下面分别对各步骤及其所涉及的相关API函数进行介绍。

1、得到设备句柄:这步用到的两面个主要API函数原型为:

A、通过以下函数

 
  1. VOID  HidD_GetHidGuid(OUT LPGUID  HidGuid    );  

得到HID设备的GUID。

B、再通过以下函数

 
  1. HDEVINFO SetupDiGetClassDevs(   
  2.   CONST LPGUID ClassGuid,    
  3.   PCTSTR Enumerator,    
  4.   HWND hwndParent,    
  5.   DWORD Flags   
  6. );  

取得HID设备结构数组指针,以便下一步利用这个数组对所有HID设备进行遍列。

2、对设备进行遍历:遍历过程如下

A、首先执行以下函数:

 
  1. WINSETUPAPI BOOL WINAPI  SetupDiEnumDeviceInterfaces(   
  2.     IN HDEVINFO  DeviceInfoSet,   
  3.     IN PSP_DEVINFO_DATA  DeviceInfoData  OPTIONAL,   
  4.     IN LPGUID  InterfaceClassGuid,   
  5.     IN DWORD  MemberIndex,   
  6.     OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData);  

运行此函数的主要目的是取得第一个参数DeviceInfoSet的填充值,又将此值作为以下函数

 
  1. BOOL SetupDiGetDeviceInterfaceDetail(   
  2.     HDEVINFO DeviceInfoSet,    
  3.     PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,    
  4.     PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData,    
  5.     DWORD DeviceInterfaceDetailDataSize,    
  6.     PDWORD RequiredSize,    
  7.     PSP_DEVINFO_DATA DeviceInfoData);   

的第一个参数,以便取得这个函数的第三个参数DeviceInterfaceDetailData的填充值,然后利用这个值传递给CreateFile函数,此时CreateFile会返回一个指向HID设备的句柄,再根据以下函数

 
  1. BOOLEAN  HidD_GetAttributes(   
  2.     IN HANDLE  HidDeviceObject,   
  3.     OUT PHIDD_ATTRIBUTES  Attributes   
  4.     );  

取得此HID设备的属性(第二个参数的填充值),然后判断属性里的PID(Attributes->ProductID)和VID(Attributes->VendorID)是否是我们要查找的设备的PID和VID。PID和VID在下位机固件代码的设备描述符里提供(设备描述里的idProduct域和idVendor,参考百合电子工作室发表的文章《USB开发基础--USB命令(请求)和USB描述符》一文中表4),当然您也可以通过一些工具查询得到PID和VID,您可以到USB组织官方网站www.usb.org下载这类工具。

3、根据得到的设备句柄利用ReadFile和WriteFile对设备进行读写操作。

  百合电子工作室已经将以上步骤封装成了一个HID类(参考了其它一些实例代码),它能实现对指定PID和VID设备的查找,并实现了数据收发功能,同时具有设备拨插检测通知功能。点击这里下载

下面用实例说明如何使用这个类。

 四、读写HID设备实例

实例 1

1、找开Visual C++ 6.0,新建一基于MFC的工程名为:Easy USB 51 Programer Test1。

2、MFC AppWizard Step 1对话框中选择基于对话框的应用程序,然后点“Finish”按钮,如图所示:

3、创建3个静态文本标签(Static Text),文本内容分别为:Write、Read和Message;创建两个文本框和一个列表框,ID分别为:IDC_EDIT_TX、IDC_EDIT_RX和IDC_LIST_MESSAGE;两个按钮ID和文本分别为:IDC_BTN_WRITE(Write)和IDCANCEL(Exit)。界面如下:

4、添加控件所对应的变量,如下图所示:

5、将Hid.c和Hid.h导入工程,并将“要用到的windows ddk里的几个文件”文件夹内的文件复制到工程所在目录,在Procect->Settings->Link页的“Object/Library moudles”设置中添加“hid.lib setupapi.lib”,如下图所示:

6、在stdafx.h文件中包含头文件语句前添加:#define WINVER  0x0500

7、修改Hid.c中的PID和VID宏定义来设置需要访问的HID设备,此处的PID和VID值分别为0x0666和0x0471:

 
  1. #define VID 0x0471   
  2. #define PID 0x0666  

8、在CEasyUSB51ProgramerTest1Dlg类中添加成员变量m_MyHidDevice,其定义如下

 
  1. CHid m_MyHidDevice;  

当然您得包含头文件Hid.h。

9、在CEasyUSB51ProgramerTest1Dlg类的OnInitDialog函数中添加如下语句:

 
  1. m_MyHidDevice.m_hParentWnd (HANDLE*) this->GetSafeHwnd( );   
  2. if(m_MyHidDevice.FindHid())     //找到指定HID设备  
  3. {   
  4.     m_ctrlMessage.InsertString(-1,"My hid device detected");   
  5. }   
  6. else                            //没有找到指定HID设备  
  7. {   
  8.     m_ctrlMessage.InsertString(-1,"My hid device not detected");   
  9.     m_ctrlWrite.EnableWindow(FALSE);    //禁用"write"按钮  
  10.  

10、在CEasyUSB51ProgramerTest1Dlg的消息映射中(“BEGIN_MESSAGE_MAP(CEasyUSB51ProgramerTest1Dlg, CDialog)” 与 “END_MESSAGE_MAP()”之间)添加如下代码:

 
  1. ON_MESSAGE(WM_DEVICECHANGE, OnDeviceChange)  

11、在CEasyUSB51ProgramerTest1Dlg类中添加成员函数:

 
  1. LRESULT OnDeviceChange(WPARAM wParam, LPARAM lParam);  

12、成员函数OnDeviceChange的结构如下:

 
  1. LRESULT CEasyUSB51ProgramerTest1Dlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)   
  2. {   
  3.        
  4.       
  5.     switch(LOWORD(wParam))    
  6.     {   
  7.            
  8.           
  9.         case DBT_DEVICEARRIVAL:   
  10.         {   
  11.               
  12.             if(m_MyHidDevice.FindHid())   
  13.             {   
  14.                   
  15.                                  
  16.             }   
  17.             break;   
  18.         }   
  19.   
  20.           
  21.         case DBT_DEVICEREMOVECOMPLETE:   
  22.         {   
  23.             if(!m_MyHidDevice.FindHid())      
  24.             {   
  25.                   
  26.                                  
  27.             }   
  28.             break;   
  29.         }   
  30.     }   
  31.   
  32.     return true;   
  33.  

13、这里为了实现在Message信息框里显示HID设备的拨插操作,现对OnDeviceChange函数作如下填充:

 
  1. LRESULT CEasyUSB51ProgramerTest1Dlg::OnDeviceChange(WPARAM wParam, LPARAM lParam)   
  2. {   
  3.        
  4.       
  5.     switch(LOWORD(wParam))    
  6.     {   
  7.            
  8.           
  9.         case DBT_DEVICEARRIVAL:   
  10.         {   
  11.               
  12.             if(m_MyHidDevice.FindHid())   
  13.             {   
  14.                   
  15.                   
  16.                 unsigned short nIndex   m_ctrlMessage.InsertString(-1,"My hid device detected");   
  17.                 m_ctrlMessage.SetCurSel(nIndex);    //流动信息窗口  
  18.                 m_ctrlWrite.EnableWindow(TRUE);     //启用"write"按钮  
  19.             }   
  20.             break;   
  21.         }   
  22.   
  23.           
  24.         case DBT_DEVICEREMOVECOMPLETE:   
  25.         {   
  26.             if(!m_MyHidDevice.FindHid())      
  27.             {   
  28.                   
  29.                   
  30.                 unsigned short nIndex   m_ctrlMessage.InsertString(-1,"My hid device removed");   
  31.                 m_ctrlMessage.SetCurSel(nIndex);    //流动信息窗口  
  32.                 m_ctrlWrite.EnableWindow(FALSE);    //禁用"write"按钮  
  33.             }   
  34.             break;   
  35.         }   
  36.     }   
  37.   
  38.     return true;   
  39.  

 14、对HID的读写可通过Hid类的成员函数WriteHid和ReadHid。以下是"write"按钮的响应函数,实现对HID设备的读写操作:

 
  1. void CEasyUSB51ProgramerTest1Dlg::OnBtnWrite()    
  2. {   
  3.     unsigned char ucTxBuffer[64];   //发送缓冲  
  4.     unsigned char ucRxBuffer[64];   //接收缓冲  
  5.   
  6.     UpdateData(TRUE);   
  7.   
  8.     //判断发送框中内容是否超过64字节   
  9.     if(m_strTx.GetLength()>64)   
  10.     {   
  11.         AfxMessageBox("发送字节数不能超过64个字节");   
  12.     }   
  13.   
  14.     //准备发送缓冲区中的内容   
  15.     for(int i=0; i<64 i++)   
  16.     {   
  17.         if(i <= (m_strTx.GetLength()-1) )   
  18.             ucTxBuffer[i]   m_strTx.GetAt(i);   
  19.         else  
  20.             ucTxBuffer[i]   0;   
  21.     }   
  22.   
  23.     //写操作   
  24.     m_MyHidDevice.WriteHid(ucTxBuffer,64);   
  25.     //读操作   
  26.     m_MyHidDevice.ReadHid(ucRxBuffer,64);   
  27.   
  28.     m_strRx     ucRxBuffer;   
  29.     UpdateData(FALSE);   
  30.  

完成后的实际效果:

下载程序

下载源代码

实例 2

  此例子需要用到扩展板:EXT-BOARD-A。实现功能为通过上位机设定 EXT-BOARD-A 上的8个发光二极管状态。

 1、命令及数据定义

  下位机已经规定了每帧数据的长度为64个字节,我们现在需要对每一个字节的含义作出定义。在这个实例中,我们可作如下规定:每帧数据前5个字节为命令,命令后面紧跟数据(从第6个字节开始)。命令为ASCII编码,在此实例中只有一个命令“ENLED”,代表设备LED状态。命令后面的一个字节为数据,代表D0~D7八个LED的状态,后面的字节无意义。

2、修改下位机程序

  修改main.c文件,其内容如下:

 
  1.   
  2.   
  3. //#include <at89x52.h>   
  4. #include <reg51.h>   
  5. #include "D12Config.h"   
  6. #include "Descriptor.h"   
  7. #include "Chap_9.h"   
  8. #include "D12Driver.h"   
  9. #include <string.h>   
  10.   
  11. main()   
  12.      
  13.     unsigned char ucLedState;   
  14.        
  15.     if (Init_D12()!=0)                  //初始化D12  
  16.         return                        //如果初始化不成功,返回  
  17.        
  18.     IT0 0;                            //外部中断0为电平触发方式  
  19.        
  20.     EX0 1;                            //开外部中断0  
  21.     PX0 0;                            //设置外部中断0中断优先级  
  22.     EA 1;                             //开80C51总中断   
  23.        
  24.     while(1)   
  25.     {   
  26.         usbserve();                     //处理USB事件  
  27.         if(bEPPflags.bits.configuration)       
  28.               
  29.             //在这里添加端点操作代码    
  30.                
  31.             if(bEPPflags.bits.ep2_rxdone  //主端点接收到数据(从主机发往设备的数据)      
  32.                   
  33.                 bEPPflags.bits.ep2_rxdone       0;           
  34.                    
  35.                 //判断是否是 ENLED 命令(EpBuf的前5个字节为”ENLED“)           
  36.                 if(strncmp("ENLED",EpBuf,5)==0)   
  37.                 {   
  38.                     //取得LED状态设定值  
  39.                     ucLedState  EpBuf[5];   
  40.                        
  41.                     //设定LED状态  
  42.                     P0  ucLedState;   
  43.                                          
  44.                    
  45.             
  46.     }   
  47. }   

 点击这里下载修改好的源代码

 3、上位机程序

  通过实例1的学习,其实上位机程序的编写非常简单,所以在这里只贴出源代码。

                                          
            

              上位机界面                                               LED的状态由上位机控制

 

http://blog.sina.com.cn/s/blog_484dff580100kq62.html

下载程序路径:D:\Yifei\Download\USB\应用实例\httpblog.sina.com.cnsblog_484dff580100kq62.html

1 0
原创粉丝点击