網站導航:首頁開源項目 USB開源項目:Easy USB 51 Programer  

目錄導航

   
  1、項目簡介
USB開發基礎
1、USB接口的優點及開發難易度
2、USB設備的開發流程
3、USB接口芯片(USB控制器)的選擇
4、了解USB的通訊過程
5、USB命令(請求)和USB描述符
6、實例講解USB的枚舉(配置)過程
准備工作
1、需要哪些工具
2、電路原理圖
3、手工制作您的電路板
4、測試您的硬件
HID設備類
1、讓PC機找到我們的硬件
2、如何成爲一個HID設備(模擬鼠標)
3、如何成爲一個HID設備(模擬鍵盤)
4、如何與HID設備通訊(一)
5、如何與HID設備通訊(二)
6、51編程器的實現
Windows USB 驱动程序(自定义设备)
1、Windows驅動開發基礎
2、開發環境配置
3、第一个实例-Hello Wdm(一)
4、第一个实例-Hello Wdm(二)
5、真正的實例—驅動我們的實驗板
6、真正的實例—測試驅動程序
7、真正的實例—控制LED及讀取按鍵狀態
8、如何編寫應用程序
   

相关産品    淘寶網店
     
 

 
  更多...  
 
 
如何編寫應用程序 查看/参与此開源項目相关讨论
 

說明:以下內容針對VC6環境

  雖然利用DriverStudio的工程向導爲我們生成了測試程序示例,但它大量使用了DriverStudio自己的封裝庫,現在來介紹在不使用DriverStudio封裝庫的情況下如何編寫測試程序。

1、打開設備的兩種方式

  我们知道打开设备用CreateFile函数,其第一个参数应指向欲打开的USB设备,它可以是Device Interface,也可以是Device Symbolic Link(设备连接符或叫设备名)。要么用Interface打开USB设备,要么用Symbolic Link打开(不知正确与否),在利用DriverStudio工程向导生成时USB驱动程序的过程中可选择应用程序打开此USB设备的方式(见下图),在这时就确定了将来该用何种方式来打开设备。

1)用Interface方式打開設備

  首先取得設備的GUID(什麽是GUID請看這篇文章:USB編程之二(常見設備類型的GUID)),然後利用設備GUID來得到設備Interface,最後就可以用CreateFile函數來打開設備了。

  GUID由驅動程序定義,如上一節的驅動程序實例中對GUID的定義如下:

 
  1. #define Easy_USB_51_ProgramerDevice_CLASS_GUID \   
  2.  { 0x47589a1e, 0xad02, 0x455e, { 0xa9, 0xf7, 0xcc, 0xb2, 0xd5, 0xe, 0x68, 0x54 } }   

  还可以利用第三方工具取得设备GUID,如USBView,还有DriverStudio自带的Symbolic Viewer),下面是用Symbolic Viewer查得的上一節驱动实例的GUID

我們這裏利用DEFINE_GUID宏來定義設備GUID,內容如下:

 
  1. DEFINE_GUID(Easy_USB_51_ProgramerDevice_CLASS_GUID,   
  2.     0xC713541C, 0x3C65, 0x474A, 0x8E, 0xBC, 0x25, 0x87, 0x51, 0x49, 0xD2, 0x05);   

DEFINE_GUID宏在initguid.h中定義的,所以需要在加入對此文件的引用:

 
  1. #include "initguid.h"  

  另外,我們將要用到的一些函數需要setupapi.h和setupapi.lib,它們是VC6自帶的,所以需要添加對這兩個文件的引用:

①#include "Setupapi.h"

②选择菜单“Project”->“Settings”,切换到“Link”页,在“Object/library modules”中填入:setupapi.lib

  好了,現在貼出以Interface方式打開設備的代碼:

 
  1. //以Device Interface方式打開設備   
  2. void CWR_CtrlLEDDlg::OnOpendevByInterface()    
  3. {   
  4.     LONG                                ii = 0;   
  5.     HDEVINFO                            hDeviceInfo;   
  6.     DWORD                               bufferSize;   
  7.     SP_DEVICE_INTERFACE_DATA            interfaceData;   
  8.     PSP_DEVICE_INTERFACE_DETAIL_DATA    deviceDetail;   
  9.   
  10.      // Find all devices that have our interface   
  11.     hDeviceInfo = SetupDiGetClassDevs(   
  12.                     (LPGUID)&Easy_USB_51_ProgramerDevice_CLASS_GUID,       
  13.                     NULL,   
  14.                     NULL,   
  15.                     DIGCF_PRESENT | DIGCF_DEVICEINTERFACE   
  16.                     );   
  17.     if (hDeviceInfo == INVALID_HANDLE_VALUE)   
  18.     {   
  19.         AfxMessageBox("SetupDiGetClassDevs failed");   
  20.         return;   
  21.     }   
  22.   
  23.     // Setup the interface data struct   
  24.     interfaceData.cbSize = sizeof(interfaceData);   
  25.   
  26.     for (ii = 0;   
  27.         SetupDiEnumDeviceInterfaces(   
  28.             hDeviceInfo,   
  29.             NULL,   
  30.             (LPGUID)&Easy_USB_51_ProgramerDevice_CLASS_GUID,               
  31.             ii,   
  32.             &interfaceData);   
  33.         ++ii)   
  34.     {   
  35.         // Found our device instance   
  36.         if (!SetupDiGetDeviceInterfaceDetail(   
  37.             hDeviceInfo,   
  38.             &interfaceData,   
  39.             NULL,   
  40.             0,   
  41.             &bufferSize,   
  42.             NULL))   
  43.         {   
  44.             if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)   
  45.             {   
  46.                 TRACE("Error: couldn't get interface detail\n");   
  47.                    
  48.                 continue;   
  49.             }   
  50.         }   
  51.            
  52.         // Allocate a big enough buffer to get detail data   
  53.         deviceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(bufferSize);   
  54.         if (deviceDetail == NULL)   
  55.         {   
  56.             TRACE("Error: Buffer allocation failed\n");   
  57.             continue;   
  58.         }   
  59.            
  60.         // Setup the device interface struct   
  61.         deviceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);   
  62.            
  63.         // Try again to get the device interface detail info   
  64.         if (!SetupDiGetDeviceInterfaceDetail(   
  65.             hDeviceInfo,   
  66.             &interfaceData,   
  67.             deviceDetail,   
  68.             bufferSize,   
  69.             NULL,   
  70.             NULL))   
  71.         {   
  72.             TRACE("Error: SetupDiGetDeviceInterfaceDetail failed\n");   
  73.             free(deviceDetail);   
  74.             continue;   
  75.         }         
  76.                
  77.            
  78.         SetupDiDestroyDeviceInfoList(hDeviceInfo);   
  79.            
  80.         // Open handle to device   
  81.         m_hDev = CreateFile(   
  82.             deviceDetail->DevicePath,   
  83.             GENERIC_READ | GENERIC_WRITE,   
  84.             FILE_SHARE_READ | FILE_SHARE_WRITE,   
  85.             NULL,   
  86.             OPEN_EXISTING,   
  87.             0,   
  88.             NULL   
  89. );         
  90.            
  91.         // Free our allocated buffer   
  92.         free(deviceDetail);   
  93.            
  94.         if (m_hDev == INVALID_HANDLE_VALUE)   
  95.         {   
  96.             AfxMessageBox("Error: CreateFile failed\n");   
  97.             return;   
  98.         }   
  99.            
  100.         AfxMessageBox("設備成功打開!");   
  101.            
  102.         GetDlgItem(IDC_BTN_OPENDEV_BY_INTERFACE)->EnableWindow(FALSE);   
  103.         GetDlgItem(IDC_BTN_OPENDEV_BY_NAME)->EnableWindow(FALSE);   
  104.            
  105.         EnableControl(TRUE);   
  106.     }   
  107. }   

2)用Symbolic Link方式打开设备

  Driver Studio通过KUnitizedName函数生成设备的Symbolic Link,我们再利用CreateFile来打开设备,其一般形式为:

 
  1. hDevice = CreateFile("\\\\.\\OMNIPORT3",   
  2.          GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ,   
  3.          NULL,    
  4. OPEN_EXISTING,    
  5. FILE_ATTRIBUTE_NORMAL ,   
  6. NULL);   

其中前缀“\\\\.\\”表示Createfile试图打开一个设备,然后紧跟设备名,其设备名可以利用DDK提供的“Device Tree”工具来查询,也可以查看DriverStudio向导生成的代码中KUnitizedName实例代码(位于AddDevice功能函数内),如果第一个参数为:L”TestDevice”,则设备名一般应为TestDevice0

  在上一節实例中生成的驱动程序是以Interface方式打开的,现在我们重新配置此项目,在配置向导第“Step 12 of 14”中,打开设备(Open Device)选择“Symbolic Link”选项,并填写Symbolic Link的值为:Easy_USB_51_Programer_SymbolicDevice:

下載編譯後驅動

下載驅動源碼(需要放到C:\Easy_USB_51_Programer_Symbolic目錄)

  安装驱动程序,然后就可以用Symbolic Link的方式打开设备了,而Symbolic Link的值就应该为Easy_USB_51_Programer_SymbolicDevice0,这个值在配置向导第“Step 12 of 14”中已经填好(但其后要加“0”),通过查看驱动源程序也可以得到(位于AddDevice功能函数的KUnitizedName实例代码的第一个参数),也可用第三方工具如Symbolic Link Viewer查询,下图是利用DriverStudio提供的Symbolic Link Viewer工具查询到的Symbolic Link值:

  好了,现在贴出以Symbolic Link方式打开设备的代码:

 
  1. //利用Symbolic link來打開設備   
  2. void CWR_CtrlLEDDlg::OnOpendevBySymbolicLink()    
  3. {   
  4.     char *sLinkName = "\\\\.\\Easy_USB_51_Programer_SymbolicDevice0";   
  5.   
  6.     m_hDev  = CreateFile(sLinkName,   
  7.                       GENERIC_READ | GENERIC_WRITE,   
  8.                       FILE_SHARE_READ,   
  9.                       NULL,   
  10.                       OPEN_EXISTING,   
  11.                       0,   
  12.                       NULL);       
  13.        
  14.     if (m_hDev == INVALID_HANDLE_VALUE)   
  15.     {   
  16.         AfxMessageBox("Error: CreateFile failed");   
  17.         return;   
  18.     }   
  19.   
  20.     AfxMessageBox("設備成功打開!");   
  21. }   

2、讀寫設備

  读写设备除了可以通过WriteFile和ReadFile函数以外,还可以利用DeviceIoControl函数。WriteFile最终会调用驱动程序的IRP_MJ_READ实例代码(DriverStudio里是Write实例函数),ReadFile最终会调用驱动程序的IRP_MJ_ WRITE实例代码(DriverStudio里是Read实例函数),而DeviceIoControl最终会调用驱动程序的IRP_MJ_DEVICE_CONTROL实例代码(DriverStudio里是DeviceControl)。

  DeviceIoControl的第二个参数为操作代码,在驱动程序里的定义形如IOCTL_XXXX格式,对于自定义的设备操作代码,一般用CTL_CODE宏定义,我们需要拷贝上一節驱动程序中对IOCTL_LED和IOCTL_GET_KEY两个操作代码的定义(在使用前需要包含头文件:#include "Winioctl.h")

 
  1. #define IOCTL_LED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA)   
  2. #define IOCTL_GET_KEY CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)   

  下面放上利用MFC編寫的一個基于對話的程序,它主要實現與上一節中測試程序相似的功能(通過端點2讀寫數據,通過控制端點控制擴展板EXT-BOARD-A上的LED狀態,通過控制端點讀取擴展板EXT-BOARD-A上的按鍵的狀態),另外還測試了兩種打開設備的方式(設備安裝驅動程序後就決定了設備只能以某一種方式打開,用不正確的方式打開會報錯)。

                           应用程序界面

(呵呵,我已經投PCB了,所以沒有用手工制作的那個原始東東來展示)

編譯好的應用程序
應用程序源代碼

這裏再次放上下位機的固件程序及其源代碼,還有兩種以不同方式打開設備的Windows驅動程序及源代碼
下位機固件源代碼
Windows驅動程序
(只能以Interface方式打開)
Windows驅動程序源代码(只能以Interface方式打開)
Windows驅動程序(只能以Symbolic Link方式打开)
Windows驅動程序源代码(只能以Symbolic Link方式打开)
 

 
 
 
本站程序由百合電子工作室開發和維護
Copyright @ baihe electric studio
渝ICP備09006681號-4