USB自定义HID设备实现-STM32
該文檔使用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)題。
- 上一篇: (王道408考研操作系统)第三章内存管理
- 下一篇: 【专栏必读】王道考研408计算机组成原理