日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

USB自定义HID设备实现-STM32

發(fā)布時(shí)間:2025/3/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 USB自定义HID设备实现-STM32 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

該文檔使用USB固件庫(kù),在其基礎(chǔ)上進(jìn)行了自己的定制,完成了一個(gè)USB-HID設(shè)備,首先是usb_desc.c文件,里面存放了usb各種描述符的存在

#include "usb_desc.h"

?

//usb標(biāo)準(zhǔn)設(shè)備描述符

const u8 DinkUsbDeviceDescriptor[DINK_USB_SIZ_DEVICE_DESC] = {

?

??? USB_DEVICE_DESC_SIZE,???????????? //bLength字段。設(shè)備描述符的長(zhǎng)度為18(0x12)字節(jié)

??? USB_DEVICE_DESCRIPTOR_TYPE,??????? ?? //bDescriptorType字段。設(shè)備描述符的編號(hào)為0x01

??? WBVAL(0x0200), ??????????? ????????? //bcdUSB字段。這里設(shè)置版本為USB1.1,即0x0110。

??? 0x00,???????????????????????????? //bDeviceClass字段。我們不在設(shè)備描述符中定義設(shè)備類(lèi),

??? 0x00,????????????????????????????? //bDeviceSubClass字段。bDeviceClass字段為0時(shí),該字段也為0。

??? 0x00,??????????????????????????? ? //bDeviceProtocol字段。bDeviceClass字段為0時(shí),該字段也為0。

??? 0x40,???????????????? ????????????? //bMaxPacketSize0字段。端點(diǎn)0的最大包長(zhǎng)度。

??? WBVAL(0x7777),??????????????????? ?? //idVender字段。廠商ID號(hào),我們這里取0x8888,僅供實(shí)驗(yàn)用。

??? WBVAL(0x8888),??????????????????? ?? //idProduct字段。產(chǎn)品ID號(hào),由于是第一個(gè)實(shí)驗(yàn),我們這里取0x0001。\。

??? WBVAL(0x0100), ???????? ?????????? // 設(shè)備的版本

??? 0x01,???????????????????????????? //iManufacturer字段。廠商字符串的索引值,為了方便記憶和管理

??? 0x02,???????????????????????????? //iProduct字段。產(chǎn)品字符串的索引值。剛剛用了1,這里就取2吧。

??? 0x03,??????????????????????????? ? //iSerialNumber字段。設(shè)備的序列號(hào)字符串索引值。

??? 0x01????????????????? ????????????? //bNumConfigurations字段。該設(shè)備所具有的配置數(shù)。

};

?

?

//USB報(bào)告描述符的定義

const u8 HID_ReportDescriptor[]=

{

0x06,0xA0,0xFF,//用法頁(yè)(FFA0h, vendor defined)

0x09, 0x01,//用法(vendor defined)

0xA1, 0x01,//集合(Application)

0x09, 0x02 ,//用法(vendor defined)

0xA1, 0x00,//集合(Physical)

0x06,0xA1,0xFF,//用法頁(yè)(vendor defined)

//輸入報(bào)告

0x09, 0x03 ,//用法(vendor defined)

0x09, 0x04,//用法(vendor defined)

0x15, 0x80,//邏輯最小值(0x80 or -128)

0x25, 0x7F,//邏輯最大值(0x7F or 127)

0x35, 0x00,//物理最小值(0)

0x45,0xFF,//物理最大值(255)

0x75, 0x08,//報(bào)告長(zhǎng)度Report size (8位)

0x95, 0x40,//報(bào)告數(shù)值(64 fields)

0x81, 0x02,//輸入(data, variable, absolute)

//輸出報(bào)告

0x09, 0x05,//用法(vendor defined)

0x09, 0x06,//用法(vendor defined)

0x15, 0x80,//邏輯最小值(0x80 or -128)

0x25, 0x7F,//邏輯最大值(0x7F or 127)

0x35, 0x00,//物理最小值(0)

0x45,0xFF,//物理最大值(255)

0x75,0x08,//報(bào)告長(zhǎng)度(8位)

0x95, 0x40,//報(bào)告數(shù)值(64 fields)

0x91, 0x02,//輸出(data, variable, absolute)

0xC0,//集合結(jié)束(Physical)

0xC0//集合結(jié)束(Application)

};

//通過(guò)上面的報(bào)告描述符的定義,我們知道返回的輸入報(bào)告具有8字節(jié)。

//輸出報(bào)告也有64字節(jié)。至于這64字節(jié)的數(shù)據(jù)是干什么用的,就要由用戶

//自己來(lái)決定了。

///報(bào)告描述符完畢

?

?

//usb配置描述符

const u8 DinkUsbConfigDescriptor[DINK_USB_SIZ_CONFIG_DESC] = {

??? /***************配置描述符***********************/

??? USB_CONFIGUARTION_DESC_SIZE,?????? //bLength字段。配置描述符的長(zhǎng)度為9字節(jié)。

??? USB_CONFIGURATION_DESCRIPTOR_TYPE, //bDescriptorType字段。配置描述符編號(hào)為0x02。

??? //wTotalLength字段。配置描述符集合的總長(zhǎng)度,

??? //包括配置描述符本身、接口描述符、類(lèi)描述符、端點(diǎn)描述符等。

??? WBVAL(?

??? USB_CONFIGUARTION_DESC_SIZE +?????????? //配置描述符

??? USB_INTERFACE_DESC_SIZE???? +??????? //接口1描述符

??? 9?????????????????????????? +?????????? //hid描述符

??? USB_ENDPOINT_DESC_SIZE????? +?????????? //端點(diǎn)描述符

??? USB_ENDPOINT_DESC_SIZE????????????????? //端點(diǎn)描述符

??? ),

??? 0x01,????????????????????????????? ???? //bNumInterfaces字段。該配置包含的接口數(shù),只有一個(gè)接口。

??? 0x01,????????????????????????????? ???? //bConfiguration字段。該配置的值為1。

??? 0x00,???????????????????????????? ???? //iConfigurationz字段,該配置的字符串索引。這里沒(méi)有,為0。

??? USB_CONFIG_BUS_POWERED ,??????????????? //bmAttributes字段,該設(shè)備的屬性

??? USB_CONFIG_POWER_MA(500),????????? ??????? //bMaxPower字段,該設(shè)備需要的最大電流量

?

??? /*********************第一個(gè)接口描述符,hid設(shè)備**********************/

??? USB_INTERFACE_DESC_SIZE,???????? ???? //bLength字段。接口描述符的長(zhǎng)度為9字節(jié)。

??? USB_INTERFACE_DESCRIPTOR_TYPE,??? ?????? //bDescriptorType字段。接口描述符的編號(hào)為0x04。

??? 0x00,???????????????????????????? ???? //bInterfaceNumber字段。該接口的編號(hào),第一個(gè)接口,編號(hào)為0。

??? 0x00,??????????????????????????? ????? //bAlternateSetting字段。該接口的備用編號(hào),為0。

??? 0x02,?????????????????????????????????? //bNumEndpoints字段。非0端點(diǎn)的數(shù)目。該接口有2個(gè)批量端點(diǎn)

?

??? USB_DEVICE_CLASS_HUMAN_INTERFACE, ????? //bInterfaceClass字段。該接口所使用的類(lèi)。大容量存儲(chǔ)設(shè)備接口類(lèi)的代碼為0x08。,

???

??? 0x00,?????????????????????????????????? //bInterfaceSubClass字段。該接口所使用的子類(lèi)。在HID1.1協(xié)議中,

??????????????????????????????????????????? //只規(guī)定了一種子類(lèi):支持BIOS引導(dǎo)啟動(dòng)的子類(lèi)。

??????????????????????????????????????????? //USB鍵盤(pán)、鼠標(biāo)屬于該子類(lèi),子類(lèi)代碼為0x01。

??????????????????????????????????????????? //但這里我們是自定義的HID設(shè)備,所以不使用子類(lèi)。

???

??? 0x00,?????????????????????????????????? //bInterfaceProtocol字段。如果子類(lèi)為支持引導(dǎo)啟動(dòng)的子類(lèi),

??????????????????????????????????????????? //則協(xié)議可選擇鼠標(biāo)和鍵盤(pán)。鍵盤(pán)代碼為0x01,鼠標(biāo)代碼為0x02。

??????????????????????????????????????????? //自定義的HID設(shè)備,也不使用協(xié)議。

?

??? 0x00,?????????????????????????????????? //iConfiguration字段。該接口的字符串索引值。這里沒(méi)有,為0。

?

??? /*********************HID報(bào)告描述符*************************/

??? //bLength字段。本HID描述符下只有一個(gè)下級(jí)描述符。所以長(zhǎng)度為9字節(jié)。

??? ?0x09,

??? ?

??? ?//bDescriptorType字段。HID描述符的編號(hào)為0x21。

??? ?0x21,

??? ?

??? ?//bcdHID字段。本協(xié)議使用的HID1.1協(xié)議。注意低字節(jié)在先。

??? ?0x10,

??? ?0x01,

??? ?

??? ?//bCountyCode字段。設(shè)備適用的國(guó)家代碼,這里選擇為美國(guó),代碼0x21。

??? ?0x21,

??? ?

??? ?//bNumDescriptors字段。下級(jí)描述符的數(shù)目。我們只有一個(gè)報(bào)告描述符。

??? ?0x01,

??? ?

??? ?//bDescriptorType字段。下級(jí)描述符的類(lèi)型,為報(bào)告描述符,編號(hào)為0x22。

??? ?0x22,

??? ?

??? ?//bDescriptorLength字段。下級(jí)描述符的長(zhǎng)度。下級(jí)描述符為報(bào)告描述符。

??? ?sizeof(HID_ReportDescriptor)&0xFF,

??? ?(sizeof(HID_ReportDescriptor)>>8)&0xFF,

??? /*********************端點(diǎn)描述符**********************************/

??? /* 端點(diǎn)描述符 */

??? USB_ENDPOINT_DESC_SIZE,?????????? ???? //bLength字段。端點(diǎn)描述符長(zhǎng)度為7字節(jié)。

??? USB_ENDPOINT_DESCRIPTOR_TYPE,???? ?????? //bDescriptorType字段。端點(diǎn)描述符編號(hào)為0x05。

??? USB_ENDPOINT_IN(1),????????????? ?????? //bEndpointAddress字段。端點(diǎn)的地址。我們使用D12的輸入端點(diǎn)1。

??? USB_ENDPOINT_TYPE_INTERRUPT,? ??????????? //bmAttributes字段。D1~D0為端點(diǎn)傳輸類(lèi)型選擇。

??? WBVAL(0x0040),???????????????????? ????? //wMaxPacketSize字段。該端點(diǎn)的最大包長(zhǎng)。最大包長(zhǎng)為64字節(jié)。

??? 0x01,????????? ??? ????????????????????????? //bInterval字段。端點(diǎn)查詢的時(shí)間,端點(diǎn)查詢的時(shí)間,此處無(wú)意義。

??? /***********************端點(diǎn)描述符*******************************************/

??? USB_ENDPOINT_DESC_SIZE,?????????? ???? //bLength字段。端點(diǎn)描述符長(zhǎng)度為7字節(jié)。

??? USB_ENDPOINT_DESCRIPTOR_TYPE,???? ?????? //bDescriptorType字段。端點(diǎn)描述符編號(hào)為0x05。

??? USB_ENDPOINT_OUT(1),????????????? ????? //bEndpointAddress字段。端點(diǎn)的地址。我們使用D12的輸入端點(diǎn)1。

??? USB_ENDPOINT_TYPE_INTERRUPT,????? ??????? //bmAttributes字段。D1~D0為端點(diǎn)傳輸類(lèi)型選擇。

??? WBVAL(0x0040),???????????????????? ????? //wMaxPacketSize字段。該端點(diǎn)的最大包長(zhǎng)。最大包長(zhǎng)為64字節(jié)。

??? 0x01,????????? ??? ????????????????????????? //bInterval字段。端點(diǎn)查詢的時(shí)間,端點(diǎn)查詢的時(shí)間,此處無(wú)意義。

};

?

?

?

?

?

/************************語(yǔ)言ID的定義********************/

const u8 DinkUsbLanguageId[DINK_USB_SIZ_STRING_LANGID]=

{

??? 0x04, //本描述符的長(zhǎng)度

??? 0x03, //字符串描述符

??? //0x0409為美式英語(yǔ)的ID

??? 0x09,

??? 0x04

};

?

?

語(yǔ)言ID完畢//

?

//Unicode 字符串描述符

//鄧小俊的usb鼠標(biāo)

const u8 DinkUsbManufacturerStringDescriptor[DINK_USB_SIZ_STRING_VENDOR]=

{

??? 32,???????? //該描述符的長(zhǎng)度為32字節(jié)

??? 0x03,?????? //字符串描述符的類(lèi)型編碼為0x03

??? 0x44, 0x00, //D

??? 0x49, 0x00, //I

??? 0x4e, 0x00, //N

??? 0x4b, 0x00, //K

??? 0x5f, 0x00, //_

??? 0x48, 0x00, //H

??? 0x49, 0x00, //I

??? 0x44, 0x00, //D

??? 0x5f, 0x00, //_

??? 0x44, 0x00, //D

??? 0x45, 0x00, //E

??? 0x56, 0x00, //V

??? 0x49, 0x00, //I

??? 0x43, 0x00, //C

??? 0x45, 0x00? //E

?

};

/廠商字符串結(jié)束/

?

?

//產(chǎn)品字符串描述符

const u8 DinkUsbProductStringDescriptor[DINK_USB_SIZ_STRING_PRODUCT]=

{

??? 32,???????? //該描述符的長(zhǎng)度為32字節(jié)

??? 0x03,?????? //字符串描述符的類(lèi)型編碼為0x03

??? 0x44, 0x00, //D

??? 0x49, 0x00, //I

??? 0x4e, 0x00, //N

??? 0x4b, 0x00, //K

??? 0x5f, 0x00, //_

??? 0x48, 0x00, //H

??? 0x49, 0x00, //I

??? 0x44, 0x00, //D

??? 0x5f, 0x00, //_

??? 0x44, 0x00, //D

??? 0x45, 0x00, //E

??? 0x56, 0x00, //V

??? 0x49, 0x00, //I

??? 0x43, 0x00, //C

??? 0x45, 0x00? //E

};

產(chǎn)品字符串結(jié)束

?

//字符串“2008-07-07”的Unicode編碼

//8位小端格式

const u8 DinkUsbSerialNumberStringDescriptor[DINK_USB_SIZ_STRING_SERIAL]={

??? 22,???????? //該描述符的長(zhǎng)度為22字節(jié)

??? 0x03,?????? //字符串描述符的類(lèi)型編碼為0x03

??? 0x32, 0x00, //2

??? 0x30, 0x00, //0

??? 0x31, 0x00, //1

??? 0x35, 0x00, //5

??? 0x2d, 0x00, //-

??? 0x30, 0x00, //0

??? 0x33, 0x00, //3

??? 0x2d, 0x00, //-

??? 0x32, 0x00, //2

??? 0x31, 0x00? //1

};

//產(chǎn)品序列號(hào)字符串結(jié)束/

?

//產(chǎn)品序列號(hào)

u8 DinkUsbStringSerialUniqueId[DINK_USB_SIZ_STRING_SERIAL_UNIQUE_ID] =

{

??? DINK_USB_SIZ_STRING_SERIAL_UNIQUE_ID,??????? //描述符長(zhǎng)度

??? 0x03????????????????????????????????????????????????????? //描述符類(lèi)型編碼

/* Serial number該編碼將會(huì)

?

可以通過(guò)修改該文件實(shí)現(xiàn)不同的設(shè)備,第二是usb_prop.c文件,定義了一系列的回調(diào)函數(shù),在usb枚舉階段使用

#include "usb_prop.h"

?

u32 ProtocolValue;

?

//表明有多少端點(diǎn),多少種配置

DEVICE Device_Table =

{

??? EP_NUM,

??? 1

};

?

//static u8 s_Request = 0;//記錄當(dāng)前請(qǐng)求值

?

//設(shè)備描述符

ONE_DESCRIPTOR Device_Descriptor =

{

??? (u8*)DinkUsbDeviceDescriptor,

??? DINK_USB_SIZ_DEVICE_DESC

};

?

//配置描述符

ONE_DESCRIPTOR Config_Descriptor =

{

??? (u8*)DinkUsbConfigDescriptor,

??? DINK_USB_SIZ_CONFIG_DESC

};

//報(bào)告描述符

ONE_DESCRIPTOR DinkUsb_Report_Descriptor =

{

??? (u8*)HID_ReportDescriptor,

??? HID_ReportDescSize

};

?

//報(bào)告描述符

ONE_DESCRIPTOR DinkUsb_Hid_Descriptor =

{

??? (u8*)(DinkUsbConfigDescriptor+9),

??? 9

};

?

?

?

//字符串描述符

ONE_DESCRIPTOR String_Descriptor[4] =

{

??? {(u8*)DinkUsbLanguageId, DINK_USB_SIZ_STRING_LANGID},

??? {(u8*)DinkUsbManufacturerStringDescriptor, DINK_USB_SIZ_STRING_VENDOR},

??? {(u8*)DinkUsbProductStringDescriptor, DINK_USB_SIZ_STRING_PRODUCT},

??? {(u8*)DinkUsbSerialNumberStringDescriptor, DINK_USB_SIZ_STRING_SERIAL}

};

?

?

?

//USB過(guò)程處理函數(shù)數(shù)組

DEVICE_PROP Device_Property =

{

??? DinkUsbInit,

??? DinkUsbReset,

??? DinkUsbStatus_In,

??? DinkUsbStatus_Out,

??? DinkUsbData_Setup,

??? DinkUsbNoDataSetup,

??? DinkUsbGetInterfaceSetting,

??? DinkUsbGetDeviceDescriptor,

??? DinkUsbGetConfigDescriptor,

??? DinkUsbGetStringDescriptor,

??? 0,

??? 0x40 /*MAX PACKET SIZE*/

};

?

//usb標(biāo)準(zhǔn)數(shù)據(jù)請(qǐng)求結(jié)構(gòu)體

//只實(shí)現(xiàn)了兩個(gè),剩下的用nop方式解決了

USER_STANDARD_REQUESTS User_Standard_Requests =

{

??? DinkUsbGetConfiguration,

??? DinkUsbSetConfiguration,

??? DinkUsbGetInterface,

??? DinkUsbSetInterface,

??? DinkUsbGetStatus,

??? DinkUsbClearFeature,

??? DinkUsbSetEndPointFeature,

??? DinkUsbSetDeviceFeature,

??? DinkUsbSetDeviceAddress

};

?

?

?

//設(shè)備初始化

void DinkUsbInit(void)

{

??? Get_SerialNum();??????? //構(gòu)建字符串描述符

??? pInformation->Current_Configuration = 0;????? //當(dāng)前選擇的配置為0

??? PowerOn();????????? //連接USB

??? _SetISTR(0);

??? wInterrupt_Mask = IMR_MSK;

??? _SetCNTR(wInterrupt_Mask);

??? bDeviceState = UNCONNECTED;?? //設(shè)備狀態(tài)初始化為未連接狀態(tài)

??? usb_debug_printf("USB Init\r\n");

}

?

//設(shè)備復(fù)位

void DinkUsbReset(void)

{

??? Device_Info.Current_Configuration = 0;? //選擇當(dāng)前配置為0

??? pInformation->Current_Feature = DinkUsbConfigDescriptor[7]; //獲取配置描述符中當(dāng)前設(shè)備屬性

??? pInformation->Current_Interface = 0;//設(shè)置當(dāng)前設(shè)備接口

??? SetBTABLE(BTABLE_ADDRESS);//設(shè)置緩沖區(qū)地址

???

??? SetEPType(ENDP0, EP_CONTROL);//控制端點(diǎn)

??? SetEPTxStatus(ENDP0, EP_TX_STALL);

??? SetEPRxAddr(ENDP0, ENDP0_RXADDR);//設(shè)置端點(diǎn)緩沖區(qū)地址

??? SetEPTxAddr(ENDP0, ENDP0_TXADDR);

??? Clear_Status_Out(ENDP0);

??? SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//設(shè)置接收最大長(zhǎng)度

??? SetEPRxValid(ENDP0);

???

??? SetEPType(ENDP1, EP_INTERRUPT);//初始化端點(diǎn)1為中斷傳輸模式,用來(lái)報(bào)告一些狀態(tài)

??? SetEPTxAddr(ENDP1, ENDP1_TXADDR);//設(shè)置端點(diǎn)地址

??? SetEPRxAddr(ENDP1, ENDP1_RXADDR);//設(shè)置端點(diǎn)地址

??? SetEPRxStatus(ENDP1, EP_RX_VALID);//使能接收

??? SetEPTxStatus(ENDP1, EP_TX_NAK);? //不使能發(fā)送

??? SetEPRxCount(ENDP1, 64);//設(shè)置接收最大長(zhǎng)度

??? Clear_Status_Out(ENDP1);

?

??? bDeviceState = ATTACHED;//設(shè)備插入

???

??? SetDeviceAddress(0);//設(shè)置當(dāng)前地址為0

??? usb_debug_printf("USB Reset\r\n");

}

?

//不知道干嘛的

void DinkUsbStatus_In(void)

{

??? return;

}

//不知道干嘛的

void DinkUsbStatus_Out(void)

{

??? return;

}

?

u8 *DinkUsbGetReportDescriptor(u16 Length)

{

??? usb_debug_printf("獲取報(bào)告描述符\r\n");

??? return Standard_GetDescriptorData(Length, &DinkUsb_Report_Descriptor);

}

?

u8 *DinkUsbGetHIDDescriptor(u16 Length)

{

??? usb_debug_printf("獲取HID述符\r\n");

??? return Standard_GetDescriptorData(Length, &DinkUsb_Hid_Descriptor);

}

?

u8 *DinkUsbGetProtocolValue(u16 Length)

{

??? usb_debug_printf("獲取協(xié)議\r\n");

??? if (Length == 0)

??? {

??????? pInformation->Ctrl_Info.Usb_wLength = 1;

??????? return NULL;

??? }

??? else

??? {

??????? return (u8 *)(&ProtocolValue);

??? }

}

?

RESULT DinkUsbData_Setup(u8 RequestNo)

{

??? u8 *(*CopyRoutine)(u16);

?

??? CopyRoutine = NULL;

??? if ((RequestNo == GET_DESCRIPTOR)

??? && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))

??? && (pInformation->USBwIndex0 == 0))

??? {

??????? //獲取報(bào)告描述符

??????? if (pInformation->USBwValue1 == REPORT_DESCRIPTOR)

??????? {

??????????? CopyRoutine = DinkUsbGetReportDescriptor;

??????? }

??????? //獲取HID描述符

??????? else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)

??????? {

??????????? CopyRoutine = DinkUsbGetHIDDescriptor;

??????? }

?

??? }

?

??? /*** GET_PROTOCOL ***/

??? else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))

??? ?? && RequestNo == GET_PROTOCOL)

??? {

??????? CopyRoutine = DinkUsbGetProtocolValue;//獲取協(xié)議值

??? }

?

?

??? if (CopyRoutine == NULL)

??? {

??????? return USB_UNSUPPORT;

??? }

?

??? pInformation->Ctrl_Info.CopyData = CopyRoutine;

??? pInformation->Ctrl_Info.Usb_wOffset = 0;

??? (*CopyRoutine)(0);

??? return USB_SUCCESS;

}

?

RESULT DinkUsbSetProtocol(void)

{

? u8 wValue0 = pInformation->USBwValue0;

? ProtocolValue = wValue0;

? return USB_SUCCESS;

}

?

RESULT DinkUsbNoDataSetup(u8 RequestNo)

{

??? if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))

??? && (RequestNo == SET_PROTOCOL))

??? {

??????? usb_debug_printf("設(shè)置協(xié)議\r\n");

??????? return DinkUsbSetProtocol();

??? }

??? else

??? {

??????? return USB_UNSUPPORT;

??? }

}

?

?

RESULT DinkUsbGetInterfaceSetting(u8 Interface, u8 AlternateSetting)

{

??? if (AlternateSetting > 0)//配置數(shù)量

??? {

??????? usb_debug_printf("設(shè)置配置\r\n");

??????? return USB_UNSUPPORT;

??? }

??? else if (Interface > 1)//接口數(shù)量

??? {

??????? usb_debug_printf("設(shè)置接口\r\n");

??????? return USB_UNSUPPORT;

??? }

??? return USB_SUCCESS;

}

?

//獲取設(shè)備描述符

u8 *DinkUsbGetDeviceDescriptor(u16 Length)

{

??? usb_debug_printf("獲取設(shè)備描述符\r\n");

??? return Standard_GetDescriptorData(Length, &Device_Descriptor);

}

//配置描述符

u8 *DinkUsbGetConfigDescriptor(u16 Length)

{

??? usb_debug_printf("獲取配置描述符\r\n");

??? return Standard_GetDescriptorData(Length, &Config_Descriptor);

}

//字符串描述符

u8 *DinkUsbGetStringDescriptor(u16 Length)

{

?

??? u8 wValue0 = pInformation->USBwValue0;

??? usb_debug_printf("獲取字符串描述符 %d\r\n",wValue0);

??? if (wValue0 > 4)

??? {

??????? return NULL;

??? }

??? else

??? {

??????? return Standard_GetDescriptorData(Length, &String_Descriptor[wValue0]); //返回字符串描述符

??? }

}

?

?

?

?

?

//將設(shè)備狀態(tài)上傳到配置數(shù)據(jù)中

void DinkUsbSetConfiguration(void)

{

?

??? DEVICE_INFO *pInfo = &Device_Info;

??? usb_debug_printf("設(shè)置配置\r\n");

??? if (pInfo->Current_Configuration != 0)

??? {

??????? bDeviceState = CONFIGURED;

??? }

}

//將地址設(shè)置上傳

void DinkUsbSetDeviceAddress (void)

{

??? usb_debug_printf("設(shè)置地址\r\n");

??? bDeviceState = ADDRESSED;

}

?

?

其中最核心的兩個(gè)函數(shù)分別是復(fù)位和初始化,復(fù)位的時(shí)候要將端點(diǎn)配置好,并且接受最好要使能,否則無(wú)法接收數(shù)據(jù)(后期自己使能也可以),然后就是端點(diǎn)的處理函數(shù)了usb_endp.c

#include "usb_endp.h"

?

//發(fā)送完成置1 發(fā)送未完成置0

u8 sendOk = 1;

//接收到數(shù)據(jù)該設(shè)置為1,數(shù)據(jù)處理完成之后修改為0

u8 ReceiveOk = 0;

?

void EP1_IN_Callback(void)

{

??? //設(shè)備向主機(jī)發(fā)送數(shù)據(jù)的回調(diào)函數(shù)

??? sendOk = 1;//發(fā)送成功為1

??? SetEPTxStatus(ENDP1, EP_TX_NAK);//發(fā)送成功等待第二次設(shè)置為valid

}

?

void EP1_OUT_Callback(void)

{

??? //接收了一次數(shù)據(jù)之后等待數(shù)據(jù)處理,將接受響應(yīng)設(shè)置為NAK

??? //處理完成之后再設(shè)置為VALID

??? SetEPRxStatus(ENDP1, EP_RX_NAK);//NAK接收

??? ReceiveOk = 1;//有數(shù)據(jù)標(biāo)志為1

?

}

?

要想使能這些函數(shù),需要將端點(diǎn)響應(yīng)函數(shù)打開(kāi)

另外,單片機(jī)應(yīng)當(dāng)來(lái)處理或者發(fā)送數(shù)據(jù),依靠usb_data_process.h文件完成

#include "usb_data_process.h"

?

?

//HID發(fā)送數(shù)據(jù)

//返回1發(fā)送失敗 返回0發(fā)送成功

u8 HID_Send_Data(u8* buffer,u8 length)

{

??? if(sendOk == 1)

??? {

??????? if(length == 0)

??????? {

??????????? SetEPTxStatus(ENDP1, EP_TX_NAK);//不發(fā)送

??????? }

??????? else

??????? {

??????????? UserToPMABufferCopy(buffer, GetEPTxAddr(ENDP1), length);

??????????? SetEPTxCount(ENDP1, length);

??????????? SetEPTxValid(ENDP1);//使能發(fā)送

??????????? sendOk = 0;//設(shè)置發(fā)送未完成狀態(tài),等待發(fā)送回調(diào)函數(shù)將數(shù)據(jù)發(fā)送到主機(jī)

??????? }

??????? return 0;

??? }

??? else

??? {

??????? return 1;//上一次的數(shù)據(jù)還沒(méi)發(fā)送出去,所以這次發(fā)送失敗

??? }

}

?

?

//HID接收數(shù)據(jù)處理

u8 HID_Receive_Data(u8* buffer)

{

??? u16 length = 0;//獲取接收到的數(shù)據(jù)長(zhǎng)度

??? u8 i = 0;

??? if(ReceiveOk == 1)//有數(shù)據(jù)

??? {

??????? length = GetEPRxCount(ENDP1);

??????? if(length == 0)return 0;

??????? else

??????? {

??????????? PMAToUserBufferCopy(buffer, GetEPRxAddr(ENDP1), length);

??????????? SetEPRxValid(ENDP1);//使能接收

??????????? ReceiveOk = 0;

???????????

??????????? printf("hid receive : ");

??????????? for(i = 0; i < length; i++)

??????????? {

??????????????? printf("%c ",buffer[i]);

??????????? }

??????????? printf("\r\n");

???????????

??????????? return length;//返回接收到的數(shù)據(jù)

??????? }

??? }

??? else

??? {

??????? //沒(méi)有數(shù)據(jù),直接為0

??????? return 0;

??? }

}

?

?

做好這里,基本上就能實(shí)現(xiàn)通訊了,詳細(xì)工程請(qǐng)查看文章最后的鏈接

?

?

?http://download.csdn.net/detail/dengrengong/8523351

?

?

?

?

?

?

?

?

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/dengxiaojun/p/4357720.html

總結(jié)

以上是生活随笔為你收集整理的USB自定义HID设备实现-STM32的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。