打印
[STM32]

2. 按键模板

[复制链接]
908|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jpy313|  楼主 | 2017-5-18 14:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*
**************************************************************************************************
*                                                                    深圳新元电子工作室
*                          
* 文    件:stm32_key.h 模板
* 描    述:1.按键消抖
*           2.按键按下键码
*           3.按键弹起键码
*           4.按键长按键码
*           5.复合按键
*           
* 版    本:V0.0
* 实验平台: 野火 iSO STM32 开发板
* 备    注:通过修改“移植修改区” 适合开发用 方便移植
* 编    辑:雨海
* 日    期:2017-03-15
***************************************************************************************************
*/

#ifndef _STM32_KEY_H
#define _STM32_KEY_H
#include "stm32f10x.h"


/*移植可修改区=======================================================*/

#define KEY_ActiveLevel  0    /* 0:低电平按键执行 1:高电平按键执行*/
#define KEY_NUM          2          /* 按键个数  */

/*按键接口定义 */
#define KEY_Pin_1        GPIO_Pin_0   
#define KEY_Port_1       GPIOA
#define KEY_CLK_1        RCC_APB2Periph_GPIOA

#define KEY_Pin_2        GPIO_Pin_13   
#define KEY_Port_2       GPIOC
#define KEY_CLK_2        RCC_APB2Periph_GPIOC


/* 按键名字ID */
typedef enum
{
        KID_1 = 0,
        KID_2,
} KEY_ID;


/*定义键值代码, 必须按如下次序定时每个键的按下、弹起和长按事件*/
typedef enum
{
        KEY_NONE = 0,                        /* 0 表示按键事件 */

        KEY_1_DOWN,                               
        KEY_1_UP,                               
        KEY_1_LONG,                       
       
        KEY_2_DOWN,                               
        KEY_2_UP,                               
        KEY_2_LONG,                               

       
} KEY_ENUM;






/*移植禁止修改区=======================================================*/
/*
        按键滤波时间50ms, 单位10ms。
        只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件
        即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件
*/
#define KEY_FILTER_TIME   5       /*按键滤波时间 单位10MS */
#define KEY_LONG_TIME     100                        /* 单位10ms, 持续1秒,认为长按事件 */
#define KEY_FIFO_SIZE            6      /* 按键FIFO用到变量 */


/*每个按键属性对应1个全局的结构体变量*/
typedef struct
{
        uint8_t (*IsKeyDownFunc)(KEY_ID);            /* 函数指针,指向判断按键手否按下的函数,1表示按下 */
        uint8_t  FilterCount;                                           /* 滤波器计数器 */
        uint16_t LongFilterCount;                                 /* 长按计数器 */
        uint16_t LongTime;                                       /* 按键按下持续时间, 0表示不检测长按 */
        uint8_t  ButtonState;                                           /* 按键当前状态(按下还是弹起) */
        uint8_t  RepeatSpeed;                               /* 连续按键周期 */
        uint8_t  RepeatCount;                               /* 连续按键计数器 */
} KEY_typeDef;


/*按键缓冲*/
typedef struct
{
        uint8_t Buf[KEY_FIFO_SIZE];         /* 键值缓冲区    */
        uint8_t Read;                                                /* 缓冲区读指针 */
        uint8_t Write;                                              /* 缓冲区写指针  */
} KeyBuf_typeDef;


/*供外部调用的函数声明*/
void Key_Init(void);
void Key_Scan(void);//共节拍调用
void Key_Put(uint8_t _KeyCode);
uint8_t Key_Get(void);
uint8_t Key_State(KEY_ID _ucKeyID);
void Key_SetParam(uint8_t KeyID, uint16_t LongTime, uint8_t Speed);
void Key_Clear(void);


#endif

/***************************** END STM32_KEY.H*********************************/

/*
**************************************************************************************************
*                                                                    深圳新元电子工作室
*                          
* 文    件:stm32_key.c 模板
* 描    述:1.按键消抖
*           2.按键按下键码
*           3.按键弹起键码
*           4.按键长按键码
*           5.复合按键
*           
* 版    本:V0.0
* 实验平台: 野火 iSO STM32 开发板
* 备    注:通过修改“移植修改区” 适合开发用 方便移植
* 编    辑:雨海
* 日    期:2017-03-15
***************************************************************************************************
*/


#include "stm32_key.h"


/*移植可修改区=======================================================*/
const uint16_t  KEY_Pin[KEY_NUM]  ={ KEY_Pin_1, KEY_Pin_2 };
GPIO_TypeDef*   KEY_Port[KEY_NUM] ={ KEY_Port_1,KEY_Port_2};
const uint32_t  KEY_CLK[KEY_NUM]  ={ KEY_CLK_1, KEY_CLK_2 };
       




/*移植禁止修改区=======================================================*/


static KEY_typeDef BUTTON[KEY_NUM];  //按键结构体类型的结构体变量
static KeyBuf_typeDef key;                       //FIFO变量定义       


/**
  * @brief  配置按键对应的GPIO
  * @param  None
  * @retval None
  */                                                                                                                                               
static void Key_IOConfig(void)
{
        uint8_t i=0;       
        GPIO_InitTypeDef GPIO_InitStructure;
        for(i=0;i<KEY_NUM;i++)
        {
                RCC_APB2PeriphClockCmd(KEY_CLK, ENABLE);       
                GPIO_InitStructure.GPIO_Pin = KEY_Pin;
                if(KEY_ActiveLevel==1)
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
                else
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
                GPIO_Init(KEY_Port, &GPIO_InitStructure);
        }
}

/**
  * @brief  判断按键是否按下
  * @param  keyName:按键名字
  * @retval 返回值1 表示按下,0表示未按下
  */
static uint8_t IsKeyDown(KEY_ID keyName)
{          
         if(KEY_ActiveLevel==1)
         {
                 if((KEY_Port[keyName]->IDR & KEY_Pin[keyName]) != 0)  
                        return 1;  else  return 0;
         }
         else
         {
                        if((KEY_Port[keyName]->IDR & KEY_Pin[keyName]) == 0)  
                        return 1;  else  return 0;
         }                               
         
}

/**
  * @brief  初始化按键
  * @param  None
  * @retval None
  */
void Key_Init(void)
{
        uint8_t i;
        /* 对按键FIFO读写指针清零 */
        key.Read = 0;
        key.Write = 0;

        Key_IOConfig();
       
        /* 给每个按键结构体成员变量赋一组缺省值 */
        for (i = 0; i < KEY_NUM; i++)
        {
                BUTTON.LongTime = KEY_LONG_TIME;                             /* 长按时间 0 表示不检测长按键事件 */
                BUTTON.FilterCount = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 */
                BUTTON.ButtonState = 0;                                                             /* 按键缺省状态,0为未按下 */
          BUTTON.RepeatSpeed = 0;                                                       /* 按键连发的速度,0表示不支持连发 */
                BUTTON.RepeatCount = 0;                                                       /* 连发计数器 */
                BUTTON.IsKeyDownFunc = IsKeyDown;         /* 判断按键按下的函数 */
        }                          
}


/**
  * @brief  将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
  * @param  KeyCode : 按键代码
  * @retval None
  */
void Key_Put(uint8_t _KeyCode)
{
        key.Buf[key.Write] = _KeyCode;

        if (++key.Write  >= KEY_FIFO_SIZE)
        {
                key.Write = 0;
        }
}


/**
  * @brief  从按键FIFO缓冲区读取一个键值。
  * @param  None
  * @retval 按键代码
  */
uint8_t Key_Get(void)
{
        uint8_t ret;

        if (key.Read == key.Write)
        {
                return KEY_NONE;
        }
        else
        {
                ret = key.Buf[key.Read];

                if (++key.Read >= KEY_FIFO_SIZE)
                {
                        key.Read = 0;
                }
                return ret;
        }
}


/**
  * @brief  读取按键的状态
  * @param  _ucKeyID : 按键ID,从0开始
  * @retval 1 表示按下, 0 表示未按下
  */
uint8_t Key_GetButtonState(KEY_ID KeyID)
{
        return BUTTON[KeyID].ButtonState;
}


/**
  * @brief  设置按键参数
  * @param  _ucKeyID : 按键ID,从0开始
  *                               _LongTime : 长按事件时间
  *                              _RepeatSpeed : 连发速度
  * @retval None
  */
void Key_SetParam(uint8_t KeyID, uint16_t LongTime, uint8_t  RepeatSpeed)
{
        BUTTON[KeyID].LongTime = LongTime;                        /* 长按时间 0 表示不检测长按键事件 */
        BUTTON[KeyID].RepeatSpeed = RepeatSpeed;                        /* 按键连发的速度,0表示不支持连发 */
        BUTTON[KeyID].RepeatCount = 0;                                                /* 连发计数器 */
}


/**
  * @brief  清空按键FIFO缓冲区
  * @param  None
  * @retval None
  */
void Key_Clear(void)
{
        key.Read = key.Write;
}


/**
  * @brief  检测一个按键。非阻塞状态,必须被周期性的调用。
  * @param  按键结构变量指针
  * @retval None
  */
static void Key_Detect(uint8_t i) //10MS执行一次
{
        KEY_typeDef *pBtn;
        /*
                如果没有初始化按键函数,则报错
                if (BUTTON.IsKeyDownFunc == 0)
                {
                        printf("Fault : DetectButton(), BUTTON.IsKeyDownFunc undefine");
                }
        */
        pBtn = &BUTTON;
        if (pBtn->IsKeyDownFunc((KEY_ID)i))//判断i按键是否按下
        {
                if (pBtn->FilterCount < KEY_FILTER_TIME)
                {
                        pBtn->FilterCount = KEY_FILTER_TIME;
                }
                else if(pBtn->FilterCount < 2 * KEY_FILTER_TIME)
                {
                        pBtn->FilterCount++;//10ms自加
                }
                else
                {
                        if (pBtn->ButtonState == 0)
                        {
                                pBtn->ButtonState = 1;

                                /* 发送按钮按下的消息 */
                                Key_Put((uint8_t)(3 * i + 1));
                        }

                        if (pBtn->LongTime > 0)
                        {
                                if (pBtn->LongFilterCount < pBtn->LongTime)
                                {
                                        /* 发送按钮持续按下的消息 */
                                        if (++pBtn->LongFilterCount == pBtn->LongTime)
                                        {
                                                /* 键值放入按键FIFO */
                                                Key_Put((uint8_t)(3 * i + 3));
                                        }
                                }
                                else
                                {
                                        if (pBtn->RepeatSpeed > 0)
                                        {
                                                if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
                                                {
                                                        pBtn->RepeatCount = 0;
                                                        /* 常按键后,每隔10ms发送1个按键 */
                                                        Key_Put((uint8_t)(3 * i + 1));
                                                }
                                        }
                                }
                        }
                }
        }
        else
        {
                if(pBtn->FilterCount > KEY_FILTER_TIME)
                {
                        pBtn->FilterCount = KEY_FILTER_TIME;
                }
                else if(pBtn->FilterCount != 0)
                {
                        pBtn->FilterCount--;
                }
                else
                {
                        if (pBtn->ButtonState == 1)
                        {
                                pBtn->ButtonState = 0;

                                /* 发送按钮弹起的消息 */
                                Key_Put((uint8_t)(3 * i + 2));
                        }
                }

                pBtn->LongFilterCount = 0;
                pBtn->RepeatCount = 0;
        }
}


/**
  * @brief  扫描所有按键。非阻塞,被systick中断周期性的调用
  * @param  None
  * @retval None
  */
void Key_Scan(void)//10MS执行一次
{
        uint8_t i;
  static uint8_t s_count = 0;   //按键扫描定时计数器
       
        /*按键扫描检测程序段*/
        if (++s_count >= 10)
        {
                s_count = 0;
          for (i = 0; i < KEY_NUM; i++)
          {
                  Key_Detect(i);//10MS执行一次
          }
        }
}
       


/***************************** END STM32_KEY.C**********************************************************/               

void SysTick_Handler(void)
{       
        Key_Scan();       
}


相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

23

帖子

1

粉丝