STM32高級教程之USB HID雙向數據傳輸

程序功能:
1,將STM32的USB枚舉爲HID設備。
2,STM32使用3個端點,端點0用於枚舉用,端點1和2用於數據的發送和接收。

3,端點長度爲64,也就是單次最多可以傳輸64個字節數據。

4,STM32獲取上位機下發的數據並將該數據通過USB原樣返回,同時將數據打印輸出。
5,上位機程序通過調用windows的API實現對HID設備的讀寫控制。

原理圖:
 
說明:實際測試的時候不用這麼複雜的電路,接好PA11和PA12即可,當然在PA12引腳上需要一個上拉電阻,其他電路都可以省略。

HID枚舉成功:
 
說明:枚舉成功後會自動安裝HID驅動,無需單獨安裝。

上位機程序運行效果圖:
 
說明:上位機程序是在VS2010環境下寫的,不過可以根據自己需求移植到其他環境中。

單片機運行輸出:
 
說明:單片機端採用超級終端輸出相關信息,使用的USART1串口,也就是PA9和PA10兩個引腳。

Bus Hound抓取數據截圖:
 
說明:Bus Hound是一個很不錯的數據抓包工具,調試USB程序相當有用。

部分程序源碼:
STM32的報告描述符:
[C] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
{
        0x05, 0x8c, /* USAGE_PAGE (ST Page) */
        0x09, 0x01, /* USAGE (Demo Kit) */
        0xa1, 0x01, /* COLLECTION (Application) */
         
        // The Input report
        0x09,0x03, // USAGE ID - Vendor defined
        0x15,0x00, // LOGICAL_MINIMUM (0)
        0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255)
        0x75,0x08, // REPORT_SIZE (8bit)
        0x95,0x40, // REPORT_COUNT (64Byte)
        0x81,0x02, // INPUT (Data,Var,Abs)
 
        // The Output report
        0x09,0x04, // USAGE ID - Vendor defined
        0x15,0x00, // LOGICAL_MINIMUM (0)
        0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255)
        0x75,0x08, // REPORT_SIZE (8bit)
        0x95,0x40, // REPORT_COUNT (64Byte)
        0x91,0x02, // OUTPUT (Data,Var,Abs)
 
        0xc0 /* END_COLLECTION */
}; /* CustomHID_ReportDescriptor */


上位機測試程序:
[C] 純文本查看 複製代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
  * @brief  發送數據後讀取數據
  * @param  None
  * @retval None
  */
void HIDSampleFunc(void)  
{      
        HANDLE       hDev;      
        BYTE         recvDataBuf[1024],reportBuf[1024];;                  
        DWORD        bytes;      
        hDev = OpenMyHIDDevice(0); // 打開設備,不使用重疊(異步)方式 ;     
        if (hDev == INVALID_HANDLE_VALUE){          
                printf("INVALID_HANDLE_VALUE\n");
                return
        }
        reportBuf[0] = 0; // 輸出報告的報告 ID 是 0     
        for(int i=0;i<REPORT_COUNT;i++){
                reportBuf[i+1]=i+1;//將數據存放在數據緩衝區
        }
        printf("開始寫數據到設備...\n");
        // 寫入數據到設備,注意,第三個參數值必須爲REPORT_COUNT+1,否則會返回1784錯誤
        if (!WriteFile(hDev, reportBuf, REPORT_COUNT+1, &bytes, NULL)){          
                printf("write data error! %d\n",GetLastError());
                return;   
        }else{
                printf("成功向設備寫出%d個數據... \n",bytes);
        }
        printf("開始從設備讀取數據...\n");
        // 從設備讀取數據,注意,第三個參數值必須大於等於REPORT_COUNT+1,否則會返回1784錯誤
        if(!ReadFile(hDev, recvDataBuf, REPORT_COUNT+1, &bytes, NULL)){ // 讀取設備發給主機的數據 
                printf("read data error! %d\n",GetLastError());
                return;   
        }else{
                printf("成功向設備讀出%d個數據... \n",bytes);
        }
        printf("設備返回的數據爲:\n");
        //顯示讀取回來的數據
        for(int i=0;i<REPORT_COUNT;i++){
                printf("0x%02X ",recvDataBuf[i+1]);
        }
        printf("\n\r");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章