历史上的今天
返回首页

历史上的今天

今天是:2024年09月19日(星期四)

正在发生

2019年09月19日 | 第12章 GPIO输入-按键检测—零死角玩转STM32-F429系列

2019-09-19 来源:eefocus

本章参考资料:《STM32F4xx参考手册》、库帮助文档《stm32f4xx_dsp_stdperiph_lib_um.chm》。


按键检测使用到GPIO外设的基本输入功能,本章中不再赘述GPIO外设的概念,如您忘记了,可重读前面"GPIO框图剖析"小节,STM32标准库中GPIO初始化结构体GPIO_TypeDef的定义与"定义引脚模式的枚举类型"小节中讲解的相同。


12.1 硬件设计

按键机械触点断开、闭合时,由于触点的弹性作用,按键开关不会马上稳定接通或一下子断开,使用按键时会产生图 121中的带波纹信号,需要用软件消抖处理滤波,不方便输入检测。本实验板连接的按键带硬件消抖功能,见图 122,它利用电容充放电的延时,消除了波纹,从而简化软件的处理,软件只需要直接检测引脚的电平即可。

图 121 按键抖动说明图


图 122 按键原理图


从按键的原理图可知,这些按键在没有被按下的时候,GPIO引脚的输入状态为低电平(按键所在的电路不通,引脚接地),当按键按下时,GPIO引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。只要我们检测引脚的输入电平,即可判断按键是否被按下。


若您使用的实验板按键的连接方式或引脚不一样,只需根据我们的工程修改引脚即可,程序的控制原理相同。


12.2 软件设计

同LED的工程,为了使工程更加有条理,我们把按键相关的代码独立分开存储,方便以后移植。在"工程模板"之上新建"bsp_key.c"及"bsp_key.h"文件,这些文件也可根据您的喜好命名,这些文件不属于STM32标准库的内容,是由我们自己根据应用需要编写的。


12.2.1 编程要点

1.    使能GPIO端口时钟;


2.    初始化GPIO目标引脚为输入模式(引脚默认电平受按键电路影响,浮空/上拉/下拉均没有区别);


3.    编写简单测试程序,检测按键的状态,实现按键控制LED灯。


12.2.2 代码分析

1.    按键引脚宏定义

同样,在编写按键驱动时,也要考虑更改硬件环境的情况。我们把按键检测引脚相关的宏定义到"bsp_key.h"文件中,见代码清单 111。


代码清单 121 按键检测引脚相关的宏


1 //引脚定义


2 /*******************************************************/


3 #define KEY1_PIN GPIO_Pin_0


4 #define KEY1_GPIO_PORT GPIOA


5 #define KEY1_GPIO_CLK RCC_AHB1Periph_GPIOA


6


7 #define KEY2_PIN GPIO_Pin_13


8 #define KEY2_GPIO_PORT GPIOC


9 #define KEY2_GPIO_CLK RCC_AHB1Periph_GPIOC


10 /*******************************************************/


以上代码根据按键的硬件连接,把检测按键输入的GPIO端口、GPIO引脚号以及GPIO端口时钟封装起来了。


2.    按键 GPIO初始化函数

利用上面的宏,编写按键的初始化函数,见代码清单 122。


代码清单 122 按键GPIO初始化函数


1 /**


2 * @brief 配置按键用到的I/O口


3 * @param 无


4 * @retval 无


5 */


6 void Key_GPIO_Config(void)


7 {


8 GPIO_InitTypeDef GPIO_InitStructure;


9


10 /*开启按键GPIO口的时钟*/


11 RCC_AHB1PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);


12


13 /*选择按键的引脚*/


14 GPIO_InitStructure.GPIO_Pin = KEY1_PIN;


15


16 /*设置引脚为输入模式*/


17 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;


18


19 /*设置引脚不上拉也不下拉*/


20 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;


21


22 /*使用上面的结构体初始化按键*/


23 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);


24


25 /*选择按键的引脚*/


26 GPIO_InitStructure.GPIO_Pin = KEY2_PIN;


27


28 /*使用上面的结构体初始化按键*/


29 GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);


30 }


 


同为GPIO的初始化函数,初始化的流程与"LED GPIO初始化函数"章节中的类似,主要区别是引脚的模式。函数执行流程如下:


(1)    使用GPIO_InitTypeDef定义GPIO初始化结构体变量,以便下面用于存储GPIO配置。


(2)    调用库函数RCC_AHB1PeriphClockCmd来使能按键的GPIO端口时钟,调用时我们使用"|"操作同时配置两个按键的时钟。


(3)    向GPIO初始化结构体赋值,把引脚初始化成浮空输入模式,其中的GPIO_Pin使用宏"KEYx_PIN"来赋值,使函数的实现方便移植。由于引脚的默认电平受按键电路影响,所以设置成"浮空/上拉/下拉"模式均没有区别。


(4)    使用以上初始化结构体的配置,调用GPIO_Init函数向寄存器写入参数,完成GPIO的初始化,这里的GPIO端口使用"KEYx_GPIO_PORT"宏来赋值,也是为了程序移植方便。


(5)    使用同样的初始化结构体,只修改控制的引脚和端口,初始化其它按键检测时使用的GPIO引脚。


3.    检测按键的状态

初始化按键后,就可以通过检测对应引脚的电平来判断按键状态了,见代码清单 123。


代码清单 123 检测按键的状态


1 /** 按键按下标置宏


2 * 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0


3 * 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可


4 */


5 #define KEY_ON 1


6 #define KEY_OFF 0


7


8 /**


9 * @brief 检测是否有按键按下


10 * @param GPIOx:具体的端口, x可以是(A...K)


11 * @param GPIO_PIN:具体的端口位,可以是GPIO_PIN_x(x可以是0...15)


12 * @retval 按键的状态


13 * @arg KEY_ON:按键按下


14 * @arg KEY_OFF:按键没按下


15 */


16 uint8_t Key_Scan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)


17 {


18 /*检测是否有按键按下 */


19 if (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON ) {


20 /*等待按键释放 */


21 while (GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);


22 return KEY_ON;


23 } else


24 return KEY_OFF;


25 }


在这里我们定义了一个Key_Scan函数用于扫描按键状态。GPIO引脚的输入电平可通过读取IDR寄存器对应的数据位来感知,而STM32标准库提供了库函数GPIO_ReadInputDataBit来获取位状态,该函数输入GPIO端口及引脚号,函数返回该引脚的电平状态,高电平返回1,低电平返回0。Key_Scan函数中以GPIO_ReadInputDataBit的返回值与自定义的宏"KEY_ON"对比,若检测到按键按下,则使用while循环持续检测按键状态,直到按键释放,按键释放后Key_Scan函数返回一个"KEY_ON"值;若没有检测到按键按下,则函数直接返回"KEY_OFF"。若按键的硬件没有做消抖处理,需要在这个Key_Scan函数中做软件滤波,防止波纹抖动引起误触发。


4.    主函数

接下来我们使用主函数编写按键检测流程,见代码清单 124。


代码清单 124 按键检测主函数


 


1 /**


2 * @brief 主函数


3 * @param 无


4 * @retval 无


5 */


6 int main(void)


7 {


8 /* LED 端口初始化 */


9 LED_GPIO_Config();


10


11 /*初始化按键*/


12 Key_GPIO_Config();


13


14 /* 轮询按键状态,若按键按下则反转LED */


15 while (1) {


16 if ( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON ) {


17 /*LED1反转*/


18 LED1_TOGGLE;


19 }


20


21 if ( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON ) {


22 /*LED2反转*/


23 LED2_TOGGLE;


24 }


25 }


26 }


代码中初始化LED灯及按键后,在while函数里不断调用Key_Scan函数,并判断其返回值,若返回值表示按键按下,则反转LED灯的状态。


12.2.3 下载验证

把编译好的程序下载到开发板并复位,按下按键可以控制LED灯亮、灭状态。

推荐阅读

史海拾趣

GAPTEC Electronic GmbH & Co. KG公司的发展小趣事

背景:2000年代初,随着全球对数字设备需求的激增,Galaxy Microelectronics在硅谷成立。公司创始人是一群来自斯坦福大学的工程师,他们看到了闪存技术在便携式设备中的巨大潜力。

发展:Galaxy Microelectronics的初创团队专注于研发高性能、低功耗的NAND闪存芯片。他们成功开发出了一种创新的电荷撷取闪存(CTF)技术,这项技术有效解决了当时浮栅架构的串扰问题,使得闪存芯片的耐用性和速度大幅提升。这一创新迅速吸引了市场关注,公司开始获得风险投资的支持。

Daniel Woodhead公司的发展小趣事

随着公司业务的不断拓展,Daniel Woodhead公司意识到人才是企业发展的核心。因此,公司加大了对研发团队的投入,引进了一批业界顶尖的技术人才。这些人才的加入不仅为公司带来了更多的创新思路,还提高了整体的技术水平。在团队的共同努力下,公司不断推出具有竞争力的新产品,进一步巩固了市场地位。

酷宅(Coolkit)公司的发展小趣事

酷宅科技在智能家居市场的发展中,选择了电子电工和照明类市场作为切入点。这个市场具有巨大的智能化需求,但生产厂家众多,垄断程度低,利润率也相对较低。酷宅凭借其在物联网技术方面的优势,迅速满足了这一市场的迫切需求,并获得了巨大的出货量。随着市场的不断扩大,酷宅科技又进一步进入小家电市场,瞄准了加湿器、香薰机等长尾品类,继续扩大其市场份额。

达晶微(CREATEK)公司的发展小趣事

为了加强研发实力和应用能力,达晶微在上海设立了研发中心和应用中心。这些中心汇聚了来自全球的优秀人才和先进技术,为公司提供了强大的技术支持和创新动力。通过不断研发新产品和拓展新领域,达晶微在电子行业中保持了领先地位。

Bipolar Integrated Technology Inc公司的发展小趣事

面对日益严峻的环境问题,BIT积极响应可持续发展的号召。他们开始研发更加环保、节能的电子产品,并推动整个行业向绿色、低碳的方向发展。同时,BIT还加大了对人才培养和技术研发的投入,为公司的未来发展奠定了坚实的基础。

请注意,以上故事仅为虚构示例,旨在展示一个电子行业中公司可能的发展历程。在实际中,每个公司的发展都有其独特的轨迹和经历。

Crowd_Supply__Inc.公司的发展小趣事

与众不同的是,Crowd Supply Inc.采用了一种基于众包和预售的产品研发策略。他们在平台上发布项目概念和初步设计,通过社区的力量进行方案优化和功能迭代。这种模式不仅降低了产品开发成本,还使得产品更贴近用户需求。其中一款基于该策略开发的产品——一款高集成度的开源硬件开发板,在预售阶段就获得了大量订单,为公司带来了可观的收入。

问答坊 | AI 解惑

状态机资料

状态机资料的资料,设计例子加资料…

查看全部问答>

PMO与PDT

项目管理办公室(Project Management Office)是为让企业内共享项目管理的技能、经验等而建立的全公司的一个职能性组织。在企业中,它可能有各种各样的称谓,比如:产品线管理办(Product-line Management Office)、项目管理办、运作支撑部等等。 ...…

查看全部问答>

EVC下的Process.h问题

现在我要把一个VC下的控制台程序移植到EVC环境下,我装了EVC 4.0 , SP4 和Standard SDK,但还是发现没有Process.h和errno.h等一些C库函数,怎么解决这个问题呢?我从网上看到 说有人整理了这些文件,licence是LGPL的. LGPL是什么意思呢?我想最好能 ...…

查看全部问答>

请教一下CE下开发多语言程序的问题(MUI)

最近需要解决CE下开发多语言程序的问题 在论坛上找到一个相关的帖子,使用资源DLL实现的。 http://community.eeworld.net/Expert/TopicView3.asp?id=5679121 这个简单。 -- 我看CE的帮助文档里有MUI(Multilingual User Interface)的内容,应该 ...…

查看全部问答>

STM32:如何关联:“stm32f10x_vector.c”文件?

在 STM32 Firmware library 目录:...STM32F10xFWLibFWLibprojectRIDE  有一个stm32f10x_vector.c  文件, 这个 ..._vector.c  就是跟中断向量有关的吧。对于 Ride7  ...…

查看全部问答>

我的CAN模块程序 出现这样的错误 求高手解答啊!

我在调试LM3S9L97板子的Can模块时 系统一直提示identifier \"GPIO_PB4_CAN0RX\" is undefined 但是 我在上面已经声明了 #define PART_LM3S9L97#include \"driverlib/pin_map.h\"了啊   下面是我的can模块的初始化代码 SysCtlPeripheralEn ...…

查看全部问答>

单片机用汇编语言的问题

我做的项目本来用ATmega128去驱动SSD1289的屏幕时,使用的是UTFT的代码,结果显示速度不能令人满意。后来发现有人说使用汇编会快一些,后来证实了这个是正确的。 所以我想问,有没有会写关于I2C和SPI的汇编代码?这样能不能使得SD卡读写速度、I2C ...…

查看全部问答>

脉宽参数测量

       前阵子做了个脉宽参数测量仪,好像是12年的电赛题目。        做这个题我主要是基于STC12C5A60S2的硬件资源上折腾的。        首先峰值测量用的是单片机上十位AD,通过在某 ...…

查看全部问答>

最小系统板最后一步,JTAG接口的问题,求助啊

28027最小系统板,如图黄色高亮的地方,jtag接口的电源引脚要不要接到芯片上?? …

查看全部问答>

用protel铺铜问题

我用protel铺铜时如图所示,铜线都是呈十字架的形式和引脚链接,这种连接方式在功率器件上怕不能满足电流的需要,请大家指点如何设置使铺铜像过孔一样是包在一起的…

查看全部问答>