OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 167|回复: 0

《STM32H7R7开发指南 V1.1 》第七十二章 USB鼠标键盘(Host)实验

[复制链接]

1365

主题

1381

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5830
金钱
5830
注册时间
2019-5-8
在线时间
1606 小时
发表于 3 天前 | 显示全部楼层 |阅读模式
第七十二章 USB鼠标键盘(Host)实验

1)实验平台:正点原子STM32H7R7开发板

2)章节摘自【正点原子】STM32H7R7开发指南 V1.1

3)购买链接: https://detail.tmall.com/item.htm?id=820823382459

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32h7rx.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32开发板技术交流群:756580169


2.jpg

3.png

本章我们介绍如何使用STM32H7R7的USB HOST来驱动USB鼠标/键盘。
本章分为如下几个小节:
72.1 USB鼠标键盘简介
72.2 硬件设计
72.3 程序设计
72.4 下载验证


72.1 USB鼠标键盘简介
传统的鼠标和键盘是采用PS/2接口和电脑通信的,但是现在PS/2接口在电脑上逐渐消失,所以现在越来越多的鼠标键盘采用的是USB接口,而不是PS/2接口的了。
USB鼠标键盘属于USB HID设备。USB HID即:Human Interface Device(人机交互设备)的缩写,键盘、鼠标与游戏杆等都属于此类设备。不过HID设备并不一定要有人机接口,只要符合HID类别规范的设备都是HID设备。关于USB HID的知识,我们这里就不详细介绍了,请大家自行百度学习。
我们直接移植官方的USB HID例程,官方例程路径:8,STM32参考资料  1,STM32CubeH7RS固件包→STM32Cube_FW_H7RS_V1.0.0→Projects→STM32H7S78-DK→Applications→USB_Host→HID_RTOS,该例程支持USB鼠标和键盘等USB HID设备,本章我们将移植这个例程到我们的开发板上。


72.2 硬件设计

1. 例程功能
本实验代码,开机的时候先显示一些提示信息,然后初始化USB HOST,并不断轮询。当检测到USB鼠标/键盘的插入后,显示设备类型,并显示设备输入数据:
如果是USB鼠标:将显示鼠标移动的坐标(X,Y坐标)以及按键(左中右)。
如果是USB键盘:将显示键盘输入的数字/字母等内容(不是所有按键都支持,部分按键没有做解码支持,比如F1~F12)。

2. 硬件资源
1)LED灯
       LED0: LED0 – PD14
       LED1 :LED1 – PC0
2)串口1(PB14/PB15连接在板载USB转串口芯片CH340上面)
3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(包括MCU屏和RGB屏,都支持)
4)HyperRAM芯片
5)USB_HOST接口(D-/D+连接在PM5/PM6上)


72.3 程序设计

72.3.1 程序解析
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。
本实验,我们在上一个实验的基础上修改,对照官方HID例子,然后,我们在工程里面添加USB HID相关代码,由于官方提供的USB_APP文件不太好用,我们正点原子团队直接编写了一套USB_APP代码,读者可以直接拷贝我们例程中的USB_APP文件夹,即:实验61 USB鼠标键盘(Host)→实验Middlewares→USB→USB_APP。如图72.3.2.1所示:


第七十二章 USB鼠标键盘1186.png
图72.3.2.1 USB鼠标键盘工程分组

1. USB驱动代码
usbh_hid_mouse.h,首先介绍usbh_hid_mouse.h里面定义的一个结构体,具体如下:

  1. /* 鼠标信息结构体*/
  2. typedef struct _HID_MOUSE_Info
  3. {
  4.   uint8_t              x;           /* x轴增量(强制转换成signed char后使用)*/
  5.   uint8_t              y;           /* y轴增量(强制转换成signed char后使用)*/
  6.   uint8_t              buttons[3];  /* 将buttons修改为button,存储按键状态 */
  7. }
  8. HID_MOUSE_Info_TypeDef;
复制代码
HID_MOUSE_Info_TypeDef结构体中,成员x和y表示鼠标的横向/纵向移动的增量值,在使用的时候,需要强制转换成unsigned char类型后使用(有±)。button的bit0、bit1、bit2分别表示鼠标的:左键、右键和滚轮键的按下状态。我们通过这个结构体,就可以获得当前鼠标的输入状态。
usbh_hid_mouse.c,总共有三个函数,首先介绍的是USBH鼠标初始化函数,其定义如下:

  1. /* 鼠标信息(坐标+按钮状态)*/
  2. HID_MOUSE_Info_TypeDef    mouse_info;           
  3. /* 鼠标上报数据长度,最多USBH_HID_MOUSE_REPORT_SIZE个字节*/
  4. uint8_t   mouse_report_data[USBH_HID_MOUSE_REPORT_SIZE];
  5. uint8_t   mouse_rx_report_buf[USBH_HID_MOUSE_REPORT_SIZE];
  6.      

  7. /**
  8. * @brief       USBH 鼠标初始化
  9. * [url=home.php?mod=space&uid=271674]@param[/url]       phost       : USBH句柄指针
  10. * @retval      USB状态
  11. *   @arg       USBH_OK(0)   , 正常;
  12. *   @arg       USBH_BUSY(1) , 忙;
  13. *   @arg       其他         , 失败;
  14. */
  15. USBH_StatusTypeDef USBH_HID_MouseInit(USBH_HandleTypeDef *phost)
  16. {
  17.   uint32_t i;
  18.   HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *)
  19. phost->pActiveClass->pData;

  20.   mouse_info.x = 0U;
  21.   mouse_info.y = 0U;
  22.   mouse_info.buttons[0] = 0U;
  23.   mouse_info.buttons[1] = 0U;
  24.   mouse_info.buttons[2] = 0U;

  25.   for (i = 0U; i < sizeof(mouse_report_data); i++)
  26.   {
  27.     mouse_report_data[i] = 0U;
  28.     mouse_rx_report_buf[i] = 0U;
  29.   }

  30.   if (HID_Handle->length > sizeof(mouse_report_data))
  31.   {
  32.     HID_Handle->length = (uint16_t)sizeof(mouse_report_data);
  33.   }
  34.   HID_Handle->pData = mouse_rx_report_buf;

  35.   if ((HID_QUEUE_SIZE * sizeof(mouse_report_data)) > sizeof(phost->
  36. device.Data))
  37.   {
  38.     return USBH_FAIL;
  39.   }
  40.   else
  41.   {
  42.     USBH_HID_FifoInit(&HID_Handle->fifo, phost->device.Data, (uint16_t)(HID_QUEUE_SIZE * sizeof(mouse_report_data)));
  43.   }

  44.   return USBH_OK;
  45. }
复制代码
USBH_HID_MouseInit函数,用于初始化鼠标,指定USB鼠标输出数据的缓存,初始化FIFO等,该函数在USBH_HID_InterfaceInit函数里面被调用。
接下来介绍的是USBH获取鼠标信息函数,其定义如下:

  1. /**
  2. * @brief       USBH 获取鼠标信息
  3. * @param       phost       : USBH句柄指针
  4. * @retval      鼠标信息(HID_MOUSE_Info_TypeDef)
  5. */
  6. HID_MOUSE_Info_TypeDef *USBH_HID_GetMouseInfo(USBH_HandleTypeDef *phost)
  7. {
  8.     if (USBH_HID_MouseDecode(phost) == USBH_OK)
  9.     {
  10.         return &mouse_info;
  11.     }
  12.     else
  13.     {
  14.         return NULL;
  15.     }
  16. }
复制代码
USBH_HID_GetMouseInfo函数,用于获取鼠标信息,通过USBH_HID_MouseDecode函数获取当前鼠标传回来的数据。该函数在USB_Demo函数里面被调用。
最后介绍的是USBH 鼠标数据解析函数,其定义如下:

  1. /**
  2. * @brief       USBH 鼠标数据解析函数
  3. * @param       phost       : USBH句柄指针
  4. * @retval      USB状态
  5. *   @arg       USBH_OK(0)   , 正常;
  6. *   @arg       USBH_BUSY(1) , 忙;
  7. *   @arg       其他           , 失败;
  8. */
  9. static USBH_StatusTypeDef USBH_HID_MouseDecode(USBH_HandleTypeDef *phost)
  10. {
  11.   HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *)
  12. phost->pActiveClass->pData;

  13.   if ((HID_Handle->length == 0U) || (HID_Handle->fifo.buf == NULL))
  14.   {
  15.     return USBH_FAIL;
  16.   }
  17.   /*Fill report */
  18.   if (USBH_HID_FifoRead(&HID_Handle->fifo, &mouse_report_data, HID_Handle
  19. ->length) == HID_Handle->length)
  20.   {
  21.     /*Decode report */
  22. mouse_info.x = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_x,
  23. 0U);
  24. mouse_info.y = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *) &prop_y,
  25. 0U);

  26. mouse_info.buttons[0] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)
  27. &prop_b1, 0U);
  28. mouse_info.buttons[1] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)
  29. &prop_b2, 0U);
  30. mouse_info.buttons[2] = (uint8_t)HID_ReadItem((HID_Report_ItemTypedef *)
  31. &prop_b3, 0U);

  32.     return USBH_OK;
  33.   }
  34.   return   USBH_FAIL;
  35. }
复制代码
USBH_HID_MouseDecode函数,用于解析USB HOST获取到的USB鼠标数据,并存放到mouse_info结构体里面。该函数被USBH_HID_GetMouseInfo函数调用。

2. main.c代码
下面是main.c的程序,具体如下:

  1. int main(void)
  2. {
  3.     uint32_t t = 0;
  4.     HID_TypeTypeDef hid_type = HID_UNKNOWN;
  5.     HID_MOUSE_Info_TypeDef *hid_mouse_info_struct;
  6.     HID_KEYBD_Info_TypeDef *hid_keybd_info_struct;
  7.     int16_t mouse_x_abs;
  8.     int16_t mouse_y_abs;
  9.     uint8_t keyboard_ascii_code;
  10.    
  11.     sys_mpu_config();                   /* 配置MPU */
  12.     sys_cache_enable();                 /* 使能Cache */
  13.     HAL_Init();                         /* 初始化HAL库 */
  14.     sys_stm32_clock_init(300, 6, 2);    /* 配置时钟,600MHz */
  15.     delay_init(600);                    /* 初始化延时 */
  16.     usart_init(115200);                 /* 初始化串口 */
  17.     led_init();                         /* 初始化LED */
  18.     hyperram_init();                    /* 初始化HyperRAM */
  19.     lcd_init();                         /* 初始化LCD */
  20.     my_mem_init(SRAMIN);                /* 初始化AXI-SRAM1~4内存池 */
  21.     my_mem_init(SRAMEX);                /* 初始化XSPI2 HyperRAM内存池 */
  22.     my_mem_init(SRAM12);                /* 初始化AHB-SRAM1~2内存池 */
  23.     my_mem_init(SRAMDTCM);              /* 初始化DTCM内存池 */
  24.     my_mem_init(SRAMITCM);              /* 初始化ITCM内存池 */
  25.    
  26.     lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  27.     lcd_show_string(30, 70, 200, 16, 16, "USB Mouse/Keyboard TEST", RED);
  28.     lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
  29.    
  30.     USBH_Init(&g_usbh_handle, usbh_user_process, HOST_HS);
  31.     USBH_RegisterClass(&g_usbh_handle, USBH_HID_CLASS);
  32.     USBH_Start(&g_usbh_handle);
  33.    
  34.     while (1)
  35.     {
  36.         USBH_Process(&g_usbh_handle);
  37.         
  38.         switch (g_status)
  39.         {
  40.             case STA_IDLE:
  41.             {
  42.                 break;
  43.             }
  44.             case STA_READY:
  45.             {
  46.                 if (hid_type == HID_UNKNOWN)
  47.                 {
  48.                     hid_type = USBH_HID_GetDeviceType(&g_usbh_handle);
  49.                     if (hid_type == HID_MOUSE)
  50.                     {
  51.                         hid_mouse_info_struct = NULL;
  52.                         mouse_x_abs = 0;
  53.                         mouse_y_abs = 0;
  54.                         lcd_show_string(30, 110, 200, 16, 16, "Mouse", BLUE);
  55.                         lcd_show_string(30, 130, 200, 16, 16, "Button: Left
  56. Middle Right", BLUE);
  57.                         lcd_show_string(30, 150, 200, 16, 16, "X:   0", BLUE);
  58.                         lcd_show_string(30, 170, 200, 16, 16, "Y:   0", BLUE);
  59.                     }
  60.                     else if (hid_type == HID_KEYBOARD)
  61.                     {
  62.                         hid_keybd_info_struct = NULL;
  63.                         keyboard_ascii_code = 0;
  64.                         lcd_show_string(30, 110, 200, 16, 16, "Keyboard",BLUE);
  65.                         lcd_show_string(30, 130, 200, 16, 16, "ASCII:  ",BLUE);
  66.                         lcd_show_string(30, 150, 200, 16, 16, "ASCII Code:   ",
  67. BLUE);
  68.                     }
  69.                 }
  70.                 break;
  71.             }
  72.             case STA_DISCONNECT:
  73.             {
  74.                 g_status = STA_IDLE;
  75.                 hid_type = HID_UNKNOWN;
  76.                 lcd_fill(30, 110, 240, 186, WHITE);
  77.                 break;
  78.             }
  79.         }
  80.         
  81.         if (hid_type == HID_MOUSE)
  82.         {
  83.             hid_mouse_info_struct = USBH_HID_GetMouseInfo(&g_usbh_handle);
  84.             if (hid_mouse_info_struct != NULL)
  85.             {
  86.                 /* 处理鼠标左键数据 */
  87.                 if (hid_mouse_info_struct->buttons[0] != 0)
  88.                 {
  89.                     lcd_show_string(94, 130, 200, 16, 16, "Left", RED);
  90.                 }
  91.                 else
  92.                 {
  93.                     lcd_show_string(94, 130, 200, 16, 16, "Left", BLUE);
  94.                 }
  95.                
  96.                 /* 处理鼠标右键数据 */
  97.                 if (hid_mouse_info_struct->buttons[1] != 0)
  98.                 {
  99.                     lcd_show_string(190, 130, 200, 16, 16, "Right", RED);
  100.                 }
  101.                 else
  102.                 {
  103.                     lcd_show_string(190, 130, 200, 16, 16, "Right", BLUE);
  104.                 }
  105.                
  106.                 /* 处理鼠标中键数据 */
  107.                 if (hid_mouse_info_struct->buttons[2] != 0)
  108.                 {
  109.                     lcd_show_string(134, 130, 200, 16, 16, "Middle", RED);
  110.                 }
  111.                 else
  112.                 {
  113.                     lcd_show_string(134, 130, 200, 16, 16, "Middle", BLUE);
  114.                 }
  115.                
  116.                 /* 处理鼠标X轴移动数据 */
  117.                 mouse_x_abs += (int8_t)hid_mouse_info_struct->x;
  118.                 if (mouse_x_abs > 9999)
  119.                 {
  120.                     mouse_x_abs = 9999;
  121.                 }
  122.                 else if (mouse_x_abs < -9999)
  123.                 {
  124.                     mouse_x_abs = -9999;
  125.                 }
  126.                 if (mouse_x_abs < 0)
  127.                 {
  128.                     lcd_show_string(54, 150, 200, 16, 16, "-", BLUE);
  129.                     lcd_show_num(62, 150, -mouse_x_abs, 4, 16, BLUE);
  130.                 }
  131.                 else
  132.                 {
  133.                     lcd_show_string(54, 150, 200, 16, 16, " ", BLUE);
  134.                     lcd_show_num(62, 150, mouse_x_abs, 4, 16, BLUE);
  135.                 }
  136.                
  137.                 /* 处理鼠标Y轴移动数据 */
  138.                 mouse_y_abs += (int8_t)hid_mouse_info_struct->y;
  139.                 if (mouse_y_abs > 9999)
  140.                 {
  141.                     mouse_y_abs = 9999;
  142.                 }
  143.                 else if (mouse_y_abs < -9999)
  144.                 {
  145.                     mouse_y_abs = -9999;
  146.                 }
  147.                 if (mouse_y_abs < 0)
  148.                 {
  149.                     lcd_show_string(54, 170, 200, 16, 16, "-", BLUE);
  150.                     lcd_show_num(62, 170, -mouse_y_abs, 4, 16, BLUE);
  151.                 }
  152.                 else
  153.                 {
  154.                     lcd_show_string(54, 170, 200, 16, 16, " ", BLUE);
  155.                     lcd_show_num(62, 170, mouse_y_abs, 4, 16, BLUE);
  156.                 }
  157.             }
  158.         }
  159.         else if (hid_type == HID_KEYBOARD)
  160.         {
  161.             hid_keybd_info_struct = USBH_HID_GetKeybdInfo(&g_usbh_handle);
  162.             if (hid_keybd_info_struct != NULL)
  163.             {
  164.                 keyboard_ascii_code = USBH_HID_GetASCIICode
  165. (hid_keybd_info_struct);
  166.                 if (keyboard_ascii_code != 0)
  167.                 {
  168.                     /* 显示键盘输入字符 */
  169.                     lcd_show_char(86, 130, keyboard_ascii_code, 16, 0, BLUE);
  170.                     
  171.                     /* 显示键盘输入字符的ASCII码 */
  172.                     lcd_show_num(126, 150, keyboard_ascii_code, 2, 16, BLUE);
  173.                 }
  174.                 else
  175.                 {
  176.                     lcd_show_string(86, 130, 200, 16, 16, " ", BLUE);
  177.                     lcd_show_string(126, 150, 200, 16, 16, "  ", BLUE);
  178.                 }
  179.             }
  180.         }
  181.         
  182.         if (++t == 200000)
  183.         {
  184.             t = 0;
  185.             LED0_TOGGLE();
  186.         }
  187.         
  188.         delay_us(1);
  189.     }
  190. }
复制代码
main函数,初始化各个外设后,通过USBH_Init等3个函数初始化并启动USB主机通信,然后进入死循环,不停的调用USBH_Process,判断USB HOST枚举是否死机、处理连接状态、判断HID设备类型、以及执行各种USB处理,确定HID 设备后,通过调用USBH_HID_GetMouseInfo或者USBH_HID_GetKeybdInfo函数读取相应的设备数据,然后进行相应的处理,最后输出到屏幕中。

72.4 下载验证
将程序下载到开发板后,然后在USB_HOST端子插入USB鼠标/键盘,注意:此时USB SLAVE口不要插USB线到电脑,否则会干扰!
等USB鼠标/键盘成功识别后,便可以看到LCD显示USB Connected,并显示设备类型:USB Mouse或者USB KeyBoard,同时也会显示输入的数据,如图72.4.1和图72.4.2所示:


第七十二章 USB鼠标键盘12026.png
图72.4.1 USB鼠标测试

第七十二章 USB鼠标键盘12045.png
图72.4.2 USB键盘测试

其中,图72.4.1是USB鼠标测试界面,图72.4.2是USB键盘测试界面。
最后,特别提醒大家,由于例程的HID内核,只处理了第一个接口描述符,所以对于USB符合设备,只能识别第一个描述符所代表的设备。体现到实际使用中,就是:USB无线鼠标,一般是无法使用(被识别为键盘),而USB无线键盘,可以使用,因为键盘在第一个描述符,鼠标在第二个描述符。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-7-13 12:30

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表