历史上的今天
返回首页

历史上的今天

今天是:2024年11月04日(星期一)

正在发生

2020年11月04日 | STM32 keyboard USB键盘功能的实现

2020-11-04 来源:eefocus

下面编写下USB键盘的程序,依然在CustomHID工程上修改。

依旧最先修改的是usb_desc.c文件。我们从设备描述符开始讲述。

设备描述符需要修改下bMaxPacketSize(最大包长度)域为0x08,因为被本次的工程最大通讯长度就是8字节,正好符合USB规范,所以这里改成0x08,还要注意在usb_prop.c的DEVICE_PROP Device_Property结构体里注册的最大长度也要是0x08,与设备描述符的要相同(我们在下文说到)。这里最好还要修改下PID和VID的域的值,以防该PID和VID对应的设备已经在电脑里有了驱动而导致功能不正常。

/* USB标准设备描述符*/

const uint8_t Keyboard_DeviceDescriptor[KEYBOARD_SIZ_DEVICE_DESC] =

{

    0x12,          /*bLength:长度,设备描述符的长度为18字节*/

    USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType:类型,设备描述符的编号是0x01*/

    0x00,                       /*bcdUSB:所使用的USB版本为2.0*/

    0x02,

    0x00,                       /*bDeviceClass:设备所使用的类代码*/

    0x00,                       /*bDeviceSubClass:设备所使用的子类代码*/

    0x00,                       /*bDeviceProtocol:设备所使用的协议*/

    0x08,                       /*bMaxPacketSize:最大包长度为8字节*/

    0x78,                       /*idVendor:厂商ID为0x7788*/

    0x67,

    0x12,                      /*idProduct:产品ID为0x1122*/

    0x01,

    0x00,                       /*bcdDevice:设备的版本号为2.00*/

    0x02,

    1,                          /*iManufacturer:厂商字符串的索引*/

    2,                          /*iProduct:产品字符串的索引*/

    3,                          /*iSerialNumber:设备的序列号字符串索引*/

    0x01                        /*bNumConfiguration:设备有1种配置*/

}; /* keyboard设备描述符 */


接下去修改下配置描述符。 找到接口的描述符的bNumEndpoints(该接口所使用的端点数)域,不用修改,但需要提下,还是0x02,表示使用2个端点。修改下接口描述符的 nInterfaceProtocol (该接口使用的协议)域为0x01,表示是键盘。在输入端点描述符中端点设置 端点1 为为中断传输的输入端点,设置 wMaxPacketSize:(该端点支持的最大包长度)域的值为0x08,因为本次键盘的工程需要向USB主机发送8字节。在输出端点描述符设置端点1为中断传输的输出端点, 设置为中断传输 设置  wMaxPacketSize:(该端点支持的最大包长度)域的值为0x01,因为USB主机只会向USB从设备发送1个字节。

/* USB配置描述符集合(配置、接口、端点、类、厂商)(Configuration, Interface, Endpoint, Class, Vendor */

const uint8_t Keyboard_ConfigDescriptor[KEYBOARD_SIZ_CONFIG_DESC] =

{

    0x09,   /*bLength:长度,设备字符串的长度为9字节*/

    USB_CONFIGURATION_DESCRIPTOR_TYPE, /*bDescriptorType:类型,配置描述符的类型编号为0x2*/

    KEYBOARD_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*/


    /************** 接口描述符****************/

/* 09 */

    0x09,          /*bLength:长度,接口描述符的长度为9字节 */

    USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType:接口描述符的类型为0x4 */

    0x00,          /*bInterfaceNumber:该接口的编号*/

    0x00,        /*bAlternateSetting:该接口的备用编号 */

    0x02,          /*bNumEndpoints:该接口所使用的端点数*/

    0x03,          /*bInterfaceClass该接口所使用的类为HID*/

    0x01,          /*bInterfaceSubClass:该接口所用的子类 1=BOOT, 0=no boot */

    0x01,          /*nInterfaceProtocol :该接口使用的协议0=none, 1=keyboard, 2=mouse */

    0,            /*iInterface: 该接口字符串的索引 */


    /*****************HID描述符 ********************/

/* 18 */

    0x09,          /*bLength: HID描述符的长度为9字节 */

    HID_DESCRIPTOR_TYPE, /* bDescriptorType: HID的描述符类型为0x21 */

    0x10,          /*bcdHID: HID协议的版本为1.1 */

    0x01,

    0x21,          /*bCountryCode: 国家代号 */

    0x01,          /*bNumDescriptors: 下级描述符的数量*/

    0x22,          /*bDescriptorType:下级描述符的类型*/

    KEYBOARD_SIZ_REPORT_DESC,/* wItemLength: 下一集描述符的长度*/

    0x00,


    /********************输入端点描述符******************/

/* 27 */

    0x07,          /* bLength: 端点描述符的长度为7字节*/

    USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x05*/

    0x81,          /* 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:保留,*/

    0x08,          /* wMaxPacketSize: 该端点支持的最大包长度为8字节*/

    0x00,

    0x0A,          /* bInterval: 轮询间隔(32ms) */


/********************输出端点描述符*******************/

/* 34 */

0x07,          /* bLength: 端点描述符的长度为7字节*/

    USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: 端点描述符的类型为0x05*/

    0x01,          /* 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:保留,*/

    0x01,          /* wMaxPacketSize: 该端点支持的最大包长度为字节*/

    0x00,

    0x0A,          /* bInterval: 轮询间隔(32ms) */

   /* 41 */

}; 


讲到报告描述符,得将报告描述符的整个替换掉。该报告描述符定义了8字节的输入域,第一个字节表示特殊件是否按下,键盘的特殊键包括:ctrl,shift,alt键等,该字节D0表示Ctrl键,D1表示Shift键,D2表示Alt键,其他位保留。第二个字节保留,固定值为0。第三个字节到第八个字节用来保存按键值,如果只有一个按键按下,则按键值保存在第三个字节,如果有两个或两个以上的按键按下,则依次保存在从第三字节开始的字节中,当然最多只能6个按键同时按下,超过6个键值,则不响应。报告描述符还定义了一个字节的输出域,该字节是是用来控制LED灯的,我们都知道键盘的上有几个LED灯,比如说大小写键的LED灯等,该字节的定义:D0:Num Lock   D1:Cap Lock   D2:Scroll Lock   D3:Compose   D4:Kana,由于我一直用笔记本电脑的键盘,所以我也只认识前三个键。在这个工程,我只做了Ctrl键、Shift键、Num Lock键,以及A键。

/* HID的报告描述符*/

/*定义了8字节发送:

**  第一字节表示特殊件是否按下:D0:Ctrl D1:Shift D2:Alt

**  第二字节保留,值为0

**  第三~第八字节:普通键键值的数组,最多能同时按下6个键

**定义了1字节接收:对应键盘上的LED灯,这里只用了两个位。

** D0:Num Lock   D1:Cap Lock   D2:Scroll Lock   D3:Compose   D4:Kana*/

const uint8_t Keyboard_ReportDescriptor[KEYBOARD_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 这是个全局条目,用途页选择为普通桌面页

0x05, 0x01, // USAGE_PAGE (Generic Desktop)

//0x09:0000 10 01 这是个全局条目,用途选择为键盘

0x09, 0x06, // USAGE (Keyboard)

//0xa1:1010 00 01 这是个主条目,选择为应用集合,

0xa1, 0x01, // COLLECTION (Application)

//0x05:0000 01 11 这是个全局条目,用途页选择为键盘/按键

0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad)


//0x19:0001 10 01 这是个局部条目,用途的最小值为0xe0,对应键盘上的左ctrl键

0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)

//0x29:0010 10 01 这是个局部条目,用途的最大值为0xe7,对应键盘上的有GUI(WIN)键

0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)

//0x15:0001 01 01 这是个全局条目,说明数据的逻辑值最小值为0

0x15, 0x00, // LOGICAL_MINIMUM (0)

//0x25:0010 01 01 这是个全局条目,说明数据的逻辑值最大值为1

0x25, 0x01, // LOGICAL_MAXIMUM (1)


//0x95:1001 01 01 这是个全局条目,数据域的数量为8个

0x95, 0x08, // REPORT_COUNT (8)

//0x75:0111 01 01 这是个全局条目,每个数据域的长度为1位

0x75, 0x01, // REPORT_SIZE (1)    

//0x81:1000 00 01 这是个主条目,有8*1bit数据域作为输入,属性为:Data,Var,Abs

0x81, 0x02, // INPUT (Data,Var,Abs)


//0x95:1001 01 01 这是个全局条目,数据域的数量为1个

0x95, 0x01, // REPORT_COUNT (1)

//0x75:0111 01 01 这是个全局条目,每个数据域的长度为8位

0x75, 0x08, // REPORT_SIZE (8)

//0x81:1000 00 01 这是个主条目,有1*8bit数据域作为输入,属性为:Cnst,Var,Abs

0x81, 0x03, // INPUT (Cnst,Var,Abs)


//0x95:1001 01 01 这是个全局条目,数据域的数量为6个

0x95, 0x06, // REPORT_COUNT (6)

//0x75:0111 01 01 这是个全局条目,每个数据域的长度为8位

0x75, 0x08, // REPORT_SIZE (8)

//0x25:0010 01 01 这是个全局条目,逻辑最大值为255

0x25, 0xFF, // LOGICAL_MAXIMUM (255)

//0x19:0001 10 01 这是个局部条目,用途的最小值为0

0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))

推荐阅读

史海拾趣

Analog Microwave Design公司的发展小趣事

随着公司规模的不断扩大,Analog Microwave Design公司开始将目光投向国际市场。为了更好地拓展海外业务,公司制定了一套完善的国际化战略。首先,公司加强了与国际知名企业的合作,通过技术交流和合作研发,提升了公司的技术水平和国际影响力。其次,公司积极参加国际展览和会议,展示公司的最新产品和技术成果,吸引了众多海外客户的关注。通过这些努力,公司的海外业务得到了快速发展,成为公司新的增长点。

Honda Tsushin Kogyo Co Ltd公司的发展小趣事

在电子行业快速发展的同时,Honda Tsushin Kogyo也面临着来自技术革新、市场竞争等方面的挑战。为了保持领先地位,公司可能积极应对这些挑战,通过转型升级来实现可持续发展。例如,公司可能加大了对新能源、物联网等新兴领域的投入,研发出符合市场需求的新产品。同时,公司还注重提升生产效率和降低成本,以应对激烈的市场竞争。

Caliber公司的发展小趣事

Caliber公司自创立之初,便以技术创新为核心竞争力。在电子行业的早期,该公司敏锐地捕捉到市场对高性能计算芯片的需求,投入大量资源进行研发。经过数年的努力,Caliber成功推出了一款具有划时代意义的芯片产品,以其出色的性能和稳定性赢得了市场的广泛认可。这一创新不仅为Caliber带来了巨大的商业成功,也为整个电子行业的发展注入了新的活力。

ETA-USA公司的发展小趣事

随着业务的发展和市场的扩大,ETA-USA开始在全球范围内布局。公司先后在中国、欧洲等地设立了分公司或办事处,以更好地服务当地客户。这一全球扩张策略不仅增强了公司的市场竞争力,也为其带来了更多的商业机会和合作伙伴。

Corning Cable Systems公司的发展小趣事

在深海光缆领域,Corning Cable Systems公司也展现出了强大的实力。公司成功研发出适用于深海环境的光缆产品,并在多个国际项目中得到了广泛应用。这些深海光缆不仅具有优异的传输性能,还能够在极端恶劣的海底环境下保持长期稳定运行,为跨洋通信提供了可靠的保障。

ACT [Advanced Crystal Technology]公司的发展小趣事

在深海光缆领域,Corning Cable Systems公司也展现出了强大的实力。公司成功研发出适用于深海环境的光缆产品,并在多个国际项目中得到了广泛应用。这些深海光缆不仅具有优异的传输性能,还能够在极端恶劣的海底环境下保持长期稳定运行,为跨洋通信提供了可靠的保障。

问答坊 | AI 解惑

噪声系数测量的三种方法

摘要:本文介绍了测量噪声系数的三种方法:增益法、Y系数法和噪声系数测试仪法。这三种方法的比较以表格的形式给出。 前言在无线通信系统中,噪声系数(NF)或者相对应的噪声因数(F)定义了噪声性能和对接收机灵敏度的贡献。本篇应用笔记详细阐述这 ...…

查看全部问答>

找手机开发,地点北京

现有手机开发项目,要求有经验的手机开发团队参与。有意可以发:project911@163.com…

查看全部问答>

谁有EVC4.0+PocketPc2003开发PDA反面的电子书?

我刚刚接触EVC4.0+PocketPc2003开发PDA程序,在网上总找不到 相关的电子教程,哪位前辈能提供些教程啊!急 啊!…

查看全部问答>

《程序员面试宝典》 一本很好的面试书籍

《程序员面试宝典》一本很好的面试书籍…

查看全部问答>

制作高频加热设备过程中的一些新感触

开年后,心思都在高频加热设备上,到今天,实验结果比较满意,频率920KHz,已经达到4500W的功率,目前看还有一定的扩展余量,基本满足产品需求,下一步将继续完善,实现产品化。 总的来说,做电源之前有两次经历,一次是03年的电动自行车项目,用a ...…

查看全部问答>

高频无线类要用模块

本帖最后由 paulhyde 于 2014-9-15 09:44 编辑 各位高手,根据刚出的2011清单 高频无线类的应该会有 请问需要准备什么模块啊?能提供一些资料吗?谢谢!  …

查看全部问答>

求摄像头大神指点

本帖最后由 jameswangsynnex 于 2015-3-3 19:58 编辑 拆了手头nokiaE66的摄像头...想用STM32 cortex m3驱动它...... 没怎么接触过手机的摄像头...貌似摄像头后有块STv0986... 找到原理图...想知道摄像头引脚:PDATA2P...PDATA2N...PCLK2P...PCLK2 ...…

查看全部问答>

EEWORLD大学堂----MSP430进阶培训—MSP430F5529的使用与开发

MSP430进阶培训—MSP430F5529的使用与开发:https://training.eeworld.com.cn/course/236 ????? MSP430F5529是德州仪器新一代F5xxx系列MCU的典型代表,不但拥有更低的功耗,而且在模拟外设、?数字外设和系统软件开发方面有了很大的改进。本培训课 ...…

查看全部问答>

51单片机产生spwm波

求教为什么TH0=0x216,这样的话对应的二进制不就不止8位了嘛 搜索 复制 …

查看全部问答>