IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 独立按键驱动设计--多功能、多模式 -> 正文阅读

[嵌入式]独立按键驱动设计--多功能、多模式

概述

本文所介绍的按键是基于STM32F系列独立按键模式,目的是使单个按键具备多种按键效果。常见的有单击、长按等功能。为拓展功能多样性,对按键驱动进行设计,实现按键功能的多样性,本设计已达到的功能包括单击、长按、双击、三击、四击…等,剩余可由用户自行添加。按键消息通过消息队列进行传递。

按键对象封装

类似于面向对象中类的封装,该结构体包含按键触发函数、硬件接口、计数器及按键状态标记。

typedef void (*KEYFUNC) (uint16_t tick_cnt_ptr);
该定义为:声明一个函数指针,指向一个参数为uint16_t 类型的变量的函数。
typedef struct
{
	KEYFUNC key_function;
	KEYFUNC fast_key_fun;
	GPIO_TypeDef* GPIOx;
	uint16_t Pin;
	uint16_t key_cnt;
	uint16_t  Status;
} KEYSTATUS;

按键事件注册

注册按键的触发函数、初始状态State、按键初始化等。
声明两个枚举变量进行按键的开启与关闭(DISABLE_KEY、GENERAL_KEY)。

enum
{
	DISABLE_KEY,
	GENERAL_KEY
};
申明一个map对象,为每个按键引用驱动类:
KEYSTATUS	io_key_map[IOKEY_NUM];
在此函数开启之前确保按键引脚已成功初始化。
void ap_peripheral_key_register(INT8U type)
{
	io_key_num = 0;
	switch(type)
	{
		case DISABLE_KEY:
		{
			//disable all key
		}
			break;
		case GENERAL_KEY:
		{
			#if IO_KEY
			io_key_map[io_key_num].GPIOx = KEY_Pin_GPIO_Port;
			io_key_map[io_key_num].Pin = KEY_Pin_Pin;
			io_key_map[io_key_num].key_function = ap_peripheral_io_key_exe;
			//io_key_map[io_key_num].fast_key_fun = ap_peripheral_io_fast_key_exe;
			io_key_map[io_key_num].key_cnt = 0;
			io_key_map[io_key_num++].Status = 0;
			#endif
			#if CHARGE
			io_key_map[io_key_num].GPIOx = STAT_CHG_GPIO_Port;
			io_key_map[io_key_num].Pin = STAT_CHG_Pin;
			io_key_map[io_key_num].key_function = ap_peripheral_charge_exe;
			io_key_map[io_key_num].key_cnt = 0;
			io_key_map[io_key_num++].Status = 0;
			#endif
			#if IO_USB
			io_key_map[io_key_num].GPIOx = USB_CH_GPIO_Port;
			io_key_map[io_key_num].Pin = USB_CH_Pin;
			io_key_map[io_key_num].key_function = ap_peripheral_io_usb_exe;
			io_key_map[io_key_num].key_cnt = 0;
			io_key_map[io_key_num++].Status = 0;
			#endif
		}
			break;
		default:
			ap_peripheral_key_register(DISABLE_KEY);
			break;
	}
}

按键回调函数

按键事件注册后,每个按键引脚功能编写对应的回调函数,为事件注册使用。
说明:按键消息是基于消息队列进行消息传递,可根据用户的需求自行设计回调函数功能!

第一个按键回调函数:

void ap_peripheral_io_key_exe(INT16U tick_cnt_ptr)
{
	if(tick_cnt_ptr >= LONG_KEY_TIME)
	{
		msgQSend(APQ, MSG_APQ_LONG_KEY,MSG_PRI_NORMAL);
	}
	else if(tick_cnt_ptr == TWO_KEY_VALUE)
	{
		msgQSend(APQ, MSG_APQ_TWO_KEY,MSG_PRI_NORMAL);
	}
	else if(tick_cnt_ptr == THREE_KEY_VALUE)
	{
		msgQSend(APQ, MSG_APQ_THREE_KEY,MSG_PRI_NORMAL);
	}
	else if(tick_cnt_ptr == FOUR_KEY_VALUE)
	{
		msgQSend(APQ, MSG_APQ_FOUR_KEY,MSG_PRI_NORMAL);
	}
	else if(tick_cnt_ptr == FIVE_KEY_VALUE)
	{
		msgQSend(APQ, MSG_APQ_FIVE_KEY,MSG_PRI_NORMAL);
	}
	else
	{
		msgQSend(APQ, MSG_APQ_CLICK_KEY,MSG_PRI_NORMAL);
	}
}
其他按键的回调函数与其相似,可自行设计......

按键扫描

按键扫描通过定时器中断进行扫描,优点是有稳定的扫描时间,可计算按键的持续时间及消抖,本设计是20ms扫描一次。此函数中,由按键事件注册函数提供一个io_key_num为其提供扫描范围:

void ap_peripheral_key_judge(void)
{
#if IOKEY_NUM
	INT8U i,status;
	static INT8U short_key_pressed = 0,key_cnt = 0;
	static INT32U last_time = 0,loosen_time = 0;
	INT32U current_time;
	for(i = 0; i < io_key_num; i++)
	{
		status = HAL_GPIO_ReadPin(io_key_map[i].GPIOx,io_key_map[i].Pin);
		#if IO_KEY
		if(io_key_map[i].Pin == KEY_Pin_Pin)
		{	
			if(status == KEY_VALUE)//按下
			{
				if(!io_key_map[i].Status)
				{	
					io_key_map[i].key_cnt += 1;
					if(io_key_map[i].key_cnt >= LONG_KEY_TIME)//长按
					{
						io_key_map[i].Status = 1;
						io_key_map[i].key_function(io_key_map[i].key_cnt);//长按回调
					}
				}
				else 
				{
					io_key_map[i].key_cnt = 0;
				}
				if(io_key_map[i].key_cnt == 65535)
				{
					io_key_map[i].key_cnt = 16;
				}
			}
			else//松开
			{
			if(io_key_map[i].key_cnt > 2)
			{
				current_time = HAL_GetTick();
				if(key_cnt==0)
				{
					last_time = current_time;//记录第一次松开的时间
				}
				if(current_time - last_time <= INTERVAL_TIME)
				{
					key_cnt++;
					last_time = current_time;//记录最后一次松开的时间
				}
			}
			if(key_cnt&&(HAL_GetTick()-last_time>INTERVAL_TIME))
			{				
				io_key_map[i].key_function(key_cnt);				
				key_cnt = 0;
			}
			io_key_map[i].key_cnt = 0;
			io_key_map[i].Status = 0;
			}
		}
		#endif
		#if CHARGE
		if(io_key_map[i].Pin == STAT_CHG_Pin)
		{
			if(status == CHARGE_VALUE)
			{
				if(!io_key_map[i].Status)
				{
					io_key_map[i].key_cnt++;
					if(io_key_map[i].key_cnt>200)
					{
						io_key_map[i].Status = 1;
						io_key_map[i].key_function(1);
					}
				}
				else
				{
					io_key_map[i].key_cnt = 0;
				}
				if(io_key_map[i].key_cnt == 65535)
				{
					io_key_map[i].key_cnt = 8;
				}
			}
			else
			{
				if(io_key_map[i].Status)
				{
					io_key_map[i].key_function(0);
					io_key_map[i].Status = 0;
					io_key_map[i].key_cnt = 0;
				}
			}
		}
		#endif
		#if IO_USB
		if(io_key_map[i].Pin == USB_CH_Pin)
		{
			if(status == USB_VALUE)
			{
				if(!io_key_map[i].Status)
				{
					io_key_map[i].key_cnt++;
					if(io_key_map[i].key_cnt>5)
					{
						io_key_map[i].Status = 1;
						io_key_map[i].key_function(1);
					}
				}
				else
				{
					io_key_map[i].key_cnt = 0;
				}
				if(io_key_map[i].key_cnt == 65535)
				{
					io_key_map[i].key_cnt = 8;
				}
			}
			else
			{
				if(io_key_map[i].Status)
				{
					io_key_map[i].key_function(0);
					io_key_map[i].Status = 0;
					io_key_map[i].key_cnt = 0;
				}
			}
		}
		#endif
	}
#endif
}

总结

该独立按键的多种功能设计,目的是实现单个按键实现多种功能,就好比遥控器的上、下、左、右、确定、返回等,通过单个按键就可实现其所有功能。该按键功能的实现,依赖于消息队列进行按键消息传递,项目引入消息队列后,极大方便了按键回调函数的设计实现。

个人笔记总结,若有问题,欢迎留言、批评指正!!!

在这里插入图片描述

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-28 12:32:33  更:2021-10-28 12:34:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:46:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码