keil,C代码实现按键单击按下触发,单击松开触发,双击,长按功能

本文详细介绍了如何在STM32F4微控制器上使用标准库配置GPIO,包括按键的初始化、硬件操作、系统时钟中断处理和按键扫描函数,展示了单击、长按及双击等按键功能的实现。
摘要由CSDN通过智能技术生成

STM32F4芯片标准库配置

1、按键初始化

/* 判断按键按下函数 */
uint8_t IsKeyDown1(void) {if ((GPIOE->IDR & GPIO_Pin_6) == 0) return 0;else return 1;}//UP
uint8_t IsKeyDown2(void) {if ((GPIOC->IDR & GPIO_Pin_15) == 0) return 0;else return 2;}//DOWN
uint8_t IsKeyDown3(void) {if ((GPIOC->IDR & GPIO_Pin_13) == 0) return 0;else return 4;}//MENU
uint8_t IsKeyDown4(void) {if ((GPIOC->IDR & GPIO_Pin_14) == 0) return 0;else return 8;}//SET
uint8_t IsKeyDown5(void) {if ((GPIOE->IDR & GPIO_Pin_5) == 0) return 0;else return 16;}//ON/OFF

/*硬件初始化*/
static void bsp_InitKeyHard(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 第1步:打开GPIO时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOE,ENABLE); //使能GPIO时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;         //PC13 14 15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;		/* 设为输入口 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	/* IO口最大速度 */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉输入
GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_6;            //PE5 PE6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);

}

2、系统时钟中断函数

其他时钟的中断函数也可以,1ms中断

#define  MAX_KEY_TIME  40	//max read key time
extern uint32_t keydouble_time;
extern uint8_t keydouble_number;
void SysTick_Handler(void)
{
	if(keydouble_time) keydouble_time--;
	else keydouble_number=0;
	
	if(--_Key.TimeCount==0)
	{
		_Key.TimeCount = MAX_KEY_TIME;
		_Key.Reflash = 1; 
	}
}

3、主函数

int main(void)
{
	SysTick_Config(SystemCoreClock / 1000);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC,ENABLE);//使能CRC时钟,时钟恢复电路

	bsp_InitKeyHard();       //按键GPIO初始化        PC13、PC14、PC15、PE6、PE7

	while(1)
	{
		keyscan(&_Key.Reflash);			//定时器中断,40ms进入一次
	}
}

4、按键扫描函数

uint8_t keyvalue_old;		//保存上一次按键数据
uint8_t keyvalue_press;		//上一次按键按下的记录

uint8_t key_debounce_count=0;//按键消抖计数
uint32_t menu_press_count=0;	//menu按键按下时触发(包括单击和长按)
uint8_t keypress_flag;		//按键按下1,按键松开0
uint32_t free_count;			//按键松开时触发

uint8_t key_longflag=0;		//按键长按标志
uint32_t key_longcount;		//长按计数

uint8_t keydouble_number;	//记录双击第几次按下
uint32_t keydouble_time;	//记录在多少时间内双击有效
uint32_t keydouble_count;		//完成双击时触发

void keyscan(uint8_t *read_time)//单击按下,单击松开,双击,长按
{
	uint8_t i;
	if(*read_time)//累计40ms把标志位拉高一次
	{
		*read_time = 0;
		i = (IsKeyDown1()|IsKeyDown2()|IsKeyDown3()|IsKeyDown4()|IsKeyDown5())&0X1F;//读按键
	
		if(i == NO_KEY_NUM)//如果没有按键按下
		{
			if(keyvalue_press != NO_KEY_NUM)//上一次按键值不为空//
			{
				keyvalue_press = NO_KEY_NUM;//无按键按下
				switch(keyvalue_old)//上一次按下的按键
				{
					case MENU_NUM:
						free_count++;			/*code  按键单击松开时触发*/
					break;
					default:break;
				}
			}
		}
		else//按键按下时
		{
			if(keyvalue_old != i)//如果上一次按键和本次按键不一样
			{
				keyvalue_old = i;		//上一次按键 = 本次按键
				key_debounce_count=0;	//消抖计数值清零
			}
			else//如果上一次按键和本次按键一样
			{
				if(++key_debounce_count>2)//按键防抖
				{
					key_debounce_count=0;//消抖计数值清零
					
					switch(i)
					{
						case  MENU_NUM://MODE KEY
							if(i == keyvalue_press)//如果上一次按键和本次一样
							{
								keypress_flag=0;//不进入单击计数//否则可能按一下按键,会进入两次
								if(key_longflag)//长按使能标志 1使能,0失能
								{
									if(++key_longcount > 10)//长按计数超过10次
									{
										keypress_flag=1;//若是使能长按,依旧可以进行单击计数
									}
								}
							}
							else//如果上一次按键和本次不一样
							{
								key_longcount = 0;//长按计数清零
								keypress_flag=1;//进行单击计数
							}
							
							if(keypress_flag)
							{
								keyvalue_press = i;
								menu_press_count++;			/*code 按键单击按下时触发,以及使能长按功能后触发*/
								
								if(key_longflag==0)//双击功能在长按功能不生效时启用
								{
									if(keydouble_number == 0)//单击第一下
									{
										keydouble_number=1;
										keydouble_time = 1000;//定时器中递减
									}
									else if(keydouble_number==1 && keydouble_time)//在时间内单击第二下
									{
										keydouble_number=0;
										keydouble_time=0;
										keydouble_count++;		/*code  按键双击时触发*/
									}
								}
							}
						break;
						default:break;
					}
				}
			}
		}
	}
}

代码以一个按键为例,可以继续封装到函数中,功能大概是这样子。

变量有点多,还是需要理一理思路。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值