按键FIFO操作

#include "key.h"

static u8  IsKeyDown1(void) {if((GPIOB->IDR &0X0200)==0) return 1;else return 0;}
static u8  IsKeyDown2(void) {if((GPIOB->IDR &0X0040)==0) return 1;else return 0;}
static u8  IsKeyDown3(void) {if((GPIOB->IDR &0x0100)==0) return 1;else return 0;}
static u8  IsKeyDown4(void) {if((GPIOA->IDR &0x0008)==0) return 1;else return 0;}
static u8  IsKeyDown5(void) {if((GPIOA->IDR &0x0020)==0) return 1;else return 0;}
static u8  IsKeyDown6(void) {if((GPIOB->IDR &0X0080)==0) return 1;else return 0;}
static u8  IsKeyDown7(void) {if((GPIOA->IDR &0X0010)==0) return 1;else return 0;}
static u8  IsKeyDown8(void) {if(IsKeyDown4()&& IsKeyDown5())return 1; else return 0;}

static KEY_T s_tBtn[KEY_COUNT];
static KEY_FIFO_T s_tKey; /* 按键FIFO变量,结构体 */

/*

*********************************************************************************************************
* 函 数 名: bsp_PutKey
* 功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
* 形    参:  _KeyCode : 按键代码
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_PutKey(u8 _KeyCode)
{
s_tKey.Buf[s_tKey.Write] = _KeyCode;

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

}

/*
*********************************************************************************************************
* 函 数 名: bsp_GetKey
* 功能说明: 从按键FIFO缓冲区读取一个键值。
* 形    参:  无
* 返 回 值: 按键代码
*********************************************************************************************************
*/
u8 bsp_GetKey(void)
{
u8 ret;

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

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

}

/*
*********************************************************************************************************
* 函 数 名: bsp_GetKeyState
* 功能说明: 读取按键的状态
* 形    参:  _ucKeyID : 按键ID,从0开始
* 返 回 值: 1 表示按下, 0 表示未按下
*********************************************************************************************************
*/
u8 bsp_GetKeyState(KEY_ID_E _ucKeyID)
{
return s_tBtn[_ucKeyID].State;

}

/*
*********************************************************************************************************
* 函 数 名: bsp_SetKeyParam
* 功能说明: 设置按键参数
* 形    参:_ucKeyID : 按键ID,从0开始
* _LongTime : 长按事件时间
* _RepeatSpeed : 连发速度
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetKeyParam(u8 _ucKeyID, u16 _LongTime, u8  _RepeatSpeed)
{
s_tBtn[_ucKeyID].LongTime = _LongTime; /* 长按时间 0 表示不检测长按键事件 */
s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed; /* 按键连发的速度,0表示不支持连发 */
s_tBtn[_ucKeyID].RepeatCount = 0; /* 连发计数器 */

}

/*
*********************************************************************************************************
* 函 数 名: bsp_ClearKey
* 功能说明: 清空按键FIFO缓冲区
* 形    参:无
* 返 回 值: 按键代码
*********************************************************************************************************
*/
void bsp_ClearKey(void)
{
s_tKey.Read = s_tKey.Write;

}

/*
*********************************************************************************************************
* 函 数 名: bsp_InitKeyVar
* 功能说明: 初始化按键变量
* 形    参:  无
* 返 回 值: 无
*********************************************************************************************************
*/
static void bsp_InitKeyVar(void)
{
u8 i;

/* 对按键FIFO读写指针清零 */
s_tKey.Read = 0;
s_tKey.Write = 0;

/* 给每个按键结构体成员变量赋一组缺省值 */
for (i = 0; i < KEY_COUNT; i++)
{
s_tBtn[i].LongTime = KEY_LONG_TIME; /* 长按时间 0 表示不检测长按键事件 */
s_tBtn[i].Count = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 */
s_tBtn[i].State = 0; /* 按键缺省状态,0为未按下 */
//s_tBtn[i].KeyCodeDown = 3 * i + 1; /* 按键按下的键值代码 */
//s_tBtn[i].KeyCodeUp   = 3 * i + 2; /* 按键弹起的键值代码 */
//s_tBtn[i].KeyCodeLong = 3 * i + 3; /* 按键被持续按下的键值代码 */
s_tBtn[i].RepeatSpeed = 0; /* 按键连发的速度,0表示不支持连发 */
s_tBtn[i].RepeatCount = 0; /* 连发计数器 */
}

/* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */
/* 比如,我们希望按键1按下超过1秒后,自动重发相同键值 */
// s_tBtn[KID_K6].LongTime = 100;
// s_tBtn[KID_K6].RepeatSpeed = 5; /* 每隔50ms自动发送键值 */
s_tBtn[3].LongTime = 50;
s_tBtn[4].LongTime = 50;
s_tBtn[3].RepeatSpeed = 14;
s_tBtn[4].RepeatSpeed = 14;


/* 判断按键按下的函数 */
s_tBtn[0].IsKeyDownFunc = IsKeyDown1;
s_tBtn[1].IsKeyDownFunc = IsKeyDown2;
s_tBtn[2].IsKeyDownFunc = IsKeyDown3;
s_tBtn[3].IsKeyDownFunc = IsKeyDown4;
s_tBtn[4].IsKeyDownFunc = IsKeyDown5;
s_tBtn[5].IsKeyDownFunc = IsKeyDown6;
s_tBtn[6].IsKeyDownFunc = IsKeyDown7;
s_tBtn[7].IsKeyDownFunc = IsKeyDown8;

}

/*
*********************************************************************************************************
* 函 数 名: bsp_DetectKey
* 功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。
* 形    参:  按键结构变量指针
* 返 回 值: 无
*********************************************************************************************************
*/
static void bsp_DetectKey(u8 i)
{
KEY_T *pBtn;


/*
如果没有初始化按键函数,则报错
if (s_tBtn[i].IsKeyDownFunc == 0)
{
printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
}
*/


pBtn = &s_tBtn[i];
if (pBtn->IsKeyDownFunc())
{
if (pBtn->Count < KEY_FILTER_TIME)
{
pBtn->Count = KEY_FILTER_TIME;
}
else if(pBtn->Count < 2 * KEY_FILTER_TIME)
{
pBtn->Count++;
}
else
{
if (pBtn->State == 0)
{
pBtn->State = 1;


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


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


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


pBtn->LongCount = 0;
pBtn->RepeatCount = 0;

}

/*
*********************************************************************************************************
* 函 数 名: bsp_KeyScan
* 功能说明: 扫描所有按键。非阻塞,被systick中断周期性的调用
* 形    参:  无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_KeyScan(void)
{
u8 i;


for (i = 0; i < KEY_COUNT; i++)
{
bsp_DetectKey(i);
}

}

/*
*********************************************************************************************************
* 函 数 名: bsp_InitKey
* 功能说明: 初始化按键. 该函数被 bsp_Init() 调用。
* 形    参:  无
* 返 回 值: 无
*********************************************************************************************************
*/
void Key_Init(void)
{
bsp_InitKeyVar(); /* 初始化按键变量 */
RCC->APB2ENR|=1<<2;
RCC->APB2ENR|=1<<3;     //使能PORTB时钟

GPIOA->CRL&=0XFF000FFF;  
GPIOA->CRL|=0X00888000;
GPIOA->ODR|=7<<3;

GPIOB->CRL&=0X00FFFFFF;  
GPIOB->CRL|=0X88000000;
GPIOB->ODR|=3<<6;
GPIOB->CRH&=0XFFFFFF00;  
GPIOB->CRH|=0X00000088;
GPIOB->ODR|=3<<8;

}

 

#ifndef __KEY_H
#define __KEY_H  
#include "sys.h"





#define KEY_COUNT    8   /* 按键个数*/


/* 根据应用程序的功能重命名按键宏 */
#define KEY_DOWN_K1 KEY_1_DOWN
#define KEY_UP_K1 KEY_1_UP
#define KEY_LONG_K1 KEY_1_LONG


#define KEY_DOWN_K2 KEY_2_DOWN
#define KEY_UP_K2 KEY_2_UP
#define KEY_LONG_K2 KEY_2_LONG


#define KEY_DOWN_K3 KEY_3_DOWN
#define KEY_UP_K3    KEY_3_UP
#define KEY_LONG_K3 KEY_3_LONG


#define KEY_DOWN_K4 KEY_4_DOWN /* 上 */
#define KEY_UP_K4 KEY_4_UP
#define KEY_LONG_K4 KEY_4_LONG


#define KEY_DOWN_K5 KEY_5_DOWN /* 上 */
#define KEY_UP_K5    KEY_5_UP
#define KEY_LONG_K5 KEY_5_LONG


#define KEY_DOWN_K6 KEY_6_DOWN
#define KEY_UP_K6    KEY_6_UP
#define KEY_LONG_K6 KEY_6_LONG


#define KEY_DOWN_K7 KEY_7_DOWN
#define KEY_UP_K7    KEY_7_UP
#define KEY_LONG_K7 KEY_7_LONG


#define KEY_DOWN_K8 KEY_8_DOWN
#define KEY_UP_K8    KEY_8_UP
#define KEY_LONG_K8 KEY_8_LONG




/* 按键ID, 主要用于bsp_KeyState()函数的入口参数 */
typedef enum
{
KID_K1 = 0,
KID_K2,
KID_K3,
KID_K4,
KID_K5,
KID_K6,
KID_K7,
KID_K8
}KEY_ID_E;


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


/*
每个按键对应1个全局的结构体变量。
*/
typedef struct
{
/* 下面是一个函数指针,指向判断按键手否按下的函数 */
u8 (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */


u8  Count; /* 滤波器计数器 */
u16 LongCount; /* 长按计数器 */
u16 LongTime; /* 按键按下持续时间, 0表示不检测长按 */
u8  State; /* 按键当前状态(按下还是弹起) */
u8  RepeatSpeed; /* 连续按键周期 */
u8  RepeatCount; /* 连续按键计数器 */
}KEY_T;


/*
定义键值代码, 必须按如下次序定时每个键的按下、弹起和长按事件


推荐使用enum, 不用#define,原因:
(1) 便于新增键值,方便调整顺序,使代码看起来舒服点
(2) 编译器可帮我们避免键值重复。
*/
typedef enum
{
KEY_NONE = 0, /* 0 表示按键事件 */


KEY_1_DOWN, /* 1键按下 */
KEY_1_UP, /* 1键弹起 */
KEY_1_LONG, /* 1键长按 */


KEY_2_DOWN, /* 2键按下 */
KEY_2_UP, /* 2键弹起 */
KEY_2_LONG, /* 2键长按 */


KEY_3_DOWN, /* 3键按下 */
KEY_3_UP, /* 3键弹起 */
KEY_3_LONG, /* 3键长按 */


KEY_4_DOWN, /* 4键按下 */
KEY_4_UP, /* 4键弹起 */
KEY_4_LONG, /* 4键长按 */

KEY_5_DOWN, /* 5键按下 */
KEY_5_UP, /* 5键弹起 */
KEY_5_LONG, /* 5键长按 */

KEY_6_DOWN, /* 4、5键按下 */
KEY_6_UP, /* 4、5键弹起 */
KEY_6_LONG, /*4、 5键长按 */

KEY_7_DOWN, /* 7键按下 */
KEY_7_UP, /* 7键弹起 */
KEY_7_LONG, /* 7键长按 */

KEY_8_DOWN, /* 7键按下 */
KEY_8_UP, /* 7键弹起 */
KEY_8_LONG, /* 7键长按 */
}KEY_ENUM;


/* 按键FIFO用到变量 */
#define KEY_FIFO_SIZE 8
typedef struct
{
u8 Buf[KEY_FIFO_SIZE]; /* 键值缓冲区 */
u8 Read; /* 缓冲区读指针1 */
u8 Write; /* 缓冲区写指针 */
// u8 Read2; /* 缓冲区读指针2 */
}KEY_FIFO_T;


/* 供外部调用的函数声明 */
void Key_Init(void);
void bsp_KeyScan(void);
void bsp_PutKey(u8 _KeyCode);
u8 bsp_GetKey(void);
u8 bsp_GetKey2(void);
u8 bsp_GetKeyState(KEY_ID_E _ucKeyID);
void bsp_SetKeyParam(u8 _ucKeyID, u16 _LongTime, u8  _RepeatSpeed);
void bsp_ClearKey(void);
#endif

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值