本帖最后由 正点原子运营 于 2024-3-26 12:02 编辑
1)实验平台:正点原子 M144Z-M3 STM32F103最小系统板
2) 章节摘自【正点原子】M144Z-M3最小系统板使用指南——STM32F103版
3)购买链接:https://detail.tmall.com/item.htm?&id=609293737870
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boar ... _mini_sysboard.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子STM32技术交流QQ群:725095144
上一章中介绍了GPIO的输出模式,并用其控制LED的亮灭。在实际的应用尝尽中,还会需要使用到GPIO的输入模式,来获取外部的输入信号,例如获取按键的状态。通过本章的学习,读者将学习到GPIO作为输入模式的使用。 本章分为如下几个小节: 11.1 硬件设计 11.2 程序设计 11.3 下载验证
11.1 硬件设计 11.1.1 例程功能 1. 按下WKUP按键,LED0状态翻转。 2. 按下KEY0按键,LED1状态翻转。
11.1.2 硬件资源 1. LED LED0 - PB5 LED1 - PE5 2. 按键 WKUP - PA0 KEY0 - PE4
11.1.3 原理图 本章实验使用的两个M144Z-M3最小系统板STM32F103版板载按键,分别为KEY0按键和WKUP按键,其于板载MCU的连接原理图,如下图所示: 从上面的原理图中可以看出,WKUP按键和KEY0按键的一端连接到了电源正极,而另一端分别与MCU的PA0引脚和PE4引脚相连接,因此当任意一个按键被按下时,MCU对应的引脚都能够读取到高电平的状态,而当松开按键后,MCU对应的引脚读取到的电平状态却是是确定的,因此用于读取WKUP按键和KEY0按键的PA0引脚和PE4引脚不仅要配置为输入模式,还需要配置成下拉,使对应引脚在悬空时被下拉在电源负极。
11.2 程序设计 11.2.1 HAL库的GPIO驱动 本章实验中要通过读取GPIO引脚的输入状态来判断按键是否被按下,以此来控制对应LED的状态翻转,因此对于判断按键的状态,需要以下几个步骤: ①:配置GPIO引脚为输入模式和下拉 ②:读取GPIO引脚的输入状态 在HAL库中对应的驱动函数如下: ①:配置GPIO引脚 请见第10.2.1小节中配置GPIO引脚的相关内容。 ②:读取GPIO引脚输入电平 该函数用于读取GPIO引脚的输入电平(高电平或低电平),其函数原型如下所示: GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 该函数的形参描述,如下表所示: 表11.2.1.1 函数HAL_GPIO_ReadPin()形参描述 该函数的返回值描述,如下表所示: 表11.2.1.2 函数HAL_GPIO_ReadPin()返回值描述 该函数的使用示例,如下所示: - #include"stm32f1xx_hal.h"
- void example_fun(void)
- {
- GPIO_PinState value;
-
- /* 读取PA0引脚输入电平 */
- value = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
-
- if (value == GPIO_PIN_SET)
- {
- /* Do something.*/
- }
- else
- {
- /* Do something.*/
- }
- }
复制代码
11.2.2按键驱动 按键驱动主要就是读取GPIO引脚的输入状态,以此判断按键是否被按下,本章实验中,按键的驱动代码包括key.c和key.h两个文件。 根据原理图可知,应当将PA0引脚和PA15引脚配置为输入模式和下拉,并在需要读取WKUP按键(KEY0按键)状态的时候,读取PA0引脚(PA15引脚)的输入电平,若读取到PA0引脚(PA15引脚)的输入电平为高电平,则说明WKUP按键(KEY0按键)被按下,反之,则说明WKUP按键(KEY0按键)没有被按下。 按键驱动中,对引脚的定义,如下所示: - #define WKUP_GPIO_PORT GPIOA
- #define WKUP_GPIO_PIN GPIO_PIN_15
- #define WKUP_GPIO_CLK_ENABLE() do { __HAL_RCC_GPIOA_CLK_ENABLE(); } while (0)
- #define KEY0_GPIO_PORT GPIOA
- #define KEY0_GPIO_PIN GPIO_PIN_0
- #define KEY0_GPIO_CLK_ENABLE() do { __HAL_RCC_GPIOA_CLK_ENABLE(); } while (0)
复制代码按键驱动中,操作引脚的定义,如下所示: - #define WKUP ( \
- (HAL_GPIO_ReadPin(WKUP_GPIO_PORT, WKUP_GPIO_PIN) == GPIO_PIN_RESET) ? \
- 0 : \
- 1)
- #define KEY0 ( \
- (HAL_GPIO_ReadPin(KEY0_GPIO_PORT, KEY0_GPIO_PIN) == GPIO_PIN_RESET) ? \
- 0 : \
- 1)
复制代码按键驱动中,按键的初始化函数,如下所示: - /**
- *@brief 初始化按键
- *@param 无
- *@retval 无
- */
- void key_init(void)
- {
- GPIO_InitTypeDef gpio_init_struct = {0};
-
- /* 使能GPIO端口时钟 */
- WKUP_GPIO_CLK_ENABLE();
- KEY0_GPIO_CLK_ENABLE();
-
- /* 配置WKUP控制引脚 */
- gpio_init_struct.Pin = WKUP_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_INPUT;
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_init_struct);
-
- /* 配置KEY0控制引脚 */
- gpio_init_struct.Pin = KEY0_GPIO_PIN;
- gpio_init_struct.Mode = GPIO_MODE_INPUT;
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_init_struct);
- }
复制代码按键的初始化函数中,使能了KEY0按键和WKUP按键对应引脚的GPIO端口时钟,并将其配置为输入模式和下拉。 按键的驱动中,扫描按键状态的函数,如下所示: - /**
- *@brief 扫描按键
- *@note 按键响应具有优先级:WKUP > KEY0
- *@param mode: 扫描模式
- *@arg 0: 不支持连续按
- *@arg 1: 支持连续按
- *@retval 按键键值
- *@arg NONE_PRES: 没有按键按下
- *@arg WKUP_PRES: WKUP按键按下
- *@arg KEY0_PRES: KEY0按键按下
- */
- uint8_t key_scan(uint8_t mode)
- {
- static uint8_t key_release = 1;
- uint8_t key_value = NONE_PRES;
-
- if (mode != 0)
- {
- key_release = 1;
- }
-
- if ((key_release == 1) && ((WKUP == 1) || (KEY0 == 1)))
- {
- delay_ms(10);
- key_release = 0;
-
- if (KEY0 == 1)
- {
- key_value = KEY0_PRES;
- }
-
- if (WKUP == 1)
- {
- key_value = WKUP_PRES;
- }
- }
- else if ((WKUP == 0) && (KEY0 == 0))
- {
- key_release = 1;
- }
-
- return key_value;
- }
复制代码以上函代码就实现了按键扫描,且具有按键消抖的功能。
11.2.3 实验应用代码 本章实验的应用代码,如下所示: - int main(void)
- {
- uint8_t key;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 配置时钟,72MHz */
- delay_init(72); /* 初始化延时 */
- usart_init(115200); /* 初始化串口 */
- led_init(); /* 初始化LED */
- key_init(); /* 初始化按键 */
-
- while (1)
- {
- key = key_scan(0); /* 扫描按键 */
-
- switch (key)
- {
- case WKUP_PRES: /* WKUP按键被按下 */
- {
- LED0_TOGGLE(); /* 翻转LED0状态 */
- break;
- }
- case KEY0_PRES: /* KEY0按键被按下 */
- {
- LED1_TOGGLE(); /* 翻转LED1状态 */
- break;
- }
- }
-
- delay_ms(10);
- }
- }
复制代码可以看到应用代码中,在初始化完LED和按键后,就进入了一个while循环,在循环中,每间隔10毫秒就调用key_scan()函数扫描以此按键的状态,如果扫描到KEY0按键或WKUP按键被按下,则反转对应LED的亮灭状态。
11.3 下载验证 在完成编译和烧录操作后,可以看到板子上的LED0和LED1默认是处于熄灭的状态,若此时按下并释放一次WKUP按键,则能够看到LED0的亮灭状态发生了一次翻转,同样的,若此时按下并释放一次KEY0按键,则能够看到LED1的亮灭状态发生了一次翻转,与预期的实验现象效果相符。 |