历史上的今天
今天是:2024年11月04日(星期一)
2020年11月04日 | STM32 CustomHID 的实现
2020-11-04 来源:eefocus
如何建立一个自定义的HID工程呢?下面就来讲讲。
首先先介绍下工程的架构,工程的总体架构下图所示,按照下图架构建工程:
STM32 CustomHID 的实现 - ziye334 - ziye334的博客
分析下工程布局,首先是APP,这个组里存放着主文件mian.c,管理所有中断服务程序stm3210x_it.c,及其管理外设库头文件的stm32f10x_conf.h。BSP这个组里存放着BSP.c,外设的洗衣初始化都在这个函数中定义,比如说串口的配置,LED灯的配置,系统时钟的配置,各类NVIC的中断配置。在这个文件中,会定义一个BSP_Init()函数,所有配置的都在这个函数中调用,例如:
void BSP_Init(void)
{
RCC_Configuration();
Set_USBClock();
USB_Init();
USART1_Configuration(115200);
LED_Configuration();
NVIC_Configuration();
USB_Interrupts_Config();
}
而这个BSP_Init()函数在main中调用,这样就使主函数简洁漂亮了。至于CMSIS这个组则是关于Cotex-M3内核的相关文件看,如core_cm3.c和system_stm32f10x.c。StartUp这个组放置系统的启动文件,不同系类的处理器使用不同的启动文件,这里有必要了解:
- startup_stm32f10x_ld_vl.s: for STM32 Low density Value line devices
- startup_stm32f10x_ld.s: for STM32 Low density devices
- startup_stm32f10x_md_vl.s: for STM32 Medium density Value line devices
- startup_stm32f10x_md.s: for STM32 Medium density devices
- startup_stm32f10x_hd.s: for STM32 High density devices
- startup_stm32f10x_xl.s: for STM32 XL density devices
- startup_stm32f10x_cl.s: for STM32 Connectivity line devices
cl:互联型产品,stm32f105/107系列
vl:超值型产品,stm32f100系列
xl:超高密度产品,stm32f101/103系列
ld:低密度产品,FLASH小于64K
md:中等密度产品,FLASH=64 or 128
hd:高密度产品,FLASH大于128
我的这个工程选择高密度型的: startup_stm32f10x_hd.s。USB_User文件组放着USB控制与应用相关的文件,在之前的文章每个文件都详细介绍过。接着是USB-FS-Device_Driver这个组放着USB的驱动,在之前的文章页已经讲述过。最后一个组是STM32F10x_StdPeriph_Driver,它里面存放着外设库文件的驱动代码,很多人为了省事,会把所有的C文件都添加进来,我不建议这么做,还是根据需要添加对应的文件,就拿我们的这个CustomHID工程,我们用到了引脚GPIO、时钟的配置,串口的配置,所以只要添加这几个对应的C库文件就可以了。
上面的各个文件大部分可以网上下载的。
接下去就讲述如何实现CustomHID功能的。
首先,最重要的文件当然是usb_desc.c这个文件了。这个文件存放着各种描述符,比如说设备描述符、配置描述符等,下面就一一介绍。
设备描述符符的定义如下:
/* USB标准设备描述符*/
const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
{
0x12, /*bLength:长度,设备描述符的长度为18字节*/
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType:类型,设备描述符的编号是0x01*/
0x00, /*bcdUSB:所使用的USB版本为2.0*/
0x02,
0x00, /*bDeviceClass:设备所使用的类代码*/
0x00, /*bDeviceSubClass:设备所使用的子类代码*/
0x00, /*bDeviceProtocol:设备所使用的协议*/
0x40, /*bMaxPacketSize:最大包长度为64字节*/
0x34, /*idVendor:厂商ID为0x1234*/
0x12,
0x10, /*idProduct:产品ID为0x1010*/
0x10,
0x00, /*bcdDevice:设备的版本号为2.00*/
0x02,
1, /*iManufacturer:厂商字符串的索引*/
2, /*iProduct:产品字符串的索引*/
3, /*iSerialNumber:设备的序列号字符串索引*/
0x01 /*bNumConfiguration:设备有1种配置*/
}; /* CustomHID设备描述符 */
设备描述符的数组的长度一般为9个字节,该描述符定义了USB协议代号、厂商ID(VID),产品ID(PID)、设备的版本号、以及厂商产品序列号描述符的索引。在USB枚举阶段,USB设备需要通过端口0向USB主机发送设备描述符。
配置描述符集合里有着丰富的USB设备的信息,如用了几个接口,用了几个端点,USB设备做什么用等。代码如下:
/* USB配置描述符集合(配置、接口、端点、类、厂商)(Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] =
{
0x09, /*bLength:长度,设备字符串的长度为9字节*/
USB_CONFIGURATION_DESCRIPTOR_TYPE, /*bDescriptorType:类型,配置描述符的类型编号为0x2*/
CUSTOMHID_SIZ_CONFIG_DESC, /*wTotalLength:配置描述符的总长度为41字节*/
0x00,
0x01, /*bNumInterfaces:配置所支持的接口数量1个*/
0x01, /*bConfigurationValue:该配置的值*/
0x00, /*iConfiguration:该配置的字符串的索引值,该值为0表示没有字符串*/
0xC0, /* bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒
D7:保留必须为1,D6:是否自供电,D5:是否支持远程唤醒,D4~D0:保留设置为0*/
// 0x32, /*从总线上获得的最大电流为100mA */
0x96, /*MaxPower:设备需要从总线上获取多少电流,单位为2mA,0x96表示300mA*/
/************** HID接口描述符****************/
0x09, /*bLength:长度,接口描述符的长度为9字节 */
USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType:接口描述符的类型为0x4 */
0x00, /*bInterfaceNumber:该接口的编号*/
0x00, /*bAlternateSetting:该接口的备用编号 */
0x02, /*bNumEndpoints:该接口所使用的端点数*/
0x03, /*bInterfaceClass该接口所使用的类为HID*/
0x00, /*bInterfaceSubClass:该接口所用的子类 1=BOOT, 0=no boot */
0x00, /*nInterfaceProtocol :该接口使用的协议0=none, 1=keyboard, 2=mouse */
0, /*iInterface: 该接口字符串的索引 */
/*****************HID描述符 ********************/
0x09, /*bLength: HID描述符的长度为9字节 */
HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID的描述符类型为0x21 */
0x10, /*bcdHID: HID协议的版本为1.1 */
0x01,
0x00, /*bCountryCode: 国家代号 */
0x01, /*bNumDescriptors: 下级描述符的数量*/
0x22, /*bDescriptorType:下级描述符的类型*/
CUSTOMHID_SIZ_REPORT_DESC,/* wItemLength: 下一集描述符的长度*/
0x00,
/********************输入端点描述符******************/
0x07, /* bLength: 端点描述符的长度为7字节*/
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x21*/
0x82, /* bEndpointAddress: 该端点(输入)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/
0x03, /* bmAttributes: 端点的属性为为中断端点.
D0~D1表示传输类型:0(控制传输),1(等时传输),2(批量传输),3(中断传输)
非等时传输端点:D2~D7:保留为0
等时传输端点:
D2~D3表示同步的类型:0(无同步),1(异步),2(适配),3(同步)
D4~D5表示用途:0(数据端点),1(反馈端点),2(暗含反馈的数据端点),3(保留),D6~D7:保留,*/
0x40, /* wMaxPacketSize: 该端点支持的最大包长度为64字节*/
0x00,
0x02, /* bInterval: 轮询间隔(2 ms) */
/********************输出端点描述符******************/
0x07, /* 端点描述符的长度为7字节 */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x21*/
0x01, /* bEndpointAddress: 该端点(输出)的地址,D7:0(OUT),1(IN),D6~D4:保留,D3~D0:端点号*/
0x03, /* bmAttributes: 端点的属性为为中断端点 */
0x40, /* wMaxPacketSize: 该端点支持的最大包长度为64字节 */
0x00,
0x02, /* bInterval: 轮询间隔(2 ms) */
};
从上面的代码中可以看出,USB设备使用了1个接口、两个端点:一个中断传输输入端点,端点号为2;一个中断传输的输出端点,端点号为1、每个端点能通讯的最大数据包长度为64字节、USB的功能自定义等。配置描述符是在USB主机发送GET_CONFIGURATION请求时,USB设备发送的。
还有一个很重要的当然报告描述符了:
/* HID的报告描述符*/
const uint8_t CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =
{
/*short Item D7~D4:bTag;D3~D2:bType;D1~D0:bSize
**bTag ---主条目 1000:输入(Input) 1001:输出(Output) 1011:特性(Feature) 1010:集合(Collection) 1100:关集合(End Collection)
** 全局条目 0000:用途页(Usage Page) 0001:逻辑最小值(Logical Minimum) 0010:逻辑最大值(Logical Maximum) 0011:物理最小值(Physical Minimum)
** 0100:物理最大值(Physical Maximum) 0101:单元指数(Unit Exponet) 0110:单元(Unit) 0111:数据域大小(Report Size)
** 1000:报告ID(Report ID) 1001:数据域数量(Report Count) 1010:压栈(Push) 1011:出栈(Pop) 1100~1111:保留(Reserved)
** 局部条目 0000:用途(Usage) 0001:用途最小值(Usage Minimum) 0010:用途最大值(Usage Maximum) 0011:标识符索引(Designator Index)
** 0100:标识符最小值(Designator Minimum) 0101:标识符最大值(Designator Maximum) 0111:字符串索引(String Index) 1000:字符串最小值(String Minimum)
** 1001:字符串最大值(String Maximum) 1010:分隔符(Delimiter) 其他:保留(Reserved)
**bType---00:主条目(main) 01:全局条目(globle) 10:局部条目(local) 11:保留(reserved)
**bSize---00:0字节 01:1字节 10:2字节 11:4字节*/
//0x05:0000 01 01 这是个全局条目,用途页为ST页
0x05, 0x8c, /* USAGE_PAGE (ST Page) */
//0x09:0000 10 01 这是个局部变量,用途为Demo Kit
0x09, 0x01, /* USAGE (Demo Kit) */
//0xa1:1010 00 01 这是一个主条目,集合为应用集合
0xa1, 0x01, /* COLLECTION (Application) */
/* 输入报告*/
//0x09:0000 10 01 这是个局部条目,用途为厂商ID
0x09,0x03, // USAGE ID - Vendor defined
//0x15:0001 01 01 这是个全局条目,逻辑最小值为0
0x15,0x00, // LOGICAL_MINIMUM (0)
//0x26:0010 01 10 这是个全局条目,逻辑最大值为255
0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255)
//0x75:0111 01 01 这是个全局条目,报告大小为8位
0x75,0x08, // REPORT_SIZE (8bit)
//0x95:1001 01 01 这是个全局条目,报告数量为64
0x95,0x40, // REPORT_COUNT (64Byte)
//0x81:1000 00 01 这是个主条目,做输入,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值
0x81,0x02, // INPUT (Data,Var,Abs)
/*输出报告*/
//0x09:0000 10 01 这是个局部条目,用途为厂商ID
0x09,0x04, // USAGE ID - Vendor defined
//0x15:0001 01 01 这是个全局条目,逻辑最小值为0
0x15,0x00, // LOGICAL_MINIMUM (0)
//0x26:0010 01 10 这是个全局条目,逻辑最大值为255
0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255)
//0x75:0111 01 01 这是个全局条目,报告大小为8位
0x75,0x08, // REPORT_SIZE (8bit)
//0x95:1001 01 01 这是个全局条目,报告数量为64
0x95,0x40, // REPORT_COUNT (64Byte)
//0x91:1001 00 01 这是个全局条目,做输出,Data表示这些数据可变,Var表示这些徐居于是独立的变量,Abs表示绝对值
史海拾趣
|
结合半波整流 — 滤波电路 ,分别采用牛顿 — 拉夫逊法和 PSPICE进行求解 ,均得出了正确的结果.经比较 ,两种方法各有所长.尤其是当电路中的非线性元件比较多 ,元件之间的非线性关系比较复杂 ,采用牛顿 — 拉夫逊法难以得到递推表达式时 ,用 PSPICE求 ...… 查看全部问答> |
|
板子是OMAP3530,BSP是从网上下的TI_EVM_3530,BSP中Device Drivers中的VGA Linear Framebuffer只支持x86的cpu,请问我要想添加这个组件的话该怎么办?必须要自己写一个能支持arm的vga驱动吗?我装vs2005的时候只选了ARMV4I,是不是再装上x86部分就 ...… 查看全部问答> |
|
比如像lss、lds之类的指令在分段前得到的段地址和段内偏移,分段后得到的段选择符和段内偏移。是不是这样理解的?这些指令能做到吗?段选择符能直接这样就能得到吗?(请见谅,我没有分数不能给分,我最近在看linux内核,知道的大哥发表些见解)… 查看全部问答> |
|
一直在用 EVC做界面,感觉提高的很慢,做的东西也是老样子,界面界面再界面。怎么样能让自己提高的快些呢?? 一直在做用 EVC做界面,感觉提高的很慢,做的东西也是老样子,界面界面再界面。怎么样能让自己提高的快些呢?? 平台式 WIN CE 5.0… 查看全部问答> |
|
错误信息为:fatal error C1083: Cannot open compiler intermediate file: \'C:\\DOCUME~1\\smc00618\\LOCALS~1\\Temp\\a02420ex\': Permission denied 那个大侠做过TCPMP的编译,帮我看看,我用的环境是EVC4.0+SP4+Smartphone SDK ,Active Proje ...… 查看全部问答> |
|
各位大侠: 怎么才可以把微软的mediaplayer控件里面的微软会标,不显示出来。 或者说,怎么才能把mediaplayer输出的视频流,才我自己定义的窗口内播放呢?… 查看全部问答> |
|
前段时间写了一篇关于建议初学者求助时提供程序流程描述而非简单贴源代码的帖子,下面我给出一个具体的流程描述的例子,当然本例更注重于方法描述,故较为详细,作为流程描述可以适当简化。 1.预置1个16位的寄存器(下称CRC寄存器),初 ...… 查看全部问答> |
|
两块板子,通过SPI3通讯,双线双向,一主一从,问题有一大堆:1.连接JLINK调试,发送数据可以被正确接收,发回的数据不正确(全是0xFF);2.去掉JLINK直接上电运行,收发都不行;另两个工程是同一个,只不过一个SPI3配置为主,一个配置为从,GPIO配 ...… 查看全部问答> |
|
太阳能热水器已成为广泛普及的家庭用品。做一个太阳能热水器小制作模型,可以体验太阳能热水器收集太阳能,让太阳能服务人类的效益。 工具/原料: 纸板、锡纸、木片或木条、剪刀、手工锯、白胶、玻璃管或透明塑料管 步骤: ...… 查看全部问答> |




