USB自定义HID设备实现-STM32
該文檔使用USB固件庫,在其基礎上進行了自己的定制,完成了一個USB-HID設備,首先是usb_desc.c文件,里面存放了usb各種描述符的存在
#include "usb_desc.h"
?
//usb標準設備描述符
const u8 DinkUsbDeviceDescriptor[DINK_USB_SIZ_DEVICE_DESC] = {
?
??? USB_DEVICE_DESC_SIZE,???????????? //bLength字段。設備描述符的長度為18(0x12)字節
??? USB_DEVICE_DESCRIPTOR_TYPE,??????? ?? //bDescriptorType字段。設備描述符的編號為0x01
??? WBVAL(0x0200), ??????????? ????????? //bcdUSB字段。這里設置版本為USB1.1,即0x0110。
??? 0x00,???????????????????????????? //bDeviceClass字段。我們不在設備描述符中定義設備類,
??? 0x00,????????????????????????????? //bDeviceSubClass字段。bDeviceClass字段為0時,該字段也為0。
??? 0x00,??????????????????????????? ? //bDeviceProtocol字段。bDeviceClass字段為0時,該字段也為0。
??? 0x40,???????????????? ????????????? //bMaxPacketSize0字段。端點0的最大包長度。
??? WBVAL(0x7777),??????????????????? ?? //idVender字段。廠商ID號,我們這里取0x8888,僅供實驗用。
??? WBVAL(0x8888),??????????????????? ?? //idProduct字段。產品ID號,由于是第一個實驗,我們這里取0x0001。\。
??? WBVAL(0x0100), ???????? ?????????? // 設備的版本
??? 0x01,???????????????????????????? //iManufacturer字段。廠商字符串的索引值,為了方便記憶和管理
??? 0x02,???????????????????????????? //iProduct字段。產品字符串的索引值。剛剛用了1,這里就取2吧。
??? 0x03,??????????????????????????? ? //iSerialNumber字段。設備的序列號字符串索引值。
??? 0x01????????????????? ????????????? //bNumConfigurations字段。該設備所具有的配置數。
};
?
?
//USB報告描述符的定義
const u8 HID_ReportDescriptor[]=
{
0x06,0xA0,0xFF,//用法頁(FFA0h, vendor defined)
0x09, 0x01,//用法(vendor defined)
0xA1, 0x01,//集合(Application)
0x09, 0x02 ,//用法(vendor defined)
0xA1, 0x00,//集合(Physical)
0x06,0xA1,0xFF,//用法頁(vendor defined)
//輸入報告
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,//報告長度Report size (8位)
0x95, 0x40,//報告數值(64 fields)
0x81, 0x02,//輸入(data, variable, absolute)
//輸出報告
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,//報告長度(8位)
0x95, 0x40,//報告數值(64 fields)
0x91, 0x02,//輸出(data, variable, absolute)
0xC0,//集合結束(Physical)
0xC0//集合結束(Application)
};
//通過上面的報告描述符的定義,我們知道返回的輸入報告具有8字節。
//輸出報告也有64字節。至于這64字節的數據是干什么用的,就要由用戶
//自己來決定了。
///報告描述符完畢
?
?
//usb配置描述符
const u8 DinkUsbConfigDescriptor[DINK_USB_SIZ_CONFIG_DESC] = {
??? /***************配置描述符***********************/
??? USB_CONFIGUARTION_DESC_SIZE,?????? //bLength字段。配置描述符的長度為9字節。
??? USB_CONFIGURATION_DESCRIPTOR_TYPE, //bDescriptorType字段。配置描述符編號為0x02。
??? //wTotalLength字段。配置描述符集合的總長度,
??? //包括配置描述符本身、接口描述符、類描述符、端點描述符等。
??? WBVAL(?
??? USB_CONFIGUARTION_DESC_SIZE +?????????? //配置描述符
??? USB_INTERFACE_DESC_SIZE???? +??????? //接口1描述符
??? 9?????????????????????????? +?????????? //hid描述符
??? USB_ENDPOINT_DESC_SIZE????? +?????????? //端點描述符
??? USB_ENDPOINT_DESC_SIZE????????????????? //端點描述符
??? ),
??? 0x01,????????????????????????????? ???? //bNumInterfaces字段。該配置包含的接口數,只有一個接口。
??? 0x01,????????????????????????????? ???? //bConfiguration字段。該配置的值為1。
??? 0x00,???????????????????????????? ???? //iConfigurationz字段,該配置的字符串索引。這里沒有,為0。
??? USB_CONFIG_BUS_POWERED ,??????????????? //bmAttributes字段,該設備的屬性
??? USB_CONFIG_POWER_MA(500),????????? ??????? //bMaxPower字段,該設備需要的最大電流量
?
??? /*********************第一個接口描述符,hid設備**********************/
??? USB_INTERFACE_DESC_SIZE,???????? ???? //bLength字段。接口描述符的長度為9字節。
??? USB_INTERFACE_DESCRIPTOR_TYPE,??? ?????? //bDescriptorType字段。接口描述符的編號為0x04。
??? 0x00,???????????????????????????? ???? //bInterfaceNumber字段。該接口的編號,第一個接口,編號為0。
??? 0x00,??????????????????????????? ????? //bAlternateSetting字段。該接口的備用編號,為0。
??? 0x02,?????????????????????????????????? //bNumEndpoints字段。非0端點的數目。該接口有2個批量端點
?
??? USB_DEVICE_CLASS_HUMAN_INTERFACE, ????? //bInterfaceClass字段。該接口所使用的類。大容量存儲設備接口類的代碼為0x08。,
???
??? 0x00,?????????????????????????????????? //bInterfaceSubClass字段。該接口所使用的子類。在HID1.1協議中,
??????????????????????????????????????????? //只規定了一種子類:支持BIOS引導啟動的子類。
??????????????????????????????????????????? //USB鍵盤、鼠標屬于該子類,子類代碼為0x01。
??????????????????????????????????????????? //但這里我們是自定義的HID設備,所以不使用子類。
???
??? 0x00,?????????????????????????????????? //bInterfaceProtocol字段。如果子類為支持引導啟動的子類,
??????????????????????????????????????????? //則協議可選擇鼠標和鍵盤。鍵盤代碼為0x01,鼠標代碼為0x02。
??????????????????????????????????????????? //自定義的HID設備,也不使用協議。
?
??? 0x00,?????????????????????????????????? //iConfiguration字段。該接口的字符串索引值。這里沒有,為0。
?
??? /*********************HID報告描述符*************************/
??? //bLength字段。本HID描述符下只有一個下級描述符。所以長度為9字節。
??? ?0x09,
??? ?
??? ?//bDescriptorType字段。HID描述符的編號為0x21。
??? ?0x21,
??? ?
??? ?//bcdHID字段。本協議使用的HID1.1協議。注意低字節在先。
??? ?0x10,
??? ?0x01,
??? ?
??? ?//bCountyCode字段。設備適用的國家代碼,這里選擇為美國,代碼0x21。
??? ?0x21,
??? ?
??? ?//bNumDescriptors字段。下級描述符的數目。我們只有一個報告描述符。
??? ?0x01,
??? ?
??? ?//bDescriptorType字段。下級描述符的類型,為報告描述符,編號為0x22。
??? ?0x22,
??? ?
??? ?//bDescriptorLength字段。下級描述符的長度。下級描述符為報告描述符。
??? ?sizeof(HID_ReportDescriptor)&0xFF,
??? ?(sizeof(HID_ReportDescriptor)>>8)&0xFF,
??? /*********************端點描述符**********************************/
??? /* 端點描述符 */
??? USB_ENDPOINT_DESC_SIZE,?????????? ???? //bLength字段。端點描述符長度為7字節。
??? USB_ENDPOINT_DESCRIPTOR_TYPE,???? ?????? //bDescriptorType字段。端點描述符編號為0x05。
??? USB_ENDPOINT_IN(1),????????????? ?????? //bEndpointAddress字段。端點的地址。我們使用D12的輸入端點1。
??? USB_ENDPOINT_TYPE_INTERRUPT,? ??????????? //bmAttributes字段。D1~D0為端點傳輸類型選擇。
??? WBVAL(0x0040),???????????????????? ????? //wMaxPacketSize字段。該端點的最大包長。最大包長為64字節。
??? 0x01,????????? ??? ????????????????????????? //bInterval字段。端點查詢的時間,端點查詢的時間,此處無意義。
??? /***********************端點描述符*******************************************/
??? USB_ENDPOINT_DESC_SIZE,?????????? ???? //bLength字段。端點描述符長度為7字節。
??? USB_ENDPOINT_DESCRIPTOR_TYPE,???? ?????? //bDescriptorType字段。端點描述符編號為0x05。
??? USB_ENDPOINT_OUT(1),????????????? ????? //bEndpointAddress字段。端點的地址。我們使用D12的輸入端點1。
??? USB_ENDPOINT_TYPE_INTERRUPT,????? ??????? //bmAttributes字段。D1~D0為端點傳輸類型選擇。
??? WBVAL(0x0040),???????????????????? ????? //wMaxPacketSize字段。該端點的最大包長。最大包長為64字節。
??? 0x01,????????? ??? ????????????????????????? //bInterval字段。端點查詢的時間,端點查詢的時間,此處無意義。
};
?
?
?
?
?
/************************語言ID的定義********************/
const u8 DinkUsbLanguageId[DINK_USB_SIZ_STRING_LANGID]=
{
??? 0x04, //本描述符的長度
??? 0x03, //字符串描述符
??? //0x0409為美式英語的ID
??? 0x09,
??? 0x04
};
?
?
語言ID完畢//
?
//Unicode 字符串描述符
//鄧小俊的usb鼠標
const u8 DinkUsbManufacturerStringDescriptor[DINK_USB_SIZ_STRING_VENDOR]=
{
??? 32,???????? //該描述符的長度為32字節
??? 0x03,?????? //字符串描述符的類型編碼為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
?
};
/廠商字符串結束/
?
?
//產品字符串描述符
const u8 DinkUsbProductStringDescriptor[DINK_USB_SIZ_STRING_PRODUCT]=
{
??? 32,???????? //該描述符的長度為32字節
??? 0x03,?????? //字符串描述符的類型編碼為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
};
產品字符串結束
?
//字符串“2008-07-07”的Unicode編碼
//8位小端格式
const u8 DinkUsbSerialNumberStringDescriptor[DINK_USB_SIZ_STRING_SERIAL]={
??? 22,???????? //該描述符的長度為22字節
??? 0x03,?????? //字符串描述符的類型編碼為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
};
//產品序列號字符串結束/
?
//產品序列號
u8 DinkUsbStringSerialUniqueId[DINK_USB_SIZ_STRING_SERIAL_UNIQUE_ID] =
{
??? DINK_USB_SIZ_STRING_SERIAL_UNIQUE_ID,??????? //描述符長度
??? 0x03????????????????????????????????????????????????????? //描述符類型編碼
/* Serial number該編碼將會
?
可以通過修改該文件實現不同的設備,第二是usb_prop.c文件,定義了一系列的回調函數,在usb枚舉階段使用
#include "usb_prop.h"
?
u32 ProtocolValue;
?
//表明有多少端點,多少種配置
DEVICE Device_Table =
{
??? EP_NUM,
??? 1
};
?
//static u8 s_Request = 0;//記錄當前請求值
?
//設備描述符
ONE_DESCRIPTOR Device_Descriptor =
{
??? (u8*)DinkUsbDeviceDescriptor,
??? DINK_USB_SIZ_DEVICE_DESC
};
?
//配置描述符
ONE_DESCRIPTOR Config_Descriptor =
{
??? (u8*)DinkUsbConfigDescriptor,
??? DINK_USB_SIZ_CONFIG_DESC
};
//報告描述符
ONE_DESCRIPTOR DinkUsb_Report_Descriptor =
{
??? (u8*)HID_ReportDescriptor,
??? HID_ReportDescSize
};
?
//報告描述符
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過程處理函數數組
DEVICE_PROP Device_Property =
{
??? DinkUsbInit,
??? DinkUsbReset,
??? DinkUsbStatus_In,
??? DinkUsbStatus_Out,
??? DinkUsbData_Setup,
??? DinkUsbNoDataSetup,
??? DinkUsbGetInterfaceSetting,
??? DinkUsbGetDeviceDescriptor,
??? DinkUsbGetConfigDescriptor,
??? DinkUsbGetStringDescriptor,
??? 0,
??? 0x40 /*MAX PACKET SIZE*/
};
?
//usb標準數據請求結構體
//只實現了兩個,剩下的用nop方式解決了
USER_STANDARD_REQUESTS User_Standard_Requests =
{
??? DinkUsbGetConfiguration,
??? DinkUsbSetConfiguration,
??? DinkUsbGetInterface,
??? DinkUsbSetInterface,
??? DinkUsbGetStatus,
??? DinkUsbClearFeature,
??? DinkUsbSetEndPointFeature,
??? DinkUsbSetDeviceFeature,
??? DinkUsbSetDeviceAddress
};
?
?
?
//設備初始化
void DinkUsbInit(void)
{
??? Get_SerialNum();??????? //構建字符串描述符
??? pInformation->Current_Configuration = 0;????? //當前選擇的配置為0
??? PowerOn();????????? //連接USB
??? _SetISTR(0);
??? wInterrupt_Mask = IMR_MSK;
??? _SetCNTR(wInterrupt_Mask);
??? bDeviceState = UNCONNECTED;?? //設備狀態初始化為未連接狀態
??? usb_debug_printf("USB Init\r\n");
}
?
//設備復位
void DinkUsbReset(void)
{
??? Device_Info.Current_Configuration = 0;? //選擇當前配置為0
??? pInformation->Current_Feature = DinkUsbConfigDescriptor[7]; //獲取配置描述符中當前設備屬性
??? pInformation->Current_Interface = 0;//設置當前設備接口
??? SetBTABLE(BTABLE_ADDRESS);//設置緩沖區地址
???
??? SetEPType(ENDP0, EP_CONTROL);//控制端點
??? SetEPTxStatus(ENDP0, EP_TX_STALL);
??? SetEPRxAddr(ENDP0, ENDP0_RXADDR);//設置端點緩沖區地址
??? SetEPTxAddr(ENDP0, ENDP0_TXADDR);
??? Clear_Status_Out(ENDP0);
??? SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);//設置接收最大長度
??? SetEPRxValid(ENDP0);
???
??? SetEPType(ENDP1, EP_INTERRUPT);//初始化端點1為中斷傳輸模式,用來報告一些狀態
??? SetEPTxAddr(ENDP1, ENDP1_TXADDR);//設置端點地址
??? SetEPRxAddr(ENDP1, ENDP1_RXADDR);//設置端點地址
??? SetEPRxStatus(ENDP1, EP_RX_VALID);//使能接收
??? SetEPTxStatus(ENDP1, EP_TX_NAK);? //不使能發送
??? SetEPRxCount(ENDP1, 64);//設置接收最大長度
??? Clear_Status_Out(ENDP1);
?
??? bDeviceState = ATTACHED;//設備插入
???
??? SetDeviceAddress(0);//設置當前地址為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("獲取報告描述符\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("獲取協議\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))
??? {
??????? //獲取報告描述符
??????? 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;//獲取協議值
??? }
?
?
??? 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("設置協議\r\n");
??????? return DinkUsbSetProtocol();
??? }
??? else
??? {
??????? return USB_UNSUPPORT;
??? }
}
?
?
RESULT DinkUsbGetInterfaceSetting(u8 Interface, u8 AlternateSetting)
{
??? if (AlternateSetting > 0)//配置數量
??? {
??????? usb_debug_printf("設置配置\r\n");
??????? return USB_UNSUPPORT;
??? }
??? else if (Interface > 1)//接口數量
??? {
??????? usb_debug_printf("設置接口\r\n");
??????? return USB_UNSUPPORT;
??? }
??? return USB_SUCCESS;
}
?
//獲取設備描述符
u8 *DinkUsbGetDeviceDescriptor(u16 Length)
{
??? usb_debug_printf("獲取設備描述符\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]); //返回字符串描述符
??? }
}
?
?
?
?
?
//將設備狀態上傳到配置數據中
void DinkUsbSetConfiguration(void)
{
?
??? DEVICE_INFO *pInfo = &Device_Info;
??? usb_debug_printf("設置配置\r\n");
??? if (pInfo->Current_Configuration != 0)
??? {
??????? bDeviceState = CONFIGURED;
??? }
}
//將地址設置上傳
void DinkUsbSetDeviceAddress (void)
{
??? usb_debug_printf("設置地址\r\n");
??? bDeviceState = ADDRESSED;
}
?
?
其中最核心的兩個函數分別是復位和初始化,復位的時候要將端點配置好,并且接受最好要使能,否則無法接收數據(后期自己使能也可以),然后就是端點的處理函數了usb_endp.c
#include "usb_endp.h"
?
//發送完成置1 發送未完成置0
u8 sendOk = 1;
//接收到數據該設置為1,數據處理完成之后修改為0
u8 ReceiveOk = 0;
?
void EP1_IN_Callback(void)
{
??? //設備向主機發送數據的回調函數
??? sendOk = 1;//發送成功為1
??? SetEPTxStatus(ENDP1, EP_TX_NAK);//發送成功等待第二次設置為valid
}
?
void EP1_OUT_Callback(void)
{
??? //接收了一次數據之后等待數據處理,將接受響應設置為NAK
??? //處理完成之后再設置為VALID
??? SetEPRxStatus(ENDP1, EP_RX_NAK);//NAK接收
??? ReceiveOk = 1;//有數據標志為1
?
}
?
要想使能這些函數,需要將端點響應函數打開
另外,單片機應當來處理或者發送數據,依靠usb_data_process.h文件完成
#include "usb_data_process.h"
?
?
//HID發送數據
//返回1發送失敗 返回0發送成功
u8 HID_Send_Data(u8* buffer,u8 length)
{
??? if(sendOk == 1)
??? {
??????? if(length == 0)
??????? {
??????????? SetEPTxStatus(ENDP1, EP_TX_NAK);//不發送
??????? }
??????? else
??????? {
??????????? UserToPMABufferCopy(buffer, GetEPTxAddr(ENDP1), length);
??????????? SetEPTxCount(ENDP1, length);
??????????? SetEPTxValid(ENDP1);//使能發送
??????????? sendOk = 0;//設置發送未完成狀態,等待發送回調函數將數據發送到主機
??????? }
??????? return 0;
??? }
??? else
??? {
??????? return 1;//上一次的數據還沒發送出去,所以這次發送失敗
??? }
}
?
?
//HID接收數據處理
u8 HID_Receive_Data(u8* buffer)
{
??? u16 length = 0;//獲取接收到的數據長度
??? u8 i = 0;
??? if(ReceiveOk == 1)//有數據
??? {
??????? 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;//返回接收到的數據
??????? }
??? }
??? else
??? {
??????? //沒有數據,直接為0
??????? return 0;
??? }
}
?
?
做好這里,基本上就能實現通訊了,詳細工程請查看文章最后的鏈接
?
?
?http://download.csdn.net/detail/dengrengong/8523351
?
?
?
?
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/dengxiaojun/p/4357720.html
總結
以上是生活随笔為你收集整理的USB自定义HID设备实现-STM32的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (王道408考研操作系统)第三章内存管理
- 下一篇: 【专栏必读】王道考研408计算机组成原理