STM32 USB 主机的鼠标和键盘驱动

本文基于 <STM32 USB Host 连接鼠标和键盘>样例, 继续详细说明鼠标和键盘的驱动.
首先介绍鼠标, 当前鼠标的格式有很多有先发送按键的有先发送移动的, 我的鼠标是先发送按键的, 且是鼠标键盘公用一个USB接口, 然后键盘的特殊字符(例如调节音量, 播放控制等)通过鼠标发送, 当为鼠标报文时, 第一个字符为1, 当发送键盘特殊报文时, 第一个字符为0, 具体格式是:

  1. 鼠标报文
地址 说明
[0] 报文类型, 1为鼠标报文, 0为键盘特殊字符报文
[1] 按键状态, 包括0位左键, 1位右键,2位中键
[2] X轴移动值
[3] Y轴移动值
[4] 滚轮旋转值
  1. 键盘特殊报文
地址 说明
[0] 报文类型, 1为鼠标报文, 0为键盘特殊字符报文
[1] 键盘特殊字符
[2]
[3]
[4]

这种格式与usbh_hid_mouse.c中给的格式完全不同, 所以要对整个文件都要修改.

  1. usbh_hid_mouse.h

因为当前鼠标多了一个滚轮和中键, 所以要修改结构体HID_MOUSE_Info_TypeDef:

typedef struct _HID_MOUSE_Info
{/* [ */uint8_t   type;uint8_t   buttons[3];
/* ] */int8_t    x;int8_t    y;
/* [ */int8_t    z;uint8_t   key;
/* ] */
}
HID_MOUSE_Info_TypeDef;
  1. usbh_hid_mouse.c

因为我的鼠标报文最大5个字节, 而默认是4个字节, 所以我把接收缓冲区改成了数组


/** @defgroup USBH_HID_MOUSE_Private_Variables* @{*/
HID_MOUSE_Info_TypeDef    mouse_info;
uint32_t                  mouse_report_data[2];
uint32_t                  mouse_rx_report_buf[2]; // 这个buf在最新的USBH库中已经添加, 但不是数组, 之前是需要自己创建的, 防止接收与提取的buf冲突

然后是添加和修改按键和移动数据的顺序:

/* Structures defining how to access items in a HID mouse report */
/* Access message status. */
static const HID_Report_ItemTypedef prop_type = {(uint8_t *)(void *)mouse_report_data + 0, /*data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFF,  /*max value read can return*/0,     /*min vale device can report*/0xFF,  /*max value device can report*/1      /*resolution*/
};/* Access the special key, when the message status is 3. */
static const HID_Report_ItemTypedef prop_key = {(uint8_t *)(void *)mouse_report_data + 1, /*data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFF,  /*max value read can return*/0,     /*min vale device can report*/0xFF,  /*max value device can report*/1      /*resolution*/
};/* Access button 1 state. */
static const HID_Report_ItemTypedef prop_b1 = {(uint8_t *)(void *)mouse_report_data + 1, /*data*/1,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/0,     /*signed?*/0,     /*min value read can return*/1,     /*max value read can return*/0,     /*min value device can report*/1,     /*max value device can report*/1      /*resolution*/
};/* Access button 2 state. */
static const HID_Report_ItemTypedef prop_b2 = {(uint8_t *)(void *)mouse_report_data + 1, /*data*/1,     /*size*/1,     /*shift*/0,     /*count (only for array items)*/0,     /*signed?*/0,     /*min value read can return*/1,     /*max value read can return*/0,     /*min value device can report*/1,     /*max value device can report*/1      /*resolution*/
};/* Access button 3 state. */
static const HID_Report_ItemTypedef prop_b3 = {(uint8_t *)(void *)mouse_report_data + 1, /*data*/1,     /*size*/2,     /*shift*/0,     /*count (only for array items)*/0,     /*signed?*/0,     /*min value read can return*/1,     /*max value read can return*/0,     /*min vale device can report*/1,     /*max value device can report*/1      /*resolution*/
};/* Access x coordinate change. */
static const HID_Report_ItemTypedef prop_x = {(uint8_t *)(void *)mouse_report_data + 2, /*data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFF,  /*max value read can return*/0,     /*min vale device can report*/0xFF,  /*max value device can report*/1      /*resolution*/
};/* Access y coordinate change. */
static const HID_Report_ItemTypedef prop_y = {(uint8_t *)(void *)mouse_report_data + 3, /*data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFF,  /*max value read can return*/0,     /*min vale device can report*/0xFF,  /*max value device can report*/1      /*resolution*/
};/* Access z coordinate change. */
static const HID_Report_ItemTypedef prop_z = {(uint8_t *)(void *)mouse_report_data + 4, /*data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFF,  /*max value read can return*/0,     /*min vale device can report*/0xFF,  /*max value device can report*/1      /*resolution*/
};

接下来是修改初始化函数USBH_HID_MouseInit,
就是对刚修改的数组初始化, 并将地址存到HID_Handle->pData

/*** @brief  USBH_HID_MouseInit*         The function init the HID mouse.* @param  phost: Host handle* @retval USBH Status*/
USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost)
{uint32_t i;HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData[phost->pActiveClass->CurrInterface];mouse_info.x = 0U;mouse_info.y = 0U;mouse_info.z = 0U;mouse_info.buttons[0] = 0U;mouse_info.buttons[1] = 0U;mouse_info.buttons[2] = 0U;for (i = 0U; i < (sizeof(mouse_report_data) / sizeof(uint32_t)); i++){mouse_report_data[i] = 0U;mouse_rx_report_buf[i] = 0U;}if (HID_Handle->length > sizeof(mouse_report_data)){HID_Handle->length = sizeof(mouse_report_data);}HID_Handle->pData = (uint8_t *)(void *)mouse_rx_report_buf;USBH_HID_FifoInit(&HID_Handle->fifo, phost->device.Data, HID_QUEUE_SIZE * sizeof(mouse_report_data));return USBH_OK;
}

最后是修改接收报文的解析函数USBH_HID_MouseDecode

/*** @brief  USBH_HID_MouseDecode*         The function decode mouse data.* @param  phost: Host handle* @retval USBH Status*/
static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost)
{HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData[phost->pActiveClass->CurrInterface];if (HID_Handle->length == 0U){return USBH_FAIL;}/*Fill report */if (USBH_HID_FifoRead(&HID_Handle->fifo, &mouse_report_data, HID_Handle->length) ==  HID_Handle->length){/*Decode report */mouse_info.type           = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_type, 0U);if (mouse_info.type == 1) {mouse_info.buttons[0] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b1, 0U);mouse_info.buttons[1] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b2, 0U);mouse_info.buttons[2] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_b3, 0U);mouse_info.x          = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_x, 0U);mouse_info.y          = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_y, 0U);mouse_info.z          = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_z, 0U);} else {mouse_info.key        = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_key, 0U);}return USBH_OK;}return   USBH_FAIL;
}

这样鼠标驱动就完成了, 剩下的就是解析完以后的HID回调函数要做的事了, 例如向emwin发送鼠标事件或自己写鼠标事件, 这些就跟应用强相关了

然后是键盘驱动, 键盘格式基本都是通用的, 只有一些特殊字符不同, 主要就是修改解析函数就行了,
USBH_HID_KeybdDecode
键盘的数据解析主要就是在同时按下多个按键的时候比较麻烦, 如果是一指禅的话, 库自带的驱动是可以使用的. 我是想把键盘当做重要的输入工具处理的, 打字、输入命令啥的, 所以还是需要对多按键进行处理的, 主要思路是通过history数组记录上次输入的按键, 然后比较这次和上次的不同, 得到最新按下的按键

uint8_t keybd_len = 0;
uint8_t history[6] = { 0 };
uint8_t history_len = 0;
uint8_t capsLk_led = 0;
/*** @brief  USBH_HID_KeybdDecode*         The function decode keyboard data.* @param  phost: Host handle* @retval USBH Status*/
static USBH_StatusTypeDef USBH_HID_KeybdDecode(USBH_HandleTypeDef *phost)
{USBH_StatusTypeDef status = USBH_FAIL;uint8_t x;uint8_t len = 1;HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *)phost->pActiveClass->pData[phost->pActiveClass->CurrInterface];if (HID_Handle->length == 0U)return USBH_FAIL;/*Fill report */if (USBH_HID_FifoRead(&HID_Handle->fifo, &keybd_report_data, HID_Handle->length) == HID_Handle->length) {keybd_info.lctrl  = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_lctrl,  0U);keybd_info.lshift = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_lshift, 0U);keybd_info.lalt   = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_lalt,   0U);keybd_info.lgui   = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_lgui,   0U);keybd_info.rctrl  = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_rctrl,  0U);keybd_info.rshift = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_rshift, 0U);keybd_info.ralt   = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_ralt,   0U);keybd_info.rgui   = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_rgui,   0U);for (x = 0U; x < sizeof(keybd_info.keys); x++) {keybd_info.keys[x] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)&imp_0_key_array, x);if (keybd_info.keys[x])len = x + 1;}keybd_len = len;if ((keybd_len == history_len == 1) &&(keybd_info.keys[0] == history[0]))return USBH_FAIL;if (keybd_len >= history_len) {if (find_new_value(history, &history_len, keybd_info.keys, keybd_len) == 1)memcpy(keybd_info.keys, history, keybd_len);if (keybd_info.keys[keybd_len - 1] == KEY_CAPS_LOCK)capsLk_led = ~capsLk_led;status = USBH_OK;} else if ((keybd_len == 1) && (keybd_info.keys[0] == 0)) {memset(history, 0, 6);history_len = keybd_len;}if ((keybd_info.keys[0] != 0) && (status == USBH_FAIL)) {memcpy(history, keybd_info.keys, keybd_len);history_len = keybd_len;}}return status;
}

查找新按键函数


static int find_new_value(uint8_t *out, uint8_t *out_len, const uint8_t *in, uint8_t in_len)
{int res;int n, m;if (in_len < *out_len)return -1;if (in_len == *out_len == 1) {out[0] = in[0];return 0;}for (n = 0; n < in_len; n++) {res = 0;for (m = 0; m < *out_len; m++) {if (out[m] == in[n]) {res |= 1;break;}}if (res == 0)out[(*out_len)++] = in[n];if (in_len == *out_len)break;}return 1;
}

最后是返回当前按键值USBH_HID_GetASCIICode, 最新值储存在数组末尾, 并根据Shift和capsLK状态输出不同值
USBH_HID_GetKeyCode直接返回按键值, 主要是检测是否为功能按键

/*** @brief  USBH_HID_GetASCIICode*         The function decode keyboard data into ASCII characters.* @param  phost: Host handle* @param  info: Keyboard information* @retval ASCII code*/
uint8_t USBH_HID_GetASCIICode(HID_KEYBD_Info_TypeDef *info)
{uint8_t output;uint8_t keys = info->keys[keybd_len - 1];if ((info->lshift == 1U) || (info->rshift == 1U)) {if ((capsLk_led) &&((keys >= KEY_A) &&(keys <= KEY_Z)))output = HID_KEYBRD_Key[HID_KEYBRD_Codes[keys]];elseoutput = HID_KEYBRD_ShiftKey[HID_KEYBRD_Codes[keys]];} else {if ((capsLk_led) &&((keys >= KEY_A) &&(keys <= KEY_Z)))output = HID_KEYBRD_ShiftKey[HID_KEYBRD_Codes[keys]];elseoutput = HID_KEYBRD_Key[HID_KEYBRD_Codes[keys]];}return output;
}uint8_t USBH_HID_GetKeyCode(HID_KEYBD_Info_TypeDef *info)
{uint8_t output;output = info->keys[keybd_len - 1];return output;
}

此驱动并不适用所有键盘、鼠标, 仅做参考.

STM32 USB Host 鼠标和键盘驱动 -- 原创相关推荐

  1. STM32 USB Host 同时连接多个设备样例(如鼠标和键盘)--原创

    STM32 USB Host 同时连接多个设备样例(如鼠标和键盘) 在网上搜了很多都是USB Host单独连接鼠标或键盘的样例, 而当前很多无线鼠标键盘都是并到一个USB口上的, 也就是同一个USB有 ...

  2. USB设备,鼠标,键盘使用CH372,CH375,进行模拟的历程

    开始打算做一个关于USB设备共享的机器,多台电脑共享一个鼠标键盘: 模拟鼠标或者键盘,必须使用外部固件模式,内置固件只负责信息数据的传输,所以不得不选择并口控制或者SPI的方式,接下来就是了解基本的U ...

  3. STM32 USB高速USB端口加持4G联网

    本文由RT-Thread论坛用户@fhqmcu原创发布:https://club.rt-thread.org/ask/article/8fc0968257c2ca01.html 1.前言 关于STM3 ...

  4. STM32之独立版USB(Host)驱动+MSC+Fatfs移植

    源:STM32之独立版USB(Host)驱动+MSC+Fatfs移植 STM32之USB驱动库详解(架构+文件+函数+使用说明+示例程序)

  5. stm32 USB HID+CDC 鼠标键盘串口 组合设备配置解析

    前言 查阅网上的博客与代码,很多都是关于USB的鼠标配置.USB的键盘配置.USB的虚拟串口配置,稍微深入一点的会将鼠标键盘合在一起,但移植起来就会报很多错误,要么是检测不到,要么是警告,这很正常,因 ...

  6. linux3.4.2 之usb鼠标驱动,键盘驱动

    目录 1  USB相关基本知识 2  USB鼠标编程指导 3 USB鼠标驱动程序完整源码 4  USB鼠标驱动测试 5  USB键盘基本知识 6 USB键盘驱动程序 4  USB键盘驱动测试 1  U ...

  7. linux ps2键盘驱动,通用键盘鼠标模拟(包括USB和PS2)

    通过直接调用Kbdclass的回调函数KeyboardClassServiceCallback直接给上层发送键盘驱动.这个方法网上已经公开,参考Hook KeyboardClassServiceCal ...

  8. linux内核添加usb键盘驱动,配置USB外设 - linux-2.6.32在mini2440开发板上移植_Linux编程_Linux公社-Linux系统门户网站...

    linux-2.6.32在mini2440开发板上移植 配置USB外设 [日期:2013-04-08] 来源:Linux社区 作者:ssdsafsdsd [字体:大 中 小] 编者:因为LINUX内核 ...

  9. Linux下的USB总线驱动(04)——USB键盘驱动 usbkbd.c

    原文链接地址:http://www.linuxidc.com/Linux/2012-12/76197p9.htm 跟USB鼠标类型一样,USB键盘也属于HID类型,代码在/dirver/hid/usb ...

  10. linux usb键盘驱动详解

    1.首先我们通过上节的代码中修改,来打印下键盘驱动的数据到底是怎样的 先来回忆下,我们之前写的鼠标驱动的id_table是这样: 所以我们要修改id_table,使这个驱动为键盘的驱动,如下图所示: ...

最新文章

  1. 设计模式之外观模式(Facade)摘录
  2. redhat linux系统补丁,如何在CentOS和RHEL系统上安装或自动更新安全补丁
  3. 设计模式详解(总纲)
  4. scrapy 安装_安装scrapy时出错
  5. Java Web之文件的上传及下载
  6. STM32 - 定时器的设定 - 基础-03 - 输出波形控制 - Output compare mode
  7. [Data Pump]impdp导入笔记
  8. 招聘 | 语言资源高精尖创新中心研发人员招聘启事
  9. 实战Python:利用Python实现基于终端的文本行编辑程序
  10. QQ空间 自动点赞脚本
  11. 漫画 | 前端发展史的江湖恩怨情仇~
  12. 《淘宝技术这十年》之LAMP架构的网站
  13. DSP指纹识别系统硬件设计
  14. 数据流系列-2-前后端数据传输技巧2
  15. 配置H3C设备无线AP多vlan步骤
  16. 国产鸿蒙2.0尝鲜试用
  17. 手机摄影中多摄融合理论详解与代码实战
  18. 构建TCP套接字(socket)的概念及具体步骤
  19. 国内消防报警主机调试软件
  20. mysql的环境搭建

热门文章

  1. VS2003一点查找按钮就卡死处理方法
  2. 【AI】人工智能之深度学习(1)—— 入门
  3. Jemalloc安装
  4. 对涉密计算机检查内容,保密工作检查内容主要有哪些
  5. php 数组排序方法,php数组排序的方法有哪些 - php完全自学手册 - php中文网手册...
  6. Cain嗅探工具的基本使用
  7. STM32入门学习 第七天
  8. 斐讯路由器K2弹广告-刷机过程
  9. 阿铭Linux_传统IDC 部署网站学习笔记20190118
  10. nginx 5xx 状态码分析