返回列表 发新帖我要提问本帖赏金: 20.00元(功能说明)

[活动] 【极海APM32F407IG Tiny Board开发板测评】7.基于官方USB例程和矩阵按键实现数字小键盘

[复制链接]
1798|9
 楼主| yuyy1989 发表于 2023-7-12 11:26 | 显示全部楼层 |阅读模式
#申请原创# @21小跑堂  
7.基于官方USB例程和矩阵按键实现数字小键盘
上个帖子已经实现了对鼠标的模拟,接下来再做个键盘的,官方已经提供了一个键盘的例程,但是是针对MINI board的并且用的IO也与TINY board的不同,先以TINY board的鼠标例程为基础改一个针对TINY board的键盘例程出来
需要改动的地方不多,都在usbd_descriptor.c这个文件里,首先是USBD_HS_PID要改为1004
QQ截图20230711105145.png
之后把USBD_HID_ITF_PORTOCOL_MOUSE换为USBD_HID_ITF_PORTOCOL_KEYBOARD,USBD_HID_MOUSE_REPORT_DESC_SIZE换为USBD_HID_KEYBOARD_REPORT_DESC_SIZE,这两个都有两处要替换,注意查找
QQ截图20230711105512.png
QQ截图20230711105620.png
之后将usbd_hid_keyboard.c加入工程并删掉原来的usbd_hid.c
QQ截图20230712081325.png
最后将键盘消息处理函数复制过来替换掉原来鼠标的就行了,注意把里面的MINI替换成TINY
  1. void USB_DevUserApplication(void)
  2. {
  3.     static uint8_t userAppState = USER_APP_INIT;
  4.     static uint8_t interval = 0;
  5.     static uint8_t report[8] = { 0 };
  6.     static uint8_t i = 4;
  7.    
  8.     switch (userAppState)
  9.     {
  10.         case USER_APP_INIT:
  11.             interval = USBD_HID_ReadInterval(&gUsbDeviceFS);

  12.             report[0] = 0;
  13.             report[1] = 0;
  14.             report[2] = 0;
  15.             report[3] = 0;
  16.             userAppState = USER_APP_RUN;
  17.             break;

  18.         case USER_APP_RUN:
  19.             if (!APM_TINY_PBGetState(BUTTON_KEY1))
  20.             {
  21.                 APM_DelayMs(10);
  22.                 if (!APM_TINY_PBGetState(BUTTON_KEY1))
  23.                 {
  24.                     if(i > 29)
  25.                     {
  26.                         i = 4;
  27.                         report[2] = KEYBOARD_ENTER;
  28.                         USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
  29.                         APM_DelayMs(20);
  30.                         report[2] = 0;
  31.                         USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
  32.                         APM_DelayMs(20);
  33.                     }
  34.                     
  35.                     report[2] = i;
  36.                     USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
  37.                     
  38.                     APM_DelayMs(20);
  39.                     
  40.                     report[2] = 0;
  41.                     USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
  42.                     
  43.                     i++;
  44.                     
  45.                     while(!APM_TINY_PBGetState(BUTTON_KEY1));
  46.                 }
  47.             }

  48.             APM_DelayMs(interval);
  49.             break;
  50.     }
  51. }

实现效果
WeChat_20230711111106 00_00_00-00_00_30.gif
再来实现一下矩阵按键的驱动
矩阵按键和普通按键不一样,不是一个IO对应一个按键,我用的这个是4行4列,在行线和列线的每个交叉点上设置一个按键,使用8个IO口来进行16个按键的控制读取
微信图片_20230711112111.jpg
读取键值的方法:
先把行配置成上拉输入模式,列配置成输出模式并输出低电平,有按键按下的那一行IO输入为低电平
再把列配置成上拉输入模式,行配置成输出模式并输出低电平,有按键按下的那一列IO输入为低电平
当然上面的检测方法中你也可以输入配置成下拉输入,输出配置为推挽输出高电平,检测IO为高电平
通过行和列就能确定是哪个按键被按下了
代码实现

  1. uint8_t lastkey = 0xFF;
  2. void matrixkeyinit()
  3. {
  4.     GPIO_Config_T GPIO_InitStructure;
  5.     RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOD);
  6.     GPIO_InitStructure.pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
  7.     GPIO_InitStructure.speed = GPIO_SPEED_100MHz;
  8.     GPIO_InitStructure.mode = GPIO_MODE_OUT;
  9.     GPIO_InitStructure.otype = GPIO_OTYPE_OD;
  10.     GPIO_InitStructure.pupd = GPIO_PUPD_UP;
  11.     GPIO_Config(GPIOD, &GPIO_InitStructure);
  12. }
  13. uint8_t readmatrixkey()
  14. {
  15.     uint8_t col = 0,row = 0,i,j;
  16.     GPIOD->MODE &= 0xFFFF0000;
  17.     GPIOD->MODE |= 0x00005500;
  18.     GPIOD->ODATA &= 0xFF0F;
  19.     APM_DelayUs(50);
  20.     row = GPIOD->IDATA;
  21.     GPIOD->ODATA |= 0x00F0;
  22.     GPIOD->MODE &= 0xFFFF0000;
  23.     GPIOD->MODE |= 0x00000055;
  24.     GPIOD->ODATA &= 0xFFF0;
  25.     APM_DelayUs(50);
  26.     col = GPIOD->IDATA >> 4;
  27.     GPIOD->ODATA |= 0x000F;
  28.     for(i = 0;i<4;i++)
  29.     {
  30.         if(!(row & 0x01))
  31.             break;
  32.         row >>= 1;
  33.     }
  34.     for(j = 0;j<4;j++)
  35.     {
  36.         if(!(col & 0x01))
  37.             break;
  38.         col >>= 1;
  39.     }
  40.     if(i == 4 || j == 4)
  41.         return 0xFF;
  42.     return i*4+j;
  43. }
串口打印一下键值
QQ截图20230711143440.png
得到键值分布图
QQ截图20230711143716.png
接下来做个这样的小键盘
QQ截图20230711145157.png
代码实现

  1. void USB_DevUserApplication(void)
  2. {
  3.     static uint8_t userAppState = USER_APP_INIT;
  4.     static uint8_t interval = 0;
  5.     static uint8_t report[8] = { 0 };
  6.     static uint8_t i = 4;
  7.     uint8_t key;
  8.    
  9.     switch (userAppState)
  10.     {
  11.         case USER_APP_INIT:
  12.             interval = USBD_HID_ReadInterval(&gUsbDeviceHS);

  13.             report[0] = 0;
  14.             report[1] = 0;
  15.             report[2] = 0;
  16.             report[3] = 0;
  17.             userAppState = USER_APP_RUN;
  18.             break;

  19.         case USER_APP_RUN:
  20.             key = readmatrixkey();
  21.             report[0] = 0;
  22.             if(key != lastkey)
  23.             {
  24.                 switch(key)
  25.                 {
  26.                     case 0:
  27.                         report[2] = KEYBOARD_1_EXCLAMATION;
  28.                         break;
  29.                     case 1:
  30.                         report[2] = KEYBOARD_2_AT;
  31.                         break;
  32.                     case 2:
  33.                         report[2] = KEYBOARD_3_NUMBER_SIGN;
  34.                         break;
  35.                     case 3:
  36.                         report[0] = 0x01;
  37.                         report[2] = KEYBOARD_C;
  38.                         break;
  39.                     case 4:
  40.                         report[2] = KEYBOARD_4_DOLLAR;
  41.                         break;
  42.                     case 5:
  43.                         report[2] = KEYBOARD_5_PERCENT;
  44.                         break;
  45.                     case 6:
  46.                         report[2] = KEYBOARD_6_CARET;
  47.                         break;
  48.                     case 7:
  49.                         report[0] = 0x01;
  50.                         report[2] = KEYBOARD_V;
  51.                         break;
  52.                     case 8:
  53.                         report[2] = KEYBOARD_7_AMPERSAND;
  54.                         break;
  55.                     case 9:
  56.                         report[2] = KEYBOARD_8_ASTERISK;
  57.                         break;
  58.                     case 10:
  59.                         report[2] = KEYBOARD_9_OPARENTHESIS;
  60.                         break;
  61.                     case 11:
  62.                         report[2] = KEYBOARD_ENTER;
  63.                         break;
  64.                     case 12:
  65.                         report[0] = 0x02;
  66.                         report[2] = KEYBOARD_8_ASTERISK;
  67.                         break;
  68.                     case 13:
  69.                         report[2] = KEYBOARD_10_CPARENTHESIS;
  70.                         break;
  71.                     case 14:
  72.                         report[0] = 0x02;
  73.                         report[2] = KEYBOARD_3_NUMBER_SIGN;
  74.                         break;
  75.                     case 15:
  76.                         report[2] = KEYBOARD_DOT_GREATER;
  77.                         break;
  78.                     default:
  79.                         report[2] = 0;
  80.                         break;
  81.                 }
  82.                 USBD_HID_TxReport(&gUsbDeviceHS, (uint8_t*)report, 8);
  83.             }
  84.             lastkey = key;
  85.             APM_DelayMs(interval);
  86.             break;
  87.     }
  88. }
效果展示
数字符号输入
WeChat_20230711150820 00_00_00-00_00_30.gif
复制粘贴快捷键

WeChat_20230711150827 00_00_00-00_00_30.gif
上面这个例程里只能识别一个按键的按下,如何识别多个按键这里暂时先不展开了,有兴趣的可以自己尝试下

打赏榜单

Gfan 打赏了 20.00 元 2023-08-17
理由:APM32F407IG Tiny Board精选测评

guijial511 发表于 2023-7-12 19:23 来自手机 | 显示全部楼层
这个操作牛的一批
tpgf 发表于 2023-8-7 09:36 | 显示全部楼层
这种矩形按键需要各个io口的状态关系才可以判定是吧
qcliu 发表于 2023-8-7 10:15 | 显示全部楼层
现在常用的按键有没有通过串口来实现的呢
drer 发表于 2023-8-7 11:41 | 显示全部楼层
每个按键都可以通过程序开确定其功能是吧
wiba 发表于 2023-8-7 12:15 | 显示全部楼层
数字小键盘可以实现一些复杂的按键功能吗
kxsi 发表于 2023-8-7 20:59 | 显示全部楼层
如果烧写官方例程之后还不能正常识别usb的话  如何查找问题呢
coshi 发表于 2023-8-7 21:32 | 显示全部楼层
像这种类型的代码他们的分支都比较多 ,可以想办法做成模块吗
 楼主| yuyy1989 发表于 2023-8-8 13:28 | 显示全部楼层
kxsi 发表于 2023-8-7 20:59
如果烧写官方例程之后还不能正常识别usb的话  如何查找问题呢

官方的例程不是针对这个板子的吧,IO好像不一样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

168

主题

826

帖子

10

粉丝
快速回复 在线客服 返回列表 返回顶部