历史上的今天
返回首页

历史上的今天

今天是:2025年03月25日(星期二)

正在发生

2019年03月25日 | STM32CubeMX学习教程之三:GPIO输入之利用SysTick中断给按键去抖

2019-03-25 来源:eefocus

本文主要讨论软件去抖。实现方法是通过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的开关切换并实现了软件去抖,不会产生误动作了。

推荐阅读

史海拾趣

Akahane Electronics Ind Corp公司的发展小趣事

Akahane深知人才是企业发展的核心动力。因此,公司一直注重人才培养和引进。通过建立健全的培训机制和激励机制,Akahane吸引了一批批优秀的研发人才和管理人才。这些人才为公司的技术创新和市场拓展提供了有力支撑。同时,公司还积极与高校和研究机构合作,共同培养电子行业的后备力量。

ETAL公司的发展小趣事

ETAL公司成立于XXXX年,由一群富有远见和热情的电子工程师创立。他们看到了电子技术在全球范围内的广泛应用和巨大潜力,决定投身于这一行业。起初,ETAL主要专注于电子元器件的研发和生产,通过不断的技术创新和产品优化,逐渐在市场上树立了良好的口碑。

Automatic Connector公司的发展小趣事

面对日益严重的环境问题,Automatic Connector公司积极响应绿色制造的号召。公司投入大量资金研发环保型电子连接器,采用环保材料和节能工艺,减少生产过程中的污染排放。同时,公司还倡导循环经济的理念,推动废弃电子产品的回收和再利用。这一举措不仅提升了公司的社会形象,也为公司的可持续发展奠定了坚实的基础。

芯佰微(Corebai)公司的发展小趣事

芯佰微始终将品质管理作为公司的核心工作之一。公司建立了严格的质量管理体系,从原材料采购到产品生产、测试、包装等各个环节都进行严格的质量控制。同时,芯佰微也非常注重客户服务,始终将客户的需求放在首位,及时解决客户在使用过程中遇到的问题。这些措施使得芯佰微赢得了客户的广泛信任和好评。

ATOP_Technologies公司的发展小趣事

随着产品线的不断丰富和技术实力的提升,ATOP Technologies开始将目光投向更广阔的市场。公司积极参与国内外各类行业展会和交流活动,加强与同行和客户的交流与合作。同时,ATOP Technologies还积极开展国际合作,与多个国家的知名企业建立了战略合作关系,共同推动工业自动化领域的发展。

Advanced Linear Devices公司的发展小趣事

随着技术的不断进步,ATOP Technologies意识到要想在激烈的市场竞争中保持领先地位,必须不断进行技术创新和产品升级。因此,公司加大了在研发方面的投入,积极引进高端人才,加强与高校和研究机构的合作。经过多年的努力,ATOP Technologies成功开发出了一系列具有自主知识产权的工业自动化产品,并在市场上取得了良好的口碑。

问答坊 | AI 解惑

《新型电源电路应用实例》作者:薛永毅

再来交流点资料。尊重版权,勿作商用。 …

查看全部问答>

【招聘】奥笙北京公司软件部招聘信息(重新发帖)

奥笙公司软件部门招聘信息(北京职位) 公司简介    奥笙时代科技(北京)有限公司(www.orpheusys.com) 是成立于2007年的高科技企业,位于中关村腹地才智大厦,毗邻北大、清华和中科院,本公司与中科院声学研究所建立了战略合作关系, ...…

查看全部问答>

cximage600_ce绘制图片闪烁

cximage600_ce在连续绘制多幅图片的时候会不停的闪烁,如果要用双缓冲修改的话,应该改哪个地方呢?…

查看全部问答>

STC12C5A32S2这个片子,串口下载的时候,无法下载。出现以下提示

这个片子我按照厂家提供的下载电路搭建的,第一次下载成功了,再下载就无法下载了,上次下的程序还再执行,只要上上电就执行程序,就是不下载,我也按照顺序,先点下载然后再上电,还是不行,哪位给解决一下,谢谢。 Chinese:正在尝试与 MCU/单片 ...…

查看全部问答>

请教如何在arm9上使用mysql数据库

要做个项目,以arm9为基础,控制器是别人开发的,提供接口给我们,我们负责应用程序的开发,自己做的程序需要查询mysql数据库,所以想把mysql集成到板子里去,想请教下这么做是否可行,可行的话要如何做,能推荐几本参考书?谢谢…

查看全部问答>

LED点阵显示仿真

LED点阵显示仿真----由浅入深之8X8,16X16,24X24LED点阵流动显示 一直以来,对LED点阵显示很感兴趣,特别是流动点阵显示。论坛里有不少例子,可是在我的电脑上大多无法正常运行。有的一运行就S机,能运行的,也是字符不清。于是,自己动手 ...…

查看全部问答>

fifo缓存

请问有谁做过,用FIFO来构成数据缓存窗口的啊,比如3*3的数据缓存窗口?请教,谢谢…

查看全部问答>

MSP430g2 launch pad 下载问题

看了David_Lee https://bbs.eeworld.com.cn/thread-303736-1-1.html 那Grace很不错,跟着他做了个实验,以前用的是CCS3.3,产生一个out 文件,要在file 里load program的,可现在的CCS4没有这个选择,只需要lauch TI debugger,可我的出现下面的 ...…

查看全部问答>

职场:出色拍档的六大要素

  步入社会,你每天要和形形色色的人打交道,在社会的每个角落,你都不可能是孤立的,你必须要通过与其他人合作完成自己的工作任务。如果你在公司里工作,那么,你是否具有团队精神,直接关系到你的业绩。一些大公司招聘人才时,十分注重人才的团 ...…

查看全部问答>

ARM学习,从语言到系统的葵花宝典!

由于资料比较大,附件传不上,只能用百度云分享给大家了。 百度云: http://pan.baidu.com/s/1sjsb76d 密码: a6uk 百度链接经常出问题,如以上链接不能访问请访问我的个人分析空间查找。 地址:http://pan.baidu.com/share/home? ... are#catego ...…

查看全部问答>