发新帖本帖赏金 20.00元(功能说明)我要提问
返回列表
打印
[活动]

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

[复制链接]
951|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创# @21小跑堂  
7.基于官方USB例程和矩阵按键实现数字小键盘
上个帖子已经实现了对鼠标的模拟,接下来再做个键盘的,官方已经提供了一个键盘的例程,但是是针对MINI board的并且用的IO也与TINY board的不同,先以TINY board的鼠标例程为基础改一个针对TINY board的键盘例程出来
需要改动的地方不多,都在usbd_descriptor.c这个文件里,首先是USBD_HS_PID要改为1004

之后把USBD_HID_ITF_PORTOCOL_MOUSE换为USBD_HID_ITF_PORTOCOL_KEYBOARD,USBD_HID_MOUSE_REPORT_DESC_SIZE换为USBD_HID_KEYBOARD_REPORT_DESC_SIZE,这两个都有两处要替换,注意查找


之后将usbd_hid_keyboard.c加入工程并删掉原来的usbd_hid.c

最后将键盘消息处理函数复制过来替换掉原来鼠标的就行了,注意把里面的MINI替换成TINY
void USB_DevUserApplication(void)
{
    static uint8_t userAppState = USER_APP_INIT;
    static uint8_t interval = 0;
    static uint8_t report[8] = { 0 };
    static uint8_t i = 4;
   
    switch (userAppState)
    {
        case USER_APP_INIT:
            interval = USBD_HID_ReadInterval(&gUsbDeviceFS);

            report[0] = 0;
            report[1] = 0;
            report[2] = 0;
            report[3] = 0;
            userAppState = USER_APP_RUN;
            break;

        case USER_APP_RUN:
            if (!APM_TINY_PBGetState(BUTTON_KEY1))
            {
                APM_DelayMs(10);
                if (!APM_TINY_PBGetState(BUTTON_KEY1))
                {
                    if(i > 29)
                    {
                        i = 4;
                        report[2] = KEYBOARD_ENTER;
                        USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                        APM_DelayMs(20);
                        report[2] = 0;
                        USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                        APM_DelayMs(20);
                    }
                    
                    report[2] = i;
                    USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                    
                    APM_DelayMs(20);
                    
                    report[2] = 0;
                    USBD_HID_TxReport(&gUsbDeviceFS, (uint8_t*)report, 8);
                    
                    i++;
                    
                    while(!APM_TINY_PBGetState(BUTTON_KEY1));
                }
            }

            APM_DelayMs(interval);
            break;
    }
}

实现效果

再来实现一下矩阵按键的驱动
矩阵按键和普通按键不一样,不是一个IO对应一个按键,我用的这个是4行4列,在行线和列线的每个交叉点上设置一个按键,使用8个IO口来进行16个按键的控制读取

读取键值的方法:
先把行配置成上拉输入模式,列配置成输出模式并输出低电平,有按键按下的那一行IO输入为低电平
再把列配置成上拉输入模式,行配置成输出模式并输出低电平,有按键按下的那一列IO输入为低电平
当然上面的检测方法中你也可以输入配置成下拉输入,输出配置为推挽输出高电平,检测IO为高电平
通过行和列就能确定是哪个按键被按下了
代码实现

uint8_t lastkey = 0xFF;
void matrixkeyinit()
{
    GPIO_Config_T GPIO_InitStructure;
    RCM_EnableAHB1PeriphClock (RCM_AHB1_PERIPH_GPIOD);
    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;
    GPIO_InitStructure.speed = GPIO_SPEED_100MHz;
    GPIO_InitStructure.mode = GPIO_MODE_OUT;
    GPIO_InitStructure.otype = GPIO_OTYPE_OD;
    GPIO_InitStructure.pupd = GPIO_PUPD_UP;
    GPIO_Config(GPIOD, &GPIO_InitStructure);
}
uint8_t readmatrixkey()
{
    uint8_t col = 0,row = 0,i,j;
    GPIOD->MODE &= 0xFFFF0000;
    GPIOD->MODE |= 0x00005500;
    GPIOD->ODATA &= 0xFF0F;
    APM_DelayUs(50);
    row = GPIOD->IDATA;
    GPIOD->ODATA |= 0x00F0;
    GPIOD->MODE &= 0xFFFF0000;
    GPIOD->MODE |= 0x00000055;
    GPIOD->ODATA &= 0xFFF0;
    APM_DelayUs(50);
    col = GPIOD->IDATA >> 4;
    GPIOD->ODATA |= 0x000F;
    for(i = 0;i<4;i++)
    {
        if(!(row & 0x01))
            break;
        row >>= 1;
    }
    for(j = 0;j<4;j++)
    {
        if(!(col & 0x01))
            break;
        col >>= 1;
    }
    if(i == 4 || j == 4)
        return 0xFF;
    return i*4+j;
}
串口打印一下键值

得到键值分布图

接下来做个这样的小键盘

代码实现

void USB_DevUserApplication(void)
{
    static uint8_t userAppState = USER_APP_INIT;
    static uint8_t interval = 0;
    static uint8_t report[8] = { 0 };
    static uint8_t i = 4;
    uint8_t key;
   
    switch (userAppState)
    {
        case USER_APP_INIT:
            interval = USBD_HID_ReadInterval(&gUsbDeviceHS);

            report[0] = 0;
            report[1] = 0;
            report[2] = 0;
            report[3] = 0;
            userAppState = USER_APP_RUN;
            break;

        case USER_APP_RUN:
            key = readmatrixkey();
            report[0] = 0;
            if(key != lastkey)
            {
                switch(key)
                {
                    case 0:
                        report[2] = KEYBOARD_1_EXCLAMATION;
                        break;
                    case 1:
                        report[2] = KEYBOARD_2_AT;
                        break;
                    case 2:
                        report[2] = KEYBOARD_3_NUMBER_SIGN;
                        break;
                    case 3:
                        report[0] = 0x01;
                        report[2] = KEYBOARD_C;
                        break;
                    case 4:
                        report[2] = KEYBOARD_4_DOLLAR;
                        break;
                    case 5:
                        report[2] = KEYBOARD_5_PERCENT;
                        break;
                    case 6:
                        report[2] = KEYBOARD_6_CARET;
                        break;
                    case 7:
                        report[0] = 0x01;
                        report[2] = KEYBOARD_V;
                        break;
                    case 8:
                        report[2] = KEYBOARD_7_AMPERSAND;
                        break;
                    case 9:
                        report[2] = KEYBOARD_8_ASTERISK;
                        break;
                    case 10:
                        report[2] = KEYBOARD_9_OPARENTHESIS;
                        break;
                    case 11:
                        report[2] = KEYBOARD_ENTER;
                        break;
                    case 12:
                        report[0] = 0x02;
                        report[2] = KEYBOARD_8_ASTERISK;
                        break;
                    case 13:
                        report[2] = KEYBOARD_10_CPARENTHESIS;
                        break;
                    case 14:
                        report[0] = 0x02;
                        report[2] = KEYBOARD_3_NUMBER_SIGN;
                        break;
                    case 15:
                        report[2] = KEYBOARD_DOT_GREATER;
                        break;
                    default:
                        report[2] = 0;
                        break;
                }
                USBD_HID_TxReport(&gUsbDeviceHS, (uint8_t*)report, 8);
            }
            lastkey = key;
            APM_DelayMs(interval);
            break;
    }
}
效果展示
数字符号输入

复制粘贴快捷键


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

使用特权

评论回复

打赏榜单

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 | 只看该作者
现在常用的按键有没有通过串口来实现的呢

使用特权

评论回复
5
drer| | 2023-8-7 11:41 | 只看该作者
每个按键都可以通过程序开确定其功能是吧

使用特权

评论回复
6
wiba| | 2023-8-7 12:15 | 只看该作者
数字小键盘可以实现一些复杂的按键功能吗

使用特权

评论回复
7
kxsi| | 2023-8-7 20:59 | 只看该作者
如果烧写官方例程之后还不能正常识别usb的话  如何查找问题呢

使用特权

评论回复
8
coshi| | 2023-8-7 21:32 | 只看该作者
像这种类型的代码他们的分支都比较多 ,可以想办法做成模块吗

使用特权

评论回复
9
yuyy1989|  楼主 | 2023-8-8 13:28 | 只看该作者
kxsi 发表于 2023-8-7 20:59
如果烧写官方例程之后还不能正常识别usb的话  如何查找问题呢

官方的例程不是针对这个板子的吧,IO好像不一样

使用特权

评论回复
发新帖 本帖赏金 20.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

504

帖子

4

粉丝