文章目录
- 一、STM32F4 IO 口简介
- 二、硬件设计
- 三、软件设计
- 四、实验现象
- 五、STM32CubeMX 配置 IO 口输出
这一章,我们将通过
ALIENTEK
阿波罗
STM32
开发板上载有的 4 个按钮(
KEY_UP
、
KEY0
、
KEY1
和
KEY2
),来控制板上的 2 个
LED
(
DS0
和
DS1
),其中
KEY_UP
控制
DS0
,
DS1
互斥点亮;
KEY2
控制
DS0
,按一次亮,再按一次灭;
KEY1
控制
DS1
,效果同
KEY2
;
KEY0
则同时控制
DS0
和
DS1
,按一次,他们的状态就翻转一次。
一、STM32F4 IO 口简介
这部分内容可参考STM32F4 | GPIO工作原理和配置。STM32F4
的 IO
口做输入使用的时候,是通过调用函数 HAL_GPIO_ReadPin ()
来读取 IO
口的状态的。
二、硬件设计
本实验用到的硬件资源有:
- 指示灯
DS0
、DS1
。 - 4 个按键:
KEY0
、KEY1
、KEY2
、和KEY_UP
。
在阿波罗 STM32
开发板上的按键 KEY0
连接在 PH3
上、KEY1
连接在 PH2
上、KEY2
连接在 PC13
上、KEY_UP
连接在 PA0
上。如图所示:
这里需要注意的是:KEY0
、KEY1
和 KEY2
是低电平有效的(按下是低电平),而 KEY_UP
是高电平有效的(按下是高电平),并且外部都没有上下拉电阻,所以,需要在 STM32F429
内部设置上下拉。输入模式配置如下:
PH3
:上拉输入PH2
:上拉输入PC13
:上拉输入PA0
:下拉输入
三、软件设计
我们直接复制上一个实验的工程模板,将复制过来的模板文件夹重新命名为“2-按键实验”。在HARDWARE->LED
文件夹下面新建key.c
文件以及头文件 key.h
。
打开key.c
文件,代码如下:
#include "key.h"
#include "delay.h"
/*
函数名称:KEY_Init
函数功能:初始化按键输入实验所用到的IO口
输 入:无
输 出:无
*/
void KEY_Init(void)
{
//定义结构体变量
GPIO_InitTypeDef GPIO_Initure;
//使能按键对应IO口的时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
//初始化IO口;H2和H3是上拉输入,C13是上拉输入;A0是下拉输入
//初始化GPIOA
GPIO_Initure.Pin = GPIO_PIN_0; //PA0
GPIO_Initure.Mode = GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull = GPIO_PULLDOWN; //下拉
GPIO_Initure.Speed = GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
//初始化GPIOC
GPIO_Initure.Pin = GPIO_PIN_13; //PC13
GPIO_Initure.Mode = GPIO_MODE_INPUT; //输入
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOC,&GPIO_Initure);
//初始化GPIOH
//由于GPIOH与GPIOC的Mode、Pull、Speed配置一样,因此可以省略
GPIO_Initure.Pin = GPIO_PIN_2 | GPIO_PIN_3; //PH2,PH3
HAL_GPIO_Init(GPIOH,&GPIO_Initure);
}
/*
函数名称:KEY_Scan
函数功能:按键处理函数
输 入:mode:0,表示不支持连续按;mode:1,表示支持连续按
输 出:0,表示没有任何按键按下;...
注意:此函数有响应优先级,KEY0>KEY1>KEY2>KEY_UP
*/
u8 KEY_Scan(u8 mode)
{
static u8 key_up = 1; //按键松开标志
if (mode==1) key_up=1; //支持连按
if (key_up && (KEY0==0 || KEY1==0 || KEY2==0 || KEY_UP==1))
{
delay_ms(10); //延时
key_up=0; //标记这次key已经按下
if (KEY0==0) return KEY0_PRES;
else if (KEY1==0) return KEY1_PRES;
else if (KEY2==0) return KEY2_PRES;
else if (KEY_UP==1) return KEYUP_PRES;
}
//KEY键没有按下
else if (KEY0==1 || KEY1==1 || KEY2==1 || KEY_UP==0)
{
key_up=1;
}
return 0; //无按键按下
}
KEY_Scan
函数,则是用来扫描这 4 个 IO
口是否有按键按下。KEY_Scan
函数,支持两种扫描方式,通过 mode
参数来设置。
- 当
mode
为 0 的时候,KEY_Scan
函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候比较不合适。 - 当
mode
为 1 的时候,KEY_Scan
函数将支持连续按,如果某个按键一直按下,则会一直返回这个按键的键值,这样可以方便的实现长按检测。
其头文件key.h
为:
#ifndef _KEY_H
#define _KEY_H
#include "sys.h"
//STM32F4的IO口做输入使用的时候,是通过调用函数HAL_GPIO_ReadPin ()来读取 IO口的状态的
#define KEY0 HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_3) //KEY0 按键 PH3
#define KEY1 HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2) //KEY1 按键 PH2
#define KEY2 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) //KEY2 按键 PC13
#define KEY_UP HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) //WKUP 按键 PA0
//宏定义独立按键按下的值
#define KEY0_PRES 1
#define KEY1_PRES 2
#define KEY2_PRES 3
#define KEYUP_PRES 4
//声明函数
void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif
打开主函数main.c
,代码如下:
/*
实验2:按键输入实验
实验现象:`KEY_UP` 控制 `DS0`,`DS1` 互斥点亮;`KEY2` 控制 `DS0`,按一次亮,再按一次灭;`KEY1` 控制 `DS1`,效果同 `KEY2`;`KEY0` 则同时控制 `DS0` 和 `DS1`,按一次,他们的状态就翻转一次。
*/
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
int main(void)
{
u8 key;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟180MHz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
while (1)
{
key = KEY_Scan(0); //单次按键扫描
switch (key)
{
case KEYUP_PRES: //控制 LED0,LED1 互斥点亮
LED1=!LED1;
LED0=!LED0;
break;
case KEY2_PRES: //控制 LED0 翻转
LED0=!LED0;
break;
case KEY1_PRES: //控制 LED1 翻转
LED1=!LED1;
break;
case KEY0_PRES: //同时控制 LED0,LED1 翻转
LED1=!LED1;
LED0=!LED0;
break;
}
delay_ms(10);
}
}
四、实验现象
使用 USB
线将开发板和电脑连接成功后(电脑能识别开发板上 CH340
串口),把编译后产生的.hex
文件烧入到芯片内。
实验现象:KEY_UP
控制 DS0
,DS1
互斥点亮;KEY2
控制 DS0
,按一次亮,再按一次灭;KEY1
控制 DS1
,效果同 KEY2
;KEY0
则同时控制 DS0
和 DS1
,按一次,他们的状态就翻转一次。
-
按下
KEY1
-
按下
KEY2
-
按下
KEY0
-
按下
KEY_UP
五、STM32CubeMX 配置 IO 口输出
阿波罗开发板上有 4 个按键,分别连接四个 IO 口 PA0
,PC13
,PH2
和 PH3
。其中 WK_UP
按键按下后对应的 PA0
输入为高电平,所以默认情况下,该 IO
口(PA0
)要初始化为下拉输入,其他 IO
口初始化为上拉输入即可。
使用 STM32CubeMX
打开光盘工程模板(双击工程目录的 Template.ioc
),我们首先在 IO
口引脚图上,依次设置四个 IO
口为输入模式 GPIO_Input
。这里我们以 PA0
为例,操作方法如下图所示:
同样的方法,我们依次配置 PC13
, PH2
和 PH3
为输入模式。然后我们进入Configuration->GPIO
配置界面,配置四个 IO
口详细参数。在配置界面点击 PA0
可以发现,当我们在前面设置 IO
口为输入 GPIO_Input
之后,其配置参数只剩下模式 GPIO Mode
和上下拉GPIO Pull-up/Pull-down
,并且模式值中只有输入模式 Input Mode
可选。这里,我们配置 PA0
为下拉输入,其他三个 IO
口配置为上拉输入即可。配置方法如下图所示:
配置完成 IO
口参数之后,接下来我们同样生成工程。打开生成的工程会发现,main.c
文件中添加了函数 MX_GPIO_Init
函数,内容如下:
/** Configure pins as
* Analog
* Input
* Output
* EVENT_OUT
* EXTI
*/
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PH2 PH3 */
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
}
该函数实现的功能和按键输入实验中 KEY_Init
函数实现的功能一模一样。将该函数内容替换按键输入实验中的 KEY_Init
函数内容,替换后会发现实现现象完全一致