STM32F407ZG有8个16引脚的GPIO端口,从PA到PH,还有一个12引脚的PI端口,这些GPIO端口都链接在AHB1总线上,最高时钟频率可以达到168MHz(如下图时钟树),GPIO引脚能承受5V电压。
一个端口的16个GPIO引脚的功能可以单独配置,每个引脚的输入/输出数据可以单独读取或输出。一个GPIO引脚的内部结构如下图所示,其内部有双向保护二极管,有可配置的上拉或下拉电阻。每个GPIO引脚可以配置为多种工作模式。
根据数据表中列出的每个I/O端口的具体硬件特性,通用IO(GPIO)端口的每个端口位,可以通过软件在以下几种模式下单独配置:
输入模式
模拟模式
输出模式
复用功能模式
外部中断/事件线
在复位期间和刚好复位后,备用功能和外部中断线不活跃,I/O端口配置为输入浮点模式。 所有GPIO引脚都有微弱的内部上拉和下拉电阻,可以激活或不激活。 在输出或备用模式下,每个IO可以配置为开漏或推挽类型,IO速度可以根据VDD值选择。 所有端口都有外部中断/事件功能。要使用外部中断线,端口必须配置为输入模式。所有可用的GPIO引脚都连接到16个外部中断/事件线,从EXTI0到EXTI15。 外部中断/事件控制器由多达23个边缘检测器(16条线连接到GPIO)组成,用于生成事件/中断请求(每个输入线可以独立配置,以选择类型 ) 。(中断或事件)和相应的触发器事件(上升或下降或两者)。每行也可以被独立屏蔽。
从正点原子的原理图中,选择4个按键,2个LED灯作为本次实验的对象,用4个按键来控制2个LED灯实现不同功能的开关LED灯的效果。
下图所示是4个按键KEY对应的原理图,及相应的配置功能
名称 | 端口 | 引脚功能 | 特性 | 初始电平 |
---|---|---|---|---|
KEY_UP | PA0 | Input mode | Pull-down 下拉 | N/A |
KEY2 | PE2 | Input mode | Pull-up 上拉 | N/A |
KEY1 | PE3 | Input mode | Pull-up 上拉 | N/A |
KEY0 | PE4 | Input mode | Pull-up 上拉 | N/A |
Buzzer | PF8 | Output | Pushpull推挽输出, | 初始低电平 |
LED1 | PF9 | Output | Pushpull推挽输出, | 初始低电平 |
LED2 | PF10 | Output | Pushpull推挽输出, | 初始低电平 |
下面我们用STM32官方IDE(继承开发环境)–STM32CubeIDE来进行代码编写,编译和调试,它集成了STM32CubeMX配置工具和Eclipse集成开发环境,为开发人员提供了一个全面的工具套件来编写、编译和调试STM32微控制器的应用程序。2017年,为了取代被ARM公司Keil工具绑定,ST在当年收购Atollic公司,帮助其在原有的TrueStudio扩展到集编译、调试和仿真等于一体的集成开发环境,并完全面向用户免费,再配合其STM32CubeMX,可以达到从代码配置到调试等各个环节。
#include "main.h"
typedef enum {
KEY_0 = 0,
KEY_1,
KEY_2,
KEY_UP,
KEY_NONE,
} KEYS;
KEYS ScanPressedKey(uint32_t timeout);
#define KEY_WAIT_ALWAYS 0
#ifdef LED1_Pin
#define LED1_Toggle() HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin)
#define LED1_ON() HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET)
#endif
#ifdef LED2_Pin
#define LED2_Toggle() HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin)
#define LED2_ON() HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET)
#define LED2_OFF() HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET)
#endif
#ifdef Buzzer_Pin
#define Buzzer_Toggle() HAL_GPIO_TogglePin(Buzzer_GPIO_Port, Buzzer_Pin)
#define Buzzer_ON() HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET)
#define Buzzer_OFF() HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET)
#endif
#include "keyled.h"
/**
* Scans 4 keys in a polling fashion and returns the key value.
* timeout = 0 (ms) - If timeout = 0, it scans until a key is pressed.
*/
KEYS ScanPressedKey(uint32_t timeout)
{
KEYS key = KEY_NONE;
uint32_t tickstart = HAL_GetTick(); /* Get the Current time */
const uint32_t binDelay = 20; /* Delay time for Key shake off */
while (1)
{
#ifdef KEY0_Pin
if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
return KEY_0;
}
#endif
#ifdef KEY1_Pin
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
return KEY_1;
}
#endif
#ifdef KEY2_Pin
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET)
return KEY_2;
}
#endif
#ifdef KEY_UP_Pin
if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
{
HAL_Delay(binDelay);
if (HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_SET)
return KEY_UP;
}
#endif
if (timeout != KEY_WAIT_ALWAYS)
{
if ((HAL_GetTick() - tickstart) > timeout)
break;
}
}
return key;
}
添加头文件路径
添加C源文件路径
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
KEYS curKey = ScanPressedKey(KEY_WAIT_ALWAYS);
switch(curKey)
{
case KEY_0:
LED1_Toggle();
break;
case KEY_1:
LED2_Toggle();
break;
case KEY_2:
LED1_Toggle();
LED2_Toggle();
break;
case KEY_UP:
Buzzer_Toggle();
break;
default:
break;
}
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
基于以上可以实现用轮询Polling的方式实时检测,按下相应的按键点亮LED灯和关闭LED灯的功能。