关于STM32上用HID HOST调鼠标数据的解析

2024-06-16 23:20

本文主要是介绍关于STM32上用HID HOST调鼠标数据的解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

关于这章主要是基于我前面的那篇文章
链接: 关于怎么用Cubemx生成的USBHID设备实现读取一体的鼠标键盘设备(改进版)
https://blog.csdn.net/qq_29187987/article/details/139535648?spm=1001.2014.3001.5501
在这里插入图片描述

引用的文章的简介

引用的这篇文章主要就是讲如何在STM32上配置用于界面的鼠标和键盘,一般的STM32的配置都是只有一个鼠标或者一个键盘,这篇文章主要是用STM32读取现在市面上的一体化的USB鼠标键盘,实现这种一个USB的鼠标键盘的STM32配置。

关于这篇文章的实现

由于上面那篇文章的实现,可以读取到鼠标和键盘的数据,但是其实鼠标并没有完全实现,鼠标移动的时候会有漂移的现象,所以这篇文章主要根据linux读取USB的方法,将STM32也实现linux下的USB鼠标键盘操作。并显示在界面上。

二、解决鼠标漂移的方法

要完全复现linux下的鼠标,就要先了解鼠标会给STM32发送多少数据。根据网上的各种文章参考,鼠标给STM32和给电脑的数据都是8个字节。

插述:关于网上的一些说法

参考文章:链接: 罗技 无线鼠标 USB HID数据格式
https://blog.csdn.net/sinat_23998749/article/details/123572543

这篇文章是我参考的文章,但是有一些和我现在这个杂牌子的鼠标不太一样,不知道是不是鼠标不一样还是什么情况,文章中数据字节的意义不对。

鼠标的数据解析

STM32中,配置为USB HOST后,Cubemx会自动生成代码,其中有一个文件usbh_hid_mouse.c里,是关于解析鼠标数据的函数。下面是部分解析用的代码。

下面展示一些 内联代码片

static const HID_Report_ItemTypedef prop_x =
{(uint8_t *)(void *)mouse_report_data + 1, /*zijie3 data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFFFF,/*max value read can return*/0,     /*min vale device can report*/0xFFFF,/*max value device can report*/1      /*resolution*/
};

1、函数添加

其中,mouse_report_data + 1的部分就是第1个字节的数据。,所以,要解析所有的鼠标数据,所以要多创建几个这个结构体,并且修改下要要解析第几个数据。具体如下:

创建prop_y,读取第二个字节数据。

下面展示一些 内联代码片

static const HID_Report_ItemTypedef prop_y =
{(uint8_t *)(void *)mouse_report_data + 2, /*zijie4  data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFFFF,/*max value read can return*/0,     /*min vale device can report*/0xFFFF,/*max value device can report*/1      /*resolution*/
};

创建prop_z,读取第三个字节数据。

下面展示一些 内联代码片

static const HID_Report_ItemTypedef prop_z =
{(uint8_t *)(void *)mouse_report_data + 3, /*zijie4  data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFFFF,/*max value read can return*/0,     /*min vale device can report*/0xFFFF,/*max value device can report*/1      /*resolution*/
};

创建prop_extra,读取第四个字节数据。

下面展示一些 内联代码片

static const HID_Report_ItemTypedef prop_extra =
{(uint8_t *)(void *)mouse_report_data + 4, /*zijie4  data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFFFF,/*max value read can return*/0,     /*min vale device can report*/0xFFFF,/*max value device can report*/1      /*resolution*/
};

创建prop_extra2,读取第五个字节数据。

下面展示一些 内联代码片

static const HID_Report_ItemTypedef prop_extra2 =
{(uint8_t *)(void *)mouse_report_data + 5, /*zijie4  data*/8,     /*size*/0,     /*shift*/0,     /*count (only for array items)*/1,     /*signed?*/0,     /*min value read can return*/0xFFFF,/*max value read can return*/0,     /*min vale device can report*/0xFFFF,/*max value device can report*/1      /*resolution*/
};

2、修改函数

完成后,就是要怎么使用1中自己创建的代码。这些代码也都是在usbh_hid_mouse.c中使用。

在usbh_hid_mouse.c中,有一个函数叫作
USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost)
这个函数如下:

下面展示一些 内联代码片

USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost)
{HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData[1];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.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);mouse_info.extra = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_extra, 0U);mouse_info.extra2 = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_extra2, 0U);/*上面的都是自己加的*/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);return USBH_OK;}return   USBH_FAIL;
}

3、修改mouse_info

我们找到mouse_info,这个变量在哪里定义的,发现是HID_MOUSE_Info_TypeDef类型的,所以我们要修改的就是这个HID_MOUSE_Info_TypeDef类型。
通过查找功能,我们找到HID_MOUSE_Info_TypeDef这个的定义如下:
下面展示一些 内联代码片

typedef struct _HID_MOUSE_Info
{uint8_t              x;uint8_t              y;/*下面是自己加的*/uint8_t              z;uint8_t              extra;uint8_t              extra2;/*上面是自己加的*/uint8_t              buttons[3];
}
HID_MOUSE_Info_TypeDef;

可以看到,我自己在mouse_info的定义中加了三个结构体中的变量,z,extra,extra2,这三个都是后面会用到的。

关于完成上面的步骤后要了解的知识

到了这里,一般跑起来不会有什么问题,但是STM32的代码并不能解析出鼠标数据,因为没有参考上一篇文章,根据文章头部的文章
链接: 关于怎么用Cubemx生成的USBHID设备实现读取一体的鼠标键盘设备(改进版)
根据这篇文章可知,实现USB鼠标键盘的读取最后是在USBH_HID_EventCallback(USBH_HandleTypeDef *phost,uint8_t flag)这个函数中的。函数如下:
下面展示一些 内联代码片

void USBH_HID_EventCallback(USBH_HandleTypeDef *phost,uint8_t flag)
{char c;HID_KEYBD_Info_TypeDef *k_pinfo;HID_MOUSE_Info_TypeDef *m_pinfo;if(1 == flag){m_pinfo = USBH_HID_GetMouseInfo(phost); /* 这里解析鼠标数据 */if (m_pinfo != NULL){Mousedataprocess(mouse_info);//我自己的函数memset(m_pinfo ,0,sizeof(HID_MOUSE_Info_TypeDef ));}}else{k_pinfo = USBH_HID_GetKeybdInfo(phost); /* ?????? */if (k_pinfo != NULL){c = USBH_HID_GetASCIICode(k_pinfo); /* ???ASCII? */Keypaddataprocess(c);  //我自己的函数memset(k_pinfo ,0,sizeof(HID_KEYBD_Info_TypeDef ));}}
}

根据改进版的实现USB鼠标键盘可知,每次鼠标移动或者按键或者键盘按键,USBH_HID_EventCallback就会运行一次。

那么,我们只要在USBH_HID_EventCallback中跑USBH_HID_GetMouseInfo就可以解析鼠标数据了。

因为USBH_HID_MouseDecode在USBH_HID_GetMouseInfo函数中跑了的。

printf出来发现,x是鼠标的按键数据,y,z,extra是鼠标的移动数据。
也就是鼠标的第二个字节,第三个字节,第四个字节。

【注释】:其实这里的第二个字节,第三个字节,第四个字节只是针对我的鼠标,不知道适不适用于读者的鼠标,所以读者最好printf出现看看,读者的鼠标移动后,第几个字节的数据会变化。

根据我解析出来的结果可知,我的y的8个位,和z的前4个位,组合在一起是X移动的数据,extra和z的后4个位组合在一起,是Y移动的数据。

在这里插入图片描述
因为移动数据是12位的,所以当12位的最高位是1的时候,表示是向负向移动(补码表示),最高位(第12位)是0的时候,表示鼠标向正向移动。

解释如下:
对于字节5-7 的意义:
字节6的低4位bits + 字节5,构成12bits的X移动数据,补码表示
字节7 +字节6的高4bits,构成12bits的Y移动数据,补码表示
似乎是高4bits为符号位,但可以统一这样解码:
如果最高bit0, 其值直接为正向移动值;
如果最高bit1,则12bits数据按位取反,然后+1,得到移动值,但表示为负向移动值;

原文链接:https://blog.csdn.net/sinat_23998749/article/details/123572543

我的鼠标移动解析代码

我的解析代码如下:
status1代表是y,status2代表是z,status3代表是extra。

下面展示一些 内联代码片

void Showmousemovedstatus(uint8_t status1,uint8_t status2,uint8_t status3)
{uint16_t X_move = 0;X_move = (status2&0x0F)<<8;X_move = X_move | status1;uint16_t Y_move = 0;Y_move = (status2&0xF0)>>0;Y_move = (Y_move | (status3<<8))>>4;//printf("%d,%d,%d,%d,%d\r\n",data.x,data.y,data.z,data.extra,data.extra2);printf("%d,%d\r\n",X_move,Y_move);if((X_move&0x0800)!=0){X_move = ~(X_move-1);X_move = X_move<<4;X_move = X_move>>4;if(_mymouse.x >= X_move){_mymouse.x-=X_move;}else{_mymouse.x=0;}}else{_mymouse.x+=X_move;if(_mymouse.x >= HOR_RES_SIZE){_mymouse.x=HOR_RES_SIZE;}}if((Y_move&0x0800)!=0){Y_move = ~(Y_move-1);Y_move = Y_move<<4;Y_move = Y_move>>4;if(_mymouse.y >= Y_move){_mymouse.y -= Y_move;}else{_mymouse.y = 0;}}else{_mymouse.y+=Y_move;if(_mymouse.y >= VER_RES_SIZE ){_mymouse.y=VER_RES_SIZE ;}}//printf("%d,%d\r\n",X_move,Y_move);
}

结尾结合下LVGL

由于我的项目是要结合LVGL,所以我把我的_mymouse.y和_mymouse.x作为全局变量,给了LVGL里的函数。
下面展示一些 内联代码片

static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
{/*Your code comes here*/(*x) = _mymouse.x;(*y) = _mymouse.y;
}

实现鼠标显示在界面上。

这篇关于关于STM32上用HID HOST调鼠标数据的解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067841

相关文章

解析 XML 和 INI

XML 1.TinyXML库 TinyXML是一个C++的XML解析库  使用介绍: https://www.cnblogs.com/mythou/archive/2011/11/27/2265169.html    使用的时候,只要把 tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

【服务器运维】MySQL数据存储至数据盘

查看磁盘及分区 [root@MySQL tmp]# fdisk -lDisk /dev/sda: 21.5 GB, 21474836480 bytes255 heads, 63 sectors/track, 2610 cylindersUnits = cylinders of 16065 * 512 = 8225280 bytesSector size (logical/physical)

SQL Server中,查询数据库中有多少个表,以及数据库其余类型数据统计查询

sqlserver查询数据库中有多少个表 sql server 数表:select count(1) from sysobjects where xtype='U'数视图:select count(1) from sysobjects where xtype='V'数存储过程select count(1) from sysobjects where xtype='P' SE

tf.split()函数解析

API原型(TensorFlow 1.8.0): tf.split(     value,     num_or_size_splits,     axis=0,     num=None,     name='split' ) 这个函数是用来切割张量的。输入切割的张量和参数,返回切割的结果。  value传入的就是需要切割的张量。  这个函数有两种切割的方式: 以三个维度的张量为例,比如说一

数据时代的数字企业

1.写在前面 讨论数据治理在数字企业中的影响和必要性,并介绍数据治理的核心内容和实践方法。作者强调了数据质量、数据安全、数据隐私和数据合规等方面是数据治理的核心内容,并介绍了具体的实践措施和案例分析。企业需要重视这些方面以实现数字化转型和业务增长。 数字化转型行业小伙伴可以加入我的星球,初衷成为各位数字化转型参考库,星球内容每周更新 个人工作经验资料全部放在这里,包含数据治理、数据要

如何在Java中处理JSON数据?

如何在Java中处理JSON数据? 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨在Java中如何处理JSON数据。JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,在现代应用程序中被广泛使用。Java通过多种库和API提供了处理JSON的能力,我们将深入了解其用法和最佳

两个基因相关性CPTAC蛋白组数据

目录 蛋白数据下载 ①蛋白数据下载 1,TCGA-选择泛癌数据  2,TCGA-TCPA 3,CPTAC(非TCGA) ②蛋白相关性分析 1,数据整理 2,蛋白相关性分析 PCAS在线分析 蛋白数据下载 CPTAC蛋白组学数据库介绍及数据下载分析 – 王进的个人网站 (jingege.wang) ①蛋白数据下载 可以下载泛癌蛋白数据:UCSC Xena (xena

陀螺仪LSM6DSV16X与AI集成(8)----MotionFX库解析空间坐标

陀螺仪LSM6DSV16X与AI集成.8--MotionFX库解析空间坐标 概述视频教学样品申请源码下载开启CRC串口设置开启X-CUBE-MEMS1设置加速度和角速度量程速率选择设置FIFO速率设置FIFO时间戳批处理速率配置过滤链初始化定义MotionFX文件卡尔曼滤波算法主程序执行流程lsm6dsv16x_motion_fx_determin欧拉角简介演示 概述 本文将探讨

【文末附gpt升级秘笈】腾讯元宝AI搜索解析能力升级:千万字超长文处理的新里程碑

腾讯元宝AI搜索解析能力升级:千万字超长文处理的新里程碑 一、引言 随着人工智能技术的飞速发展,自然语言处理(NLP)和机器学习(ML)在各行各业的应用日益广泛。其中,AI搜索解析能力作为信息检索和知识抽取的核心技术,受到了广泛的关注和研究。腾讯作为互联网行业的领军企业,其在AI领域的探索和创新一直走在前列。近日,腾讯旗下的AI大模型应用——腾讯元宝,迎来了1.1.7版本的升级,新版本在AI搜