CH585/CH584/CH582/CH592_全速USB口实现绝对鼠标

简单来说,绝对鼠标 是一种根据绝对坐标系 来定位光标的输入设备。

为了更好地理解,我们通常将其与日常使用的普通鼠标(即相对鼠标 )进行对比。

 
特性
绝对鼠标
相对鼠标 (我们日常用的鼠标)
定位原理
光标位置与设备所在的绝对坐标一一对应。
光标位置基于相对位移,即相对于上一次位置移动了多少。
工作方式
类似于触控屏或绘图板,屏幕上的每一个点都对应设备上的一个特定位置。
移动鼠标报告的是“方向”和“距离”,而不是一个固定的坐标点。
举例说明
当我们把绝对鼠标从A点拿起,放到B点,屏幕上的光标会瞬间从对应的A‘点跳到B’点。
当我们把鼠标从A点拿起,放到B点,屏幕上的光标不会动,因为它检测不到桌面上的移动。
常见设备
触摸屏、图形绘图板、一些专业领域的控制设备。
所有常见的台式机、笔记本电脑用的光电、激光鼠标。

核心区别总结

  • 绝对鼠标 :关心“你在哪里 ”。它直接告诉电脑:“把光标放在屏幕的(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(左键)
位1: 按钮2(右键)
位2: 按钮3(中键)
位3: 按钮4(侧键1)
位4: 按钮5(侧键2)

位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,等待主机来取数据
}

 

image

 

四、数据上报演示

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

posted @ 2026-01-30 12:58  oTvTo  阅读(6)  评论(0)    收藏  举报