求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
要资料
 
追随技术信仰

随时听讲座
每天看新闻
 
 
STM32单片机自学教程
0.前言
1.STM32单片机入门
2.STM32开发C语言
3.STM32F1x系统架构
4.STM32单片机系统电路
5.STM32F1x的寄存器
6.STM32开发环境介绍
7.嵌入式开发常见概念简介
8.STM32开发方式(库函数)介绍
9. Keil5-MDK软件简介
10.创建MDK工程-寄存器版
11.创建MDK工程-基于自建库函数
12.STM32标准库简介
13.创建MDK工程-基于标准库版
14.GPIO简介
15.GPIO输入-按键检测
16.GPIO位带操作
17.RCC-STM32时钟配置
18.STM32中断系统概述
19.基本定时器
 

 
目录
 
第15章.GPIO输入-按键检测
来源:CSDN,作者:村里大明白
37 次浏览
4次  

本节我们学习一下GPIO的输入检测,按键检测是最常用最简单的输入检测场景。掌握了按键输入检测之后,其他的不同设备外设检测都是大同小异,触类旁通,我们更重要的是要学习这些工程开发思想和技巧。

15.1.硬件设计

15.1.1 硬件设计示意图

图15.1-1 硬件连接示意图

我们的硬件连接非常简单,PA1口接一个按键到GND,PB1控制LED灯的亮灭。我们要实现的程序现象就是,按下按键后LED灯状态进行反转,实现亮-灭控制。

15.1.2 机械按键问题

按键是机械的,在按下和松手的瞬间会伴随有一定时间的抖动,按键开关不会马上稳定接通或一下断开,使用按键时会产生图 15.1-2 中所示波浪信号,我们写程序的时候需要用软件消抖处理滤波。

图15.1-2 按键抖动说明

当然也可以设计硬件进行消抖,如果有硬件消抖,软件就不用再设计消抖处理。硬件消抖一般是利用RC电路的电容充放电特性来对抖动产生的电压毛刺进行滤波,简单示意图如图15.1-3.

图15.1-3 硬件消抖

15.2 软件设计

15.2.1 工程文件创建

目前设计的软件,要更加注重的是可移植性,所以很多软件设计里有很多封装,有很多“层层套娃”等,目的是为了软件的可移植性可重用性。一些硬件的改动,仅仅需要软件配置上做一定适配,软件就能用,减少开发周期和成本。

我们利用以前的工程模版,再新建2个文件夹,“BSP”(即板级支持包)和“SrcLibrary”,分别存放板子的驱动函数和工程服务函数(这个可以按自己习惯来,文件夹命名不同人有不同的风格),工程里也对应新建2个组。如图15.2-1。

图15.2-1 工程创建示意图

我们一个开发板可能有很多外设,一般每个外设我们都需要写驱动服务函数,即2个文件,.h和.C。.h一般是.C文件需要被外部调用的变量和函数的声明,以及软件和硬件配置相关内容;.C文件主要是一些和外设相关的过程实现函数。如上图,我们本次需要用到LED和按键Key两个外设,在BSP中我们对应建立了2个外设对应的.c和.h文件。工程文件的建立过程前面多次讲过,这里就略过。

“SrcLibrary”文件夹里我们放了“Delay”函数,因为本次编程中用到延时相关的内容,这里我们直接拿过来用即可。后面我们还会介绍。这里也提一下,我们开发时要善于用别人已经开发好的函数,这样可以大大提高开发速度,有些函数我们知道怎么去构建,但有时候确实非常耗费时间。也有些函数我们也没必要去深究,我一直秉承一个思想,当今世界知识爆炸,需要你去学的东西太多了,每一项你都要去深究学习,是不对的,要有的放矢,该放下的就放下,“学海无涯,人生苦短,点到即止”。当然对于你从事的专业工作,那肯定还是要深入研究,这个不要太死板。

15.2.2 LED相关程序设计

为方便以后移植,我们建立LED.h文件,对LED使用的端口,是高电平点亮还是低电平点亮等方式进行配置。这样即便后续硬件有更改,那么我们只用修改.h文件里的配置信息即可。当项目非常大时,这些差异化的配置,我们也可以统一放到一个.h文件中,如建立一个user_config.h,把所有需要特殊配置的内容都放在这里面。现在开发,这些配置都是可以通过工具自动生成的,都无需人工代码,现在项目开发有完备的工具链,你只需要在开发界面里选择好你的设置内容,代码自动生成。

LED.h的代码如下:

  1. #ifndef __LED_H
  2. #define __LED_H
  3. #include "stm32f10x.h"
  4. /* LED连接的GPIO端口配置, 用户只需要修改下面的代码即可改变控制的LED引脚 */
  5. #define LED_GPIO_PORT GPIOB /* GPIO端口 */
  6. #define LED_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
  7. #define LED_GPIO_PIN GPIO_Pin_1 /* GPIO -pin*/
  8. /** 定义LED亮灭对应的高低电平,根据硬件设计可修改
  9. * 1 - off
  10. * 0 - on
  11. */
  12. #define LED_ON 0
  13. #define LED_OFF 1
  14. void LED_Init(void);//LED端口初始化
  15. void LED_Toggle(void);//LED灯反转
  16. #endif

代码中对LED的亮灭也进行了定义,这样做有两个好处:一是更加形象,编程的时候一看便知是什么意思;二是方便程序移植,如果其他硬件配置的高低电平点亮方式和软件设计的不同,那么我们只需要修改一下这个配置即可,无需再修改主代码。这段代码除了LED相关的硬件配置,还声明了2个函数,分别是LED端口的初始化函数和LED灯反转的函数,这2个函数需要在LED.c文件中实现。LED.c文件代码如下:

  1. #include "stm32f10x.h" // Device header
  2. #include "LED.h"
  3. //LED端口初始化函数
  4. void LED_Init(void)
  5. {
  6. /*定义一个GPIO_InitTypeDef类型的结构体*/
  7. GPIO_InitTypeDef GPIO_InitStructure;
  8. /*开启LED相关的GPIO外设时钟*/
  9. RCC_APB2PeriphClockCmd(LED_GPIO_CLK, ENABLE);
  10. /*选择要控制的GPIO引脚*/
  11. GPIO_InitStructure.GPIO_Pin = LED_GPIO_PIN;
  12. /*设置引脚模式为通用推挽输出*/
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
  14. /*设置引脚速率为50MHz */
  15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  16. /*调用库函数,初始化GPIO*/
  17. GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
  18. }
  19. //LED端口反转函数
  20. void LED_Toggle(void)
  21. {
  22. if (GPIO_ReadOutputDataBit(LED_GPIO_PORT, LED_GPIO_PIN) == LED_ON)
  23. {
  24. GPIO_SetBits(LED_GPIO_PORT, LED_GPIO_PIN);
  25. }
  26. else
  27. {
  28. GPIO_ResetBits(LED_GPIO_PORT, LED_GPIO_PIN);
  29. }
  30. }
  31. /*注:LED的端口反转函数,还可以这样写,就是靠操作端口输出寄存器ODR的值,异或位运算^=可以反转IO口
  32. void LED_Toggle(void)
  33. {
  34. LED_GPIO_PORT->ODR ^=LED_GPIO_PIN;//输出反转状态
  35. }
  36. */

初始化函数我们就不讲了,步骤都是固定的,开启时钟,配置模式和速率,这里模式我们选择推挽输出 。

LED的反转函数LED_Toggle,我们用到了标准库函数GPIO_ReadOutputDataBit,这个函数是读取端口指定pin的输出状态。不清楚的可以再翻看前面《第14章GPIO简介》中库函数的介绍。我们采用的实现方式是最直观的好理解的一种方式,同时我们也提供了另外一个方式,就是通过对GPIO数据输出寄存器ODR的指定位进行异或操作,将对应PIn反转:

LED_GPIO_PORT->ODR ^=LED_GPIO_PIN

这个在《第2章.STM32开发C语言常用知识点》中有介绍,有需要的可以再翻看一下。

15.2.3 按键检测程序设计

和前面LED类似,在.h文件中进行硬件相关配置和实现函数的声明。

  1. #ifndef __KEY_H
  2. #define __KEY_H
  3. #include "stm32f10x.h"
  4. // 引脚定义
  5. #define KEY_GPIO_CLK RCC_APB2Periph_GPIOA
  6. #define KEY_GPIO_PORT GPIOA
  7. #define KEY_GPIO_PIN GPIO_Pin_1
  8. /** 按键按下标置宏
  9. * 按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0
  10. * 若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1
  11. */
  12. #define KEY_ON 0
  13. #define KEY_OFF 1
  14. void Key_Init(void);
  15. uint8_t Key_State(void);
  16. #endif

Key.c需要中需要设计2个函数,分别是初始化函数和按键是否按下的检测函数,代码如下:

  1. #include "stm32f10x.h" // Device header
  2. #include "Key.h"
  3. #include "Delay.h"
  4. //按键端口初始化
  5. void Key_Init(void)
  6. {
  7. GPIO_InitTypeDef GPIO_InitStructure;
  8. RCC_APB2PeriphClockCmd(KEY_GPIO_CLK, ENABLE);
  9. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
  10. GPIO_InitStructure.GPIO_Pin = KEY_GPIO_PIN;
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12. GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStructure);
  13. }
  14. //获取按键的状态,是否被按下
  15. uint8_t Key_State(void)
  16. {
  17. /*检测是否有按键按下 */
  18. if(GPIO_ReadInputDataBit(KEY_GPIO_PORT,KEY_GPIO_PIN) == KEY_ON )
  19. {
  20. Delay_ms(20);//消抖
  21. /*等待按键释放 */
  22. while(GPIO_ReadInputDataBit(KEY_GPIO_PORT,KEY_GPIO_PIN) == KEY_ON);
  23. Delay_ms(20);//消抖
  24. return KEY_ON;
  25. }
  26. else
  27. {
  28. return KEY_OFF;
  29. }
  30. }

初始化函数我们这里设置为上拉输入模式。按键检测函数Key_State函数中用到了对GPIO数据输入寄存器IDR指定pin口的数据读取函数GPIO_ReadInputDataBit,用法和前面得GPIO_ReadOutputDataBit一样,有2个参数,分别是端口GPIOX和对应pin口。按键检测中需要Delay函数延时20ms进行消抖处理,两处消抖对应我们上节画的那个示意图。

15.2.4 主函数设计

主函数main.c的设计就非常简单了,首先是对硬件LED和KEY对应GPIO口初始化,然后就是检测按键是否按下,如果按下就反转LED灯的状态,代码如下:

  1. #include "stm32f10x.h" // Device header
  2. #include "Delay.h"
  3. #include "LED.h"
  4. #include "Key.h"
  5. int main(void)
  6. {
  7. /* LED端口初始化 */
  8. LED_Init();
  9. /* 按键端口初始化 */
  10. Key_Init();
  11. /* 轮询按键状态,若按键按下则反转LED */
  12. while(1)
  13. {
  14. if( Key_State()== KEY_ON)
  15. {
  16. /*LED反转*/
  17. LED_Toggle();
  18. }
  19. }
  20. }

资源已经上传

15.3 触类旁通

前面是最简单的一个输入检测和输出控制的实例,掌握了这个实例,我们用STM32可做的事就非常多了,无非是输入的硬件和输出控制的硬件的变化,但操作方式是一模一样的。比如输入硬件可以换成光敏元器件,根据亮度的不同会反馈高低电平,我们可以根据这个高低电平控制灯的亮灭,例如我们常见的日控灯。也可以将输入器件换成烟雾检测器件,输出变成蜂鸣器,检测到烟雾检测器件输入的信号,就给蜂鸣器高低电平实现鸣叫。在后面时钟章节,我们可以做一个类似的实验。


您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码: 验证码,看不清楚?请点击刷新验证码 必填



37 次浏览
4次