最近发现许多人对STM32的USB通讯很感兴趣。要将USB的通讯协议搞懂确实是一个比较绵长的进程。可是USB的HID通讯无论是上位机的规划仍是STM32程序的编程都十分的简略。仅仅我想许多人都不知道罢了。这篇文章的意图是让咱们以最短的时刻将USB加到你的设备中。假如想学得更深就靠咱们。
HID仅仅合适低速传输,其理论上能够到达64KB/S,但多因为windows体系和硬件的联系一般达不到这个传输数度。但这个速度关于一般体系的操控和数据传输都现已足够了,并且是免驱,省去了许多费事。假如您需求高速传输可参阅我的别的一篇文章《STM32的USB例程修正过程》文章在http://blog.csdn.net/cy757/archive/2010/01/01/5117610.aspx
一、安装完MDK后请翻开C:/Keil/ARM/Examples/ST/STM32F10xUSBLib/Demos途径,将Custom_HID在同一个目录下仿制一份,假如你要放到其他途径你需求在MDK Options for target的C/C++中增加USB的头文件途径(MDK下的/INC/ST/STM32F10x/USB)。
二、翻开usb_desc.c文件,该文件首要包括的端点描述符、设备描述符、装备描述符和字符描述符等。详细请咱们参阅其他材料了,这儿首要说几个常用。
u8 DeviceDescriptor[SIZ_DEVICE_DESC]为USB设备描述符。傍边的
0x83, /*idVendor (0x0483)*/
0x04,
0x50, /*idProduct = 0x5750*/
0x57,
//idVender字段。厂商ID号,咱们这儿取0x0483,仅供试验用。
//实践产品不能随意运用厂商ID号,有必要跟USB协会请求厂商ID号。
//留意小端形式,低字节在先。
//idProduct字段。产品ID号,咱们这儿取0x5750。
//留意小端形式,低字节应该在前。
const u8 ConfigDescriptor[SIZ_CONFIG_DESC]是装备描述符,留意如下
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
0x81, /* bEndpointAddress: Endpoint Address (IN) */
0x03, /* bmAttributes: Interrupt endpoint */
0x02, /* wMaxPacketSize: 2 Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (32 ms) */
/* 34 */
0x07, /* bLength: Endpoint Descriptor size */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */
/* Endpoint descriptor type */
0x01, /* bEndpointAddress: */
/* Endpoint Address (OUT) */
0x03, /* bmAttributes: Interrupt endpoint */
0x02, /* wMaxPacketSize: 2 Bytes max */
0x00,
0x20, /* bInterval: Polling Interval (20 ms) */
上面包括了“输入端点描述符”和“输出端点描述符”。
//wMaxPacketSize字段。该端点的最大包长。
//bInterval字段。端点查询的时刻,
为了完结更高速的通讯咱们修正如下:
/******************** Descriptor of endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
0x81, /*bEndpointAddress: Endpoint Address (IN)*/
0x03, /*bmAttributes: Interrupt endpoint*/
0x40, /*wMaxPacketSize: 64 Byte max */
0x00,
0x0A, /*bInterval: Polling Interval (10 ms)*/
/* 34 */
/******************** Descriptor of endpoint ********************/
/* 27 */
0x07, /*bLength: Endpoint Descriptor size*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
0x01, /*bEndpointAddress: Endpoint Address (OUT)*/
0x03, /*bmAttributes: Interrupt endpoint*/
0x40, /*wMaxPacketSize: 64 Byte max */
0x00,
0x0A, /*bInterval: Polling Interval (10 ms)*/
const u8 ReportDescriptor[SIZ_REPORT_DESC]为HID专用的陈述描述符,详细的咱们就参阅材料了,这儿能够直接仿制了。
const u8 CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
{
0x05, 0xFF, // USAGE_PAGE(User define)
0x09, 0xFF, // USAGE(User define)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x01, // USAGE_PAGE(1)
0x19, 0x00, // USAGE_MINIMUM(0)
0x29, 0xFF, // USAGE_MAXIMUM(255)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x40, // REPORT_COUNT (64)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x02, // USAGE_PAGE(2)
0x19, 0x00, // USAGE_MINIMUM (0)
0x29, 0xFF, // USAGE_MAXIMUM (255)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0xFF, // LOGICAL_MAXIMUM (255)
0x95, 0x08, // REPORT_COUNT (8)
0x75, 0x40, // REPORT_SIZE (64)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION
}; /* ReportDescriptor */
const u8 CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR]
const u8 StringProduct[SIZ_STRING_PRODUCT]
const u8 StringSerial[SIZ_STRING_SERIAL]
分别是“厂商字符”、“产品字符”、“产品序列号”,这些将在USB HID设备加载的时分显现。可是这需求这些字符要求为Unicode编码,你需求将你要显现的字符先转为Unicode编码。你能够到http://computer00.21ic.org/user1/2198/archives/2007/42769.html转化。最好咱们还要依据各个数组的长度修正如下界说。
#define CUSTOMHID_SIZ_REPORT_DESC 39
#define CUSTOMHID_SIZ_STRING_VENDOR 64
#define CUSTOMHID_SIZ_STRING_PRODUCT 28
#define CUSTOMHID_SIZ_STRING_SERIAL 26
三、翻开hw_config.c文件,将那些没有的函数删去,只保存如下函数
a) Set_System(void)
b) void Set_USBClock(void)
c) void USB_Interrupts_Config(void)
d) void USB_Cable_Config (FunctionalState NewState)
特别要留意最终一个函数,其首要作用是操控USB的上拉电阻,让电脑检测USB设备是否衔接的。
四、翻开stm32f10x_it.c文件,把EXTI15_10_IRQHandler等中止内的代码删去。
翻开usb_prop.c文件,修正如下:
void CustomHID_Reset(void)
{
/* Set Joystick_DEVICE as not configured */
pInformation->Current_Configuration = 0;
pInformation->Current_Interface = 0;/*the default Interface*/
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 */
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);
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_INTERRUPT);
SetEPTxAddr(ENDP1, ENDP1_TXADDR);
SetEPTxCount(ENDP1, 64);
SetEPRxStatus(ENDP1, EP_RX_DIS);
SetEPTxStatus(ENDP1, EP_TX_NAK);
/* Initialize Endpoint 1 */
// SetEPType(ENDP1, EP_INTERRUPT);
SetEPRxAddr(ENDP1, ENDP1_RXADDR);
SetEPRxCount(ENDP1, 64);
// SetEPTxStatus(ENDP1, EP_TX_DIS);
SetEPRxStatus(ENDP1, EP_RX_VALID);
/* Set this device to response on default address */
SetDeviceAddress(0);
}
五、usb_endp.c文件
void EP1_OUT_Callback(void)
{
这些写接纳代码
}
六、数据发送和接纳,举例阐明
1、数据接纳
u8 DataLen;
DataLen = GetEPRxCount(ENDP1);
PMAToUserBufferCopy(TX1_buffer, ENDP1_RXADDR, DataLen);
SetEPRxValid(ENDP1);
USART1_Send(DataLen);
count_out = 1;
2、数据发送
UserToPMABufferCopy(InBuffer, GetEPTxAddr(ENDP1), 64);
SetEPTxCount(ENDP1, 64);
SetEPTxValid(ENDP1);
假如你发送数据较为频频,每次发送前应运用GetEPTxStatus(ENDP1)检测前次发送是否完结。假如端点状况处于EP_TX_VALID,阐明发送未完毕,假如端点状况处于EP_TX_NAK,阐明发送完毕。