CH585/CH584/CH582/CH592_全速USB口实现绝对鼠标
简单来说,绝对鼠标 是一种根据绝对坐标系 来定位光标的输入设备。
为了更好地理解,我们通常将其与日常使用的普通鼠标(即相对鼠标 )进行对比。
核心区别总结
- 绝对鼠标 :关心“你在哪里 ”。它直接告诉电脑:“把光标放在屏幕的(X, Y)坐标上。”
- 相对鼠标 :关心“你移动了多少 ”。它告诉电脑:“光标从当前位置向某个方向移动了ΔX和ΔY的距离。”
一、绝对鼠标报告描述符:
const uint8_t HIDMSDescr[] =
{
0x05,0x01, //0 GLOBAL_USAGE_PAGE(Generic Desktop Controls)
0x09,0x02, //2 LOCAL_USAGE(Mouse)
0xA1,0x01, //4 MAIN_COLLECTION(Applicatior)
0x09,0x01, //6 LOCAL_USAGE(Pointer)
0xA1,0x00, //8 MAIN_COLLECTION(Physical)
0x05,0x09, //12 GLOBAL_USAGE_PAGE(Button)
0x19,0x01, //14 LOCAL_USAGE_MINIMUM(1)
0x29,0x05, //16 LOCAL_USAGE_MAXIMUM(5)
0x15,0x00, //18 GLOBAL_LOGICAL_MINIMUM(0)
0x25,0x01, //20 GLOBAL_LOCAL_MAXIMUM(1)
0x95,0x05, //22 GLOBAL_REPORT_COUNT(5)
0x75,0x01, //24 GLOBAL_REPORT_SIZE(1)
0x81,0x02, //26 MAIN_INPUT(data var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 0.5
0x95,0x01, //28 GLOBAL_REPORT_COUNT(1)
0x75,0x03, //30 GLOBAL_REPORT_SIZE(3)
0x81,0x03, //32 MAIN_INPUT(const var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 1.0
0x05,0x01, //34 GLOBAL_USAGE_PAGE(Generic Desktop Controls)
0x09,0x30, //36 LOCAL_USAGE(X)
0x15,0x00, //38 GLOBAL_LOGICAL_MINIMUM(0)
0x26,0xFF,0x0F, //40 GLOBAL_LOCAL_MAXIMUM(4095/4095)
0x75,0x0D, //43 GLOBAL_REPORT_SIZE(13)
0x95,0x01, //45 GLOBAL_REPORT_COUNT(1)
0x81,0x02, //47 MAIN_INPUT(data var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 2.5
0x75,0x03, //49 GLOBAL_REPORT_SIZE(3)
0x95,0x01, //51 GLOBAL_REPORT_COUNT(1)
0x81,0x03, //53 MAIN_INPUT(const var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 3.0
0x09,0x31, //55 LOCAL_USAGE(Y)
0x15,0x00, //57 GLOBAL_LOGICAL_MINIMUM(0)
0x26,0xFF,0x0F, //59 GLOBAL_LOCAL_MAXIMUM(4095/4095)
0x75,0x0D, //62 GLOBAL_REPORT_SIZE(13)
0x95,0x01, //64 GLOBAL_REPORT_COUNT(1)
0x81,0x02, //66 MAIN_INPUT(data var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 4.5
0x75,0x03, //68 GLOBAL_REPORT_SIZE(3)
0x95,0x01, //70 GLOBAL_REPORT_COUNT(1)
0x81,0x03, //72 MAIN_INPUT(const var absolute NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 5.0
0x09,0x38, //74 LOCAL_USAGE(Wheel)
0x15,0x81, //76 GLOBAL_LOGICAL_MINIMUM(-127)
0x25,0x7F, //78 GLOBAL_LOCAL_MAXIMUM(127)
0x75,0x08, //80 GLOBAL_REPORT_SIZE(8)
0x95,0x01, //82 GLOBAL_REPORT_COUNT(1)
0x81,0x06, //84 MAIN_INPUT(data var relative NoWrap linear PreferredState NoNullPosition NonVolatile ) Input 6.0
0xC0, //86 MAIN_COLLECTION_END
0xC0, //87 MAIN_COLLECTION_END
};
二、报告描述符解析:
|
字节位置
|
位范围
|
功能说明
|
数值含义
|
|---|---|---|---|
|
字节0
|
位0-4
|
按钮状态
|
每个位对应一个按钮(0=未按下,1=按下)
位0: 按钮1(左键) |
|
位5-7
|
填充位
|
固定为0,用于数据对齐
|
|
|
字节1
|
位0-7
|
X坐标低字节
|
X轴坐标的低8位(0-255)
|
|
字节2
|
位0-4
|
X坐标高字节
|
X轴坐标的高5位(与字节1组合成13位)
|
|
位5-7
|
填充位
|
固定为0
|
|
|
字节3
|
位0-7
|
Y坐标低字节
|
Y轴坐标的低8位(0-255)
|
|
字节4
|
位0-4
|
Y坐标高字节
|
Y轴坐标的高5位(与字节3组合成13位)
|
|
位5-7
|
填充位
|
固定为0
|
|
|
字节5
|
位0-7
|
滚轮数据
|
相对滚轮值(-127到+127)
|
三、数据上传接口,示例程序将绝对鼠标写在接口1-端点2(接口0为键盘);需先查看自己电脑屏幕分辨率信息(见下图),此次测试电脑的屏幕分辨率为1920*1080;
/*********************************************************************
* @fn DevHIDMouseReport
*
* @brief 上报鼠标数据
*
* @return none
*/
uint8_t MouseStatus[ 6 ] = { 0x00 };
__HIGH_CODE
void DevHIDMouseReport(uint8_t button , uint16_t X , uint16_t Y , int8_t wheel)
{
uint16_t x_pix_val = 0;/* 绝对鼠标x坐标值 */
uint16_t y_pix_val = 0;/* 绝对鼠标y坐标值 */
x_pix_val = (X) * 4096/1920;//4096为绝对鼠标报告描述符中X轴分辨率最大值,1920为当前主机电脑的X分辨率
y_pix_val = (Y) * 4096/1080;//4096为绝对鼠标报告描述符中Y轴分辨率最大值,1080为当前主机电脑的X分辨率
MouseStatus[ 0 ] = button;
MouseStatus[ 1 ] = (uint8_t)x_pix_val;/* X_Val_l */
MouseStatus[ 2 ] = (uint8_t)(x_pix_val>>8);/* X_Val_h */
MouseStatus[ 3 ] = (uint8_t)y_pix_val;/* Y_Val_l */
MouseStatus[ 4 ] = (uint8_t)(y_pix_val>>8);/* Y_Val_h */
MouseStatus[ 5 ] = wheel;//-127 ~ 127
memcpy(pEP2_IN_DataBuf, MouseStatus, sizeof(MouseStatus));//拷贝到端点2DMA缓存中
DevEP2_IN_Deal(sizeof(MouseStatus));//端点2置ACK,等待主机来取数据
}

四、数据上报演示
/*********************************************************************
* @fn main
*
* @brief 主函数
*
* @return none
*/
int main()
{
HSECFG_Capacitance(HSECap_18p);
SetSysClock(SYSCLK_FREQ);
DebugInit();
PRINT("start\n");
pEP0_RAM_Addr = EP0_Databuf;
pEP1_RAM_Addr = EP1_Databuf;
pEP2_RAM_Addr = EP2_Databuf;
pEP3_RAM_Addr = EP3_Databuf;
USB_DeviceInit();
PFIC_EnableIRQ(USB_IRQn);
while(1)
{//模拟鼠标从(0,0)滑动到(648,648)
uint16_t Y_val=0;
for(uint16_t X_val = 0 ; X_val<=648;X_val+=16)
{
DevHIDMouseReport(0,X_val,Y_val,0);
Y_val += 16;
DelayMs(20);
}
DelayMs(20);
DevHIDMouseReport(0,0,0,-1);//鼠标滚轮向下移动一个单位
DelayMs(20);
DevHIDMouseReport(0,0,0, 1);//鼠标滚轮向上移动一个单位
DelayMs(1000);
}
}
工程链接如下,可自取:
通过网盘分享的文件:CH585_RelativeMouse.zip
链接: https://pan.baidu.com/s/1SABCVbsGZmorSG0z0w3U9w?pwd=g8ga 提取码: g8ga

浙公网安备 33010602011771号