STM32CubeMX学习教程之三:GPIO输入之利用SysTick中断给按键去抖
2018-03-27 19:01
567 查看
上一篇博文讲述了如何使用GPIO的外部中断检测按键控制LED。但是实际情况是,物理按键通常会有抖动,导致中断多次被触发。较好的设计,应该是在硬件上做去抖设计,比如设计RC电路,或者单端稳态电路、施密特触发器(比如NEC555)等来实现。硬件去抖的好处是可以避免抖动产生的负压对MCU的GPIO造成的可能损坏。坏处是增加成本。而软件实现的去抖则无法避免负压带来的可能损害。
本文主要讨论软件去抖。实现方法是通过SysTick中断每1ms对按键进行扫描,当检测到连续的稳定无抖动电平信号(长度可设置)之后,才进行相应的逻辑操作。
软件版本:
STM32CubeMX V4.25.0
System Workbench V2.4硬件:OneNet 麒麟座V2.3
在STM32CubeMX中新建项目,选择正确的MCU型号
![](https://img-blog.csdn.net/20180327195621182?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
然后设置RCC和SYS,然后根据板子实际情况设置时钟(麒麟座外部晶振是12M,STM32F103x的最高主频是72M)
![](https://img-blog.csdn.net/2018032622454826?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![](https://img-blog.csdn.net/20180326224638413?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
然后设置GPIO_Output (连接到LED) 和GPIO_Input(连接到按键)。注意上一篇文章里面按键连接的引脚设置为外部中断模式,这里只需要设置为GPIO_Input就可以了。
![](https://img-blog.csdn.net/20180327183001965?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
GPIO_Output的具体设置如下:
![](https://img-blog.csdn.net/20180327183147918?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
GPIO_Input设置如下
![](https://img-blog.csdn.net/20180327183227163?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
这里按键我用了SW1/2/3/4。
同样修改Project - setting ,ToolChain/IDE选择 SW4STM32
![](https://img-blog.csdn.net/20180327192226830?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
还要勾选这里
![](https://img-blog.csdn.net/20180326225056515?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rvb3Bvbw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
然后生成代码,打开项目。
编辑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
sw4Cou
4000
nt=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 */
}这次控制LED的语句我们升级一下,使用枚举。 在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 */
uint8_t swState1,swState2,swState3,swState4;
/* USER CODE END 0 */
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
本文主要讨论软件去抖。实现方法是通过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
sw4Cou
4000
nt=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 */
}这次控制LED的语句我们升级一下,使用枚举。 在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);然后Run/Debug Setting里面使用自定义 Run.cfg文件,修改如下两行: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
相关文章推荐
- STM32CubeMX学习教程之二:GPIO输入之外部中断
- Linux gpio 按键中断学习
- STM32CubeMX学习教程之四:定时器中断
- STM32 学习总结2 ----利用中断来控制按键点灯、捕获功能练习
- STM32CubeMX学习教程之一:GPIO输出之跑马灯
- ARM7测试外部方波信号(利用GPIO口和定时器中断)
- 2、CC2541芯片中级教程-OSAL操作系统(进一步了解-OLED && 普通按键和5方向按键-中断!!!)这个系统驱动层和应用层不一样~
- 嵌入式学习-uboot-lesson11-按键中断
- stm32笔记:GPIO的的配置和操作(2)引脚输入之查询按键
- S3C2440学习之GPIO按键控制LED灯
- 20150217 IMX257实现GPIO-IRQ中断按键驱动程序
- Tensorflow学习教程------模型参数和网络结构保存且载入,输入一张手写数字图片判断是几
- STM32-按键输入实验学习笔记
- 设备树学习之(一)GPIO中断【转】
- 用龙芯1c库在RT-Thread下实现外部中断(GPIO中断、按键中断)
- STM8_GPIO 外部中断输入
- Tiny6410 + Linux2.6.38 + input子系统 + 按键中断模拟系统键盘输入的例程
- stm8 GPIO按键输入
- STM32F103mini教程学习总结与心得(三)---->中断
- 按键输入-GPIO输入