按键消抖的方式

1.使用并联电容的方式

        电容消抖:在开光并联一个电容,电容不能突变,平稳后才输出,达到消抖目的,但是这样会增加产品的硬件成本,一般项目更倾向于使用软件处理中断,降低成本

2.使用外部中断服务函数触发标志位

         使用外部中断,在外部中断服务函数中设置一个标志位,在主函数中进行标志位判断,延时50ms,然后再判断和相应操作,这样会影响主函数的效率

#include "stm32f4xx.h"

static GPIO_InitTypeDef GPIO_InitStructure;
static EXTI_InitTypeDef EXTI_InitStructure;
static NVIC_InitTypeDef NVIC_InitStructure;

void delay_ms(uint32_t ms)
{
	while (ms--)
	{
		SysTick->CTRL = 0;	   // 关闭系统定时器后才能配置寄存器
		SysTick->LOAD = 21000; // 设置计数值,用于设置定时的时间
		SysTick->VAL = 0;	   // 清空当前值还有计数标志位
		SysTick->CTRL = 1;	   // 使能系统定时器工作,且时钟源为系统时钟的8分频(168MHz/8=21MHz)
		while ((SysTick->CTRL & (1 << 16)) == 0)
			;			   // 等待系统定时器计数完毕
		SysTick->CTRL = 0; // 关闭系统定时器
	}
}

#define PEout(n) (*(volatile uint32_t *)(0x42000000 + (GPIOE_BASE + 0x14 - 0x40000000) * 32 + n * 4))
#define PFout(n) (*(volatile uint32_t *)(0x42000000 + (GPIOF_BASE + 0x14 - 0x40000000) * 32 + n * 4))
#define PAin(n) (*(volatile uint32_t *)(0x42000000 + (GPIOA_BASE + 0x10 - 0x40000000) * 32 + n * 4))

static uint32_t g_key_event = 0;

/* 主函数 */
int main(void)
{
	/* 打开端口A的硬件时钟(就是对硬件供电),默认状态下,所有时钟都是关闭 */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

	/* 打开端口F的硬件时钟(就是对硬件供电),默认状态下,所有时钟都是关闭 */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);

	/* 打开系统配置syscfg时钟(就是对硬件供电),默认状态下,所有时钟都是关闭 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; // 指定9 10号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;			// 引脚工作在输出模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;		// 速度越高,响应时间越短,但是功耗就越高,电磁干扰也越高
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			// 如果外部没有上拉电阻,就配置推挽输出模式
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		// 不需要使能上下拉电阻
	GPIO_Init(GPIOF, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		   // 指定0号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;	   // 引脚工作在输入模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 速度越高,响应时间越短,但是功耗就越高,电磁干扰也越高
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   // 不需要使能上下拉电阻
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* 将外部中断连接到指定的引脚,特别说明:引脚编号决定了使用哪个外部中断 */
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);

	/* 配置外部中断0 */
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;				// 指定外部中断0
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;		// 工作在中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发:就是发现有从高电平到低电平的跳变,就向CPU中断请求处理
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;				// 允许外部中断0工作
	EXTI_Init(&EXTI_InitStructure);

	/* 通过NVIC管理外部中断0的中断请求:中断号、优先级、中断打开/关闭 */
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;			 // 中断号
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; // 抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;		 // 响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				 // 中断打开
	NVIC_Init(&NVIC_InitStructure);

	PFout(9) = 1;
	PFout(10) = 1;

	while (1)
	{
		if (g_key_event)
		{
			delay_ms(50); // 延时消抖

			if (PAin(0) == 0) // 按键按下
				PFout(9) ^= 1;

			while (PAin(0) == 0)
				;

			g_key_event = 0;

			/* 打开EXTI0外部中断请求 */
			NVIC_EnableIRQ(EXTI0_IRQn);
		}
	}
}

/* 中断服务函数 */
void EXTI0_IRQHandler(void)
{
	/* 检测中断是否有触发 */
	if (EXTI_GetITStatus(EXTI_Line0) == SET)
	{

		/* 添加用户代码:灯的控制 */
#if 1
		g_key_event = 1;

		/* 关闭EXTI0外部中断请求 */
		NVIC_DisableIRQ(EXTI0_IRQn);

#else

		PFout(9) ^= 1; // 0^1=1 1^1=0 .........
#endif

		/* 清空中断标志位,告诉CPU当前事件已经处理完毕
		   思考题:如果不清空标志位,会出现什么现象?
		*/
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

3.使用外部中断服务函数调用另外一个定时器中断服务函数

 使用外部中断(EXTI)使能一个定时器(TIM),定时器设置为50ms左右,在外部中断中使能定时器,然后在定时器中断服务函数中进行判断和相应操作,这样就不会影响到主函数的运行,提高效率
 

void EXTI2_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line2) == SET)
	{
     	/* 清除定时器3的时间更新标志位 */
     	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
      
		/* 关闭定时器3 */
    	TIM_Cmd(TIM3, DISABLE); 
     
        	/* 清空当前计数值 */
        	TIM_SetCounter(TIM3,0);
		
		/* 启动定时器3,就算有一些纹波存在,也会重置定时器 */
		TIM_Cmd(TIM3, ENABLE);	
           
		EXTI_ClearITPendingBit(EXTI_Line2);
	}
}

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
	{
		/* 检测按键状态*/
		if(PEin(2)==0)
			PFout(9)^=1;
		
		/* 关闭定时器3 */
		TIM_Cmd(TIM3, DISABLE);
  
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值