矩阵按键 进行单击建识别 灵敏度0.5s

添加链接描述接着上篇文章,验证了矩阵键盘的识别,采用定时器加状态机进行判断 因为时间的关系,我没有调出来组合按键的识别,如有哪位大佬有新的想法,欢迎交流。

.c文件

/*


  • 模块名称 : 独立按键驱动模块
  • 文件名称 : bsp_key.c
  • 版 本 : V1.0
  • 说 明 :

*/

#include “bsp.h”

/* 按键的硬件接口及时钟 增加按键或者删除按键 需要对应增加或者删除 */
#define RCC_ALL_KEY (RCC_APB2Periph_GPIOC )

//矩阵的列 检测是否有按键按下
#define GPIO_Y_PORT_K1 GPIOC
#define GPIO_Y_PIN_K1 GPIO_Pin_4
#define GPIO_Y_PORT_K2 GPIOC
#define GPIO_Y_PIN_K2 GPIO_Pin_5
#define GPIO_Y_PORT_K3 GPIOC
#define GPIO_Y_PIN_K3 GPIO_Pin_6

//矩阵的行 输出高电平
#define GPIO_X_PORT_K1 GPIOC
#define GPIO_X_PIN_K1 GPIO_Pin_10
#define GPIO_X_PORT_K2 GPIOC
#define GPIO_X_PIN_K2 GPIO_Pin_11
#define GPIO_X_PORT_K3 GPIOC
#define GPIO_X_PIN_K3 GPIO_Pin_12

/*


  • 名 称:bsp_InitKey (void)
  • 功 能:初始化硬件接口
  • 入口参数:无
  • 出口参数:无
  • 调用方法:需要在调用处理函数之前进行
    增加按键或者删除按键 需要对应增加或者删除

*/
void bsp_InitKey(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* 第1步:打开GPIO时钟 */
RCC_APB2PeriphClockCmd(RCC_ALL_KEY, ENABLE);

/* 配置矩阵列的按键按键GPIO为浮动输入模式(实际上CPU复位后就是输入状态) */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD ; /* 下拉输入 */

GPIO_InitStructure.GPIO_Pin = GPIO_Y_PIN_K1;
GPIO_Init(GPIO_Y_PORT_K1, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Y_PIN_K2;
GPIO_Init(GPIO_Y_PORT_K2, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Y_PIN_K3;
GPIO_Init(GPIO_Y_PORT_K3, &GPIO_InitStructure);

/*配置矩阵行的按键按键GPIO为浮动输入模式(实际上CPU复位后就是输入状态) */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  /*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚模式为通用推挽输出*/

GPIO_InitStructure.GPIO_Pin = GPIO_X_PIN_K1;
GPIO_Init(GPIO_X_PORT_K1, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_X_PIN_K2;
GPIO_Init(GPIO_X_PORT_K2, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_X_PIN_K3;
GPIO_Init(GPIO_X_PORT_K3, &GPIO_InitStructure);

//并设置为输出为低电平
GPIO_ResetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
GPIO_ResetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
GPIO_ResetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);

}

/****************************************************************************

  • 名 称: GetKEY(void)

  • 功 能:取得按键GPIO的值

  • 入口参数:无

  • 出口参数:返回按键值

  • 说 明:如果读到低电平则说明有按键按下,不同的CPU只要更改if里面的读取方式即可

  • 调用方法:key_driver 函数调用 用于判断是否有按键按下
    增加按键或者删除按键 需要对应增加或者删除
    PRESS 是对有效电平的声明
    /
    uint8_t GetKEY(void)
    {
    if(GPIO_ReadInputDataBit(GPIO_Y_PORT_K1, GPIO_Y_PIN_K1) == PRESS) /
    读取按键 2 的状态 /
    {
    return KEY_Y_K1;//按键被按下 返回1
    }
    if(GPIO_ReadInputDataBit(GPIO_Y_PORT_K2, GPIO_Y_PIN_K2) == PRESS) /
    读取按键 2 的状态 /
    {
    return KEY_Y_K2;//按键被按下 返回2
    }
    if(GPIO_ReadInputDataBit(GPIO_Y_PORT_K3, GPIO_Y_PIN_K3) == PRESS) /
    读取按键 2 的状态 /
    {
    return KEY_Y_K3;//按键被按下 返回3
    }
    return KEY_NO_DOWN;
    }
    /

  • 名 称:char key_read(void)

  • 功 能:状态机检测按键

  • 入口参数:无

  • 出口参数:返回按键值

  • 调用方法:该函数是对 key_driver 函数的调用 实现矩阵键盘的识别 返回 0x00 表示无按键按下
    增加行数或者列数需要更改该函数相应的部分其余代码不需要更改
    ****************************************************************************/
    unsigned char key_read(void)
    {
    static unsigned char KeyState = 0; // 按键状态变量
    static uint16_t KeyTime = 0; // 按键状态变量
    static unsigned char KeyReturnValue = 0,KeyLaetgValue = 0;// 当前按键值 上一次扫描的键值
    unsigned char KeyValue;//当前按键键值

    KeyValue = key_driver(); // 读取当前键值的状态
    KeyTime ++ ;

    switch (KeyState)
    {
    case KEY_STATE_1: // 扫描第一行
    GPIO_ResetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
    GPIO_ResetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
    GPIO_ResetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);
    GPIO_SetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
    KeyState = KEY_STATE_2;
    break;

    case KEY_STATE_2: // 扫描第二行
    GPIO_ResetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
    GPIO_ResetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
    GPIO_ResetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);
    GPIO_SetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
    KeyState = KEY_STATE_3;
    break;

    case KEY_STATE_3: // 扫描第三行
    GPIO_ResetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
    GPIO_ResetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
    GPIO_ResetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);
    GPIO_SetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);
    KeyState = KEY_STATE_1;
    break;

    default:// 特殊情况:这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    GPIO_ResetBits(GPIO_X_PORT_K1,GPIO_X_PIN_K1);
    GPIO_ResetBits(GPIO_X_PORT_K2,GPIO_X_PIN_K2);
    GPIO_ResetBits(GPIO_X_PORT_K3,GPIO_X_PIN_K3);
    KeyState = KEY_STATE_1;
    break;
    }

    switch (KeyState)
    {
    case KEY_STATE_1: //扫描第一列 识别 按键 1 2 3
    if( ( KeyValue != KEY_NO_DOWN ) /* & ( KeyTime >= 20 ) */ ) //判断是否有按键按下 有按键按下 KeyValue 的值不为 0
    {
    switch( KeyValue )
    {
    case Key1_S :
    KeyReturnValue = 0x01;
    break;
    case Key2_S :
    KeyReturnValue = 0x02;
    break;
    case Key3_S :
    KeyReturnValue = 0x03;
    break;
    default:
    KeyReturnValue = 0x00;
    break;
    }
    }
    break;

    case KEY_STATE_2://扫描第二列 识别 按键 4 5 6
    if( ( KeyValue != KEY_NO_DOWN ) /* & ( KeyTime >= 20 ) */ ) //判断是否有按键按下 有按键按下 KeyValue 的值不为 0
    {
    switch( KeyValue )
    {
    case Key1_S :
    KeyReturnValue = 0x04;
    break;
    case Key2_S :
    KeyReturnValue = 0x05;
    break;
    case Key3_S :
    KeyReturnValue = 0x06;
    break;
    default:
    KeyReturnValue = 0x00;
    break;
    }
    }
    break;

    case KEY_STATE_3://扫描第三列 识别 按键 7 8 9
    if( ( KeyValue != KEY_NO_DOWN ) /* & ( KeyTime >= 20 ) */ ) //判断是否有按键按下 有按键按下 KeyValue 的值不为 0
    {
    switch( KeyValue )
    {
    case Key1_S :
    KeyReturnValue = 0x07;
    break;
    case Key2_S :
    KeyReturnValue = 0x08;
    break;
    case Key3_S :
    KeyReturnValue = 0x09;
    break;
    default:
    KeyReturnValue = 0x00;
    break;
    }
    }
    break;
    }

    if( KeyTime >= KEY_TIME ) //按键按下后,没有做按键松开检测 通过其他方法实现按键松开检测
    {
    KeyTime = 0;
    KeyReturnValue = KeyLaetgValue = 0;
    }

    if (KeyLaetgValue != KeyReturnValue) //按键按下后,没有做按键松开检测 通过其他方法实现按键松开检测
    {
    KeyLaetgValue = KeyReturnValue;//保存键值
    return KeyLaetgValue; // 返回 按键值
    }
    else
    {
    return 0x00;
    }

}

/****************************************************************************

  • 名 称:unsigned char key_driver(void)

  • 功 能:状态机检测按键

  • 入口参数:无

  • 出口参数:返回按键值

  • 调用方法:该函数实现按键的单击按键按下的检测
    添加或者删除独立按键不需要更改此处
    ****************************************************************************/
    unsigned char key_driver(void)
    {
    static unsigned char key_state = 0; // 按键状态变量
    static unsigned int key_time = 0; // 按键计时变量
    static unsigned char Key_LaetgValue = 0;//上一次扫描的键值
    unsigned char Key_LaetPress,key_press, key_return;//当前按键键值

    key_return = N_KEY; // 清除 返回按键值

    Key_LaetPress = key_press = GetKEY(); // 读取当前键值

    if( Key_LaetPress ) //保存按键的的键值只在非 0 的状态才改变其按键值
    {
    Key_LaetgValue = key_press;
    }

    switch (key_state)
    {
    case KEY_STATE_A: // 按键状态A:判断有无按键按下
    if ( ( key_press != 0 ) & (key_press == Key_LaetPress) ) // 有按键按下
    {
    key_time = 0; // 清零时间间隔计数
    key_state = KEY_STATE_B; // 然后进入 按键状态B
    }
    break;

    case KEY_STATE_B: // 按键状态B:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
    if (key_press == Key_LaetPress)
    {
    key_time++; // 一次10ms
    if(key_time>=SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms;
    {
    key_state = KEY_STATE_C; // 如果按键时间超过 消抖时间,即判定为按下的按键有效.
    }
    }
    else
    {
    key_state = KEY_STATE_A; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
    }
    break;

    case KEY_STATE_C: // 按键状态C:是单击
    if( key_press == 0 ) // 如果按键在 设定的长按时间 内释放,则判定为单击
    {
    key_return = (Key_LaetgValue | KEY_STATE_C ); // 返回 有效按键值:单击
    key_state = KEY_STATE_A; // 返回 按键状态A,继续等待按键
    }
    break;

    case KEY_STATE_F: // 按键状态C:按键释放
    if ( key_press == 0 )
    {
    key_state = KEY_STATE_A; // 按键释放后,进入 按键状态A ,进行下一次按键的判定
    }
    break;

    default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
    key_state = KEY_STATE_A;
    break;
    }

    return key_return; // 返回 按键值
    }

.h文件

/*


  • 模块名称 : 按键驱动模块
  • 文件名称 : bsp_key.h
  • 版 本 : V1.0
  • 说 明 : 头文件
  • Copyright ©, 2013-2014, 安富莱电子 www.armfly.com

*/

#ifndef __BSP_KEY_H
#define __BSP_KEY_H

#include “stm32f10x.h” // Device header

//按键状态
#define KEY_STATE_A 0xA0 // 无
#define KEY_STATE_B 0xB0 // 软件消抖
#define KEY_STATE_C 0xC0 // 单击
#define KEY_STATE_E 0xE0 // 长按
#define KEY_STATE_F 0xF0 // 等待按键释放

//状态机的状态切换标志 用于解决只能识别一行的问题
#define KEY_STATE_1 0x01 // 第一行
#define KEY_STATE_2 0x02 // 第二行
#define KEY_STATE_3 0x03 // 第三行

//用于识别按键的状态 用它与按键的状态相与即可区分
#define STATE 0xF0 // 等待按键释放
#define VALUE 0x0F // 存放按键值

//用于识别按键按下的状态识别
#define PRESS !RESET //高电平识别

//按键时间调整
#define SINGLE_KEY_TIME 3 // 消抖时间为 SINGLE_KEY_TIME10MS
#define KEY_TIME 50 /
两次单击间隔时间 KEY_TIME10MS 改变这个数值可以增加按键的灵敏度 数值越小 灵敏度越高 不建议更改这个数值 否则可能会引起 不能识别单击/
#define LONG_KEY_TIME 50 // 长按时间 LONG_KEY_TIME*10MS

// 按键值 增加按键或者删除按键 需要对应增加或者删除
#define KEY_NO_DOWN 0x00 //无按键按下
#define KEY_Y_K1 0x01 // 第一个按键按下
#define KEY_Y_K2 0x02 // 第二个按键按下
#define KEY_Y_K3 0x03 // 第三个按键按下

//按键返回值 增加按键或者删除按键 需要对应增加或者删除
#define N_KEY 0x00 // no click
#define Key1_S (KEY_STATE_C | KEY_Y_K1 ) // single click
#define Key2_S (KEY_STATE_C | KEY_Y_K2 ) // single click
#define Key3_S (KEY_STATE_C | KEY_Y_K3 ) // single click

/* 供外部调用的函数声明 */
void bsp_InitKey(void); //初始化硬件连接
unsigned char key_driver(void); //按键底层识别函数 可以识别按键单击 长按
unsigned char key_read(void); //在底层按键的基础上增加识别双击 可以根据需要添加多击

#endif
完整工程

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值