STM32CubeMX学习教程之三:GPIO输入之利用SysTick中断给按键去抖

完整源码下载:

https://github.com/simonliu009/STM32CubeMX-GPIO-Debounce

上一篇博文讲述了如何使用GPIO的外部中断检测按键控制LED。但是实际情况是,物理按键通常会有抖动,导致中断多次被触发。较好的设计,应该是在硬件上做去抖设计,比如设计RC电路,或者单端稳态电路、施密特触发器(比如NEC555)等来实现。硬件去抖的好处是可以避免抖动产生的负压对MCU的GPIO造成的可能损坏。坏处是增加成本。而软件实现的去抖则无法避免负压带来的可能损害。

本文主要讨论软件去抖。实现方法是通过SysTick中断每1ms对按键进行扫描,当检测到连续的稳定无抖动电平信号(长度可设置)之后,才进行相应的逻辑操作。

 

软件版本:
STM32CubeMX V4.25.0  
System Workbench V2.4

硬件:OneNet 麒麟座V2.3

 

 

在STM32CubeMX中新建项目,选择正确的MCU型号

然后设置RCC和SYS,然后根据板子实际情况设置时钟(麒麟座外部晶振是12M,STM32F103x的最高主频是72M)

 

然后设置GPIO_Output (连接到LED) 和GPIO_Input(连接到按键)。注意上一篇文章里面按键连接的引脚设置为外部中断模式,这里只需要设置为GPIO_Input就可以了。

GPIO_Output的具体设置如下:

GPIO_Input设置如下

这里按键我用了SW1/2/3/4。

 

同样修改

Project - setting ,ToolChain/IDE选择 SW4STM32

还要勾选这里

 

然后生成代码,打开项目。

编辑stm32f1xx_it.h,函数声明那里增加一行 :

 

void Key_Scan(void);

然后编辑stm32f1xx_it.c 增加如下代码:

/* USER CODE BEGIN 0 */
uint8_t sw1Count,sw2Count,sw3Count,sw4Count;
uint8_t pushFlag1,pushFlag2,pushFlag3,pushFlag4;
extern uint8_t swState1,swState2,swState3,swState4;
 void Key_Scan(void)
{
         /*检测SW1是否按下 */
         if(   HAL_GPIO_ReadPin(SW1_GPIO_Port,SW1_Pin) == GPIO_PIN_RESET )
         {
                 sw1Count++;                         //SW1键按下,计数sw1Count加1
                 if(sw1Count>=32)                    //1MS中断一次,sw1Count大于等于32,即按键已按下32ms
                 {
                         if(pushFlag1==0)                //判断有没有重按键,1为有,0为没有
                        {
                        swState1=1;                       //设置按键标志
                        sw1Count=0;
                        pushFlag1=1;                     //设置重按键标志
                        }
                        else
                        sw1Count=0;
                 }
                 else
                	    swState1=0;

         }
         else                                            //无按键按下
         {
                 sw1Count=0;                           //清零sw1Count
                 swState1=0;                            //清除按键标志
                 pushFlag1=0;                          //清除重按键标志
         }

         /*检测SW2是否按下 */
         if(   HAL_GPIO_ReadPin(SW2_GPIO_Port,SW2_Pin) == GPIO_PIN_RESET )
         {
                 sw2Count++;                         //SW2键按下,计数sw2Count加1
                 if(sw2Count>=32)                    //1MS中断一次,sw2Count大于等于32,即按键已按下32ms
                 {
                         if(pushFlag2==0)                //判断有没有重按键,1为有,0为没有
                        {
                        swState2=1;                       //设置按键标志
                        sw2Count=0;
                        pushFlag2=1;                     //设置重按键标志
                        }
                        else
                        sw2Count=0;
                 }
                 else
                	    swState2=0;

         }
         else                                            //无按键按下
         {
                 sw2Count=0;                           //清零sw2Count
                 swState2=0;                            //清除按键标志
                 pushFlag2=0;                          //清除重按键标志
         }

         /*检测SW3是否按下 */
         if(   HAL_GPIO_ReadPin(SW3_GPIO_Port,SW3_Pin) == GPIO_PIN_RESET )
         {
                 sw3Count++;                         //SW3键按下,计数sw3Count加1
                 if(sw3Count>=32)                    //1MS中断一次,sw3Count大于等于32,即按键已按下32ms
                 {
                         if(pushFlag3==0)                //判断有没有重按键,1为有,0为没有
                        {
                        swState3=1;                       //设置按键标志
                        sw3Count=0;
                        pushFlag3=1;                     //设置重按键标志
                        }
                        else
                        sw3Count=0;
                 }
                 else
                	    swState3=0;

         }
         else                                            //无按键按下
         {
                 sw3Count=0;                           //清零sw3Count
                 swState3=0;                            //清除按键标志
                 pushFlag3=0;                          //清除重按键标志
         }

         /*检测SW4是否按下 */
         if(   HAL_GPIO_ReadPin(SW4_GPIO_Port,SW4_Pin) == GPIO_PIN_RESET )
         {
                 sw4Count++;                         //SW4键按下,计数sw4Count加1
                 if(sw4Count>=32)                    //1MS中断一次,sw4Count大于等于32,即按键已按下32ms
                 {
                         if(pushFlag4==0)                //判断有没有重按键,1为有,0为没有
                        {
                        swState4=1;                       //设置按键标志
                        sw4Count=0;
                        pushFlag4=1;                     //设置重按键标志
                        }
                        else
                        sw4Count=0;
                 }
                 else
                	    swState4=0;

         }
         else                                            //无按键按下
         {
                 sw4Count=0;                           //清零sw4Count
                 swState4=0;                            //清除按键标志
                 pushFlag4=0;                          //清除重按键标志
         }

}
/* USER CODE END 0 */

然后在SysTick中断处理函数增加一行 void Key_Scan(void);, 代码如下:

/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
	Key_Scan();
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  HAL_SYSTICK_IRQHandler();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

 在gpio.c 中增加如下两处代码:

/* USER CODE BEGIN 1 */
GPIO_TypeDef* GPIO_PORT[] = {LED1_GPIO_Port,
                             LED2_GPIO_Port,
			     LED3_GPIO_Port,
			     LED4_GPIO_Port};

const uint16_t GPIO_PIN[] = {LED1_Pin,
			     LED2_Pin,
                             LED3_Pin,
			     LED4_Pin};

/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
void LED_Toggle(Led_TypeDef Led)
{
HAL_GPIO_TogglePin(GPIO_PORT[Led], GPIO_PIN[Led]);
}

/* USER CODE END 2 */

然后编辑main.c,增加如下两处代码:

/* USER CODE BEGIN 0 */
uint8_t swState1,swState2,swState3,swState4;
/* USER CODE END 0 */
 /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if  ( swState1 == 1 )
	  {
		  LED_Toggle(LED1);
//		  HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
		  HAL_Delay(1);
	  }
	  if  ( swState2 == 1 )
	  {
		  LED_Toggle(LED2);
//		  HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
		  HAL_Delay(1);
	  }
	  if  ( swState3 == 1 )
	  {
		  LED_Toggle(LED3);
//		  HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);
		  HAL_Delay(1);
	  }
	  if  ( swState4 == 1 )
	  {
		  LED_Toggle(LED4);
//		  HAL_GPIO_TogglePin(LED4_GPIO_Port,LED4_Pin);
		  HAL_Delay(1);
	  }
  /* USER CODE END WHILE */

注意 如下两个语句是等效的,我注释掉了HAL_GPIO_TogglePin()。因为我们使用枚举重新定义了LED状态切换的函数LED_Toggle()。

1.		  LED_Toggle(LED1);  
2.		  HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);

 

然后右键点击项目,选择Properties, Run-Debug Settings, 点击右侧的New,在弹出对话框中选择Ac6 STM32 Debugging。

然后任务栏上点击Run图,当然会报错的,原因请查看另一篇我的博客(https://blog.csdn.net/toopoo/article/details/79680323),所以需要右键点击  项目名Run.cfg ,给它改个名字,

 

然后右键点击项目树里面的项目名称,选择“Propeties”,然后在Run/Debug Settings-选择项目名-Edit-Main-C/C++Application那里点击“Search Project”,然后选择出现的默认的elf文件:

然后在Debugger-User Defined-Browse 那里选择你自己改名的配置文件:

然后右键点击那个新的cfg文件,选择"Open With - Text Editor", 进行如下更改:

source [find interface/stlink.cfg] 更改为 source [find interface/stlink-v2.cfg]

reset_config srst_only srst_nogate connect_assert_srst 这一行改为 reset_config none 

然后再Run一下,就可以了。

 

就实现四个按键分别控制LED的开关切换并实现了软件去抖,不会产生误动作了。

 

本文参考了如下文章:

http://www.waveshare.net/study/article-630-1.html

https://blog.csdn.net/yongyooh/article/details/21877227

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值