1.什么是GPIO?
General Purpose Input Output,即通用输入输出端口,简称GPIO
作用:通过IO口采集外部器件的“输入”信息或者“输出”控制外部器件工作,即输入输出
2.STM32 GPIO简介
(1)STM32 GPIO电气特性
(2)GPIO引脚分布
STM32引脚类型:
电源引脚、晶振引脚、复位引脚、下载引脚、BOOT引脚、GPIO引脚
(3)GPIO的八种模式
(4)GPIO寄存器介绍
GPIO通用寄存器GPIOX_yyy
MODER | OTYPER | OSPEEDR | PUPDR | IDR | ODR | BSRR | LCKR |
---|---|---|---|---|---|---|---|
设置模式 | 设置输出类型 | 设置输出速度 | 设置上下拉电阻 | 输入数据 | 输出数据 | 设置ODR寄存器值 | 配置锁定,用得不多 |
3.GPIO的HAL库函数
函数名 | 功能描述 |
---|---|
HAL_GPIO_Init() | GPIO引脚初始化 |
HAL_GPIO_DeInit() | GPIO引脚反初始化,恢复为复位后的状态 |
HAL_GPIO_WritePin() | 使引脚输出0或1 |
HAL_GPIO_ReadPin() | 读取引脚的输入电平 |
HAL_GPIO_TogglePin() | 翻转引脚的输出 |
HAL_GPIO_LockPin() | 锁定引脚配置,而不是锁定引脚的输入或输出值 |
4.GPIO使用硬件操作示例
(0)功能要求:
实现右按键按下,LED1灯翻转;左按键按下,LED2灯翻转;上按键按下,两灯同时翻转;下按键按下,蜂鸣器响灭。
(1)电路链接图
开发板有2个LED、4个按键和1个有源蜂鸣器,通过GPIO引脚控制。
-
LED电路:GPIO通过PF9 和 PF10 分别控制2个LED灯,设置为推挽输出。高电平,LED灭;低电平,LED亮;
-
按键电路:设置为输入模式。在按键按下时,输入PA0引脚为高电平,所以,引脚PA0在初始设置时应为:输入下拉;
另外3个按键,在按键按下时,引脚PE2,PE3,PE4为高电平,所以,引脚PE2,PE3,PE4在初始设置时应为:输入上拉;
-
蜂鸣器电路:蜂鸣器有PF8控制,设置为推挽输出。当PF8输出为0时,蜂鸣器响;为1时,蜂鸣器不响。
LED电路图
按键电路
蜂鸣器电路
(2)CUBEMX配置
打开CUBEMX软件:
配置下载引脚及时钟配置
下载方式设置:
外部时钟配置:选择外部晶振作为高低速时钟
配置GPIO输入输出引脚
用户标签 | 引脚名称 | 引脚功能 | GPIO模式 | 上下拉模式 |
---|---|---|---|---|
LED1 | FP9 | GPIO_Output | 推挽输出 | 无 |
LED2 | PF10 | GPIO_Output | 推挽输出 | 无 |
KeyRight | PE2 | GPIO_Input | 输入 | 上拉 |
KeyDown | PE3 | GPIO_Input | 输入 | 上拉 |
KeyLeft | PE4 | GPIO_Input | 输入 | 上拉 |
KeyUp | PA0 | GPIO_Input | 输入 | 下拉 |
Buzzer | PF8 | GPIO_Output | 推挽输出 | 上拉 |
设置引脚模式和用户标签:以PA0和 蜂鸣器PF8为例,其余以此类推
生成MDK的工程文件:
5.编写驱动程序
keyled.c 程序:
#include "keyled.h"
KEYS ScanPressedKey(uint32_t timeout)
{
uint32_t tickstart = HAL_GetTick();
const uint32_t btnDelay = 20;
while(1)
{
#ifdef KeyRight_Pin
if(HAL_GPIO_ReadPin(KeyRight_GPIO_Port,KeyRight_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(btnDelay);
if(HAL_GPIO_ReadPin(KeyRight_GPIO_Port,KeyRight_Pin) == GPIO_PIN_RESET)
return KEY_Right;
}
#endif
#ifdef KeyLeft_Pin
if(HAL_GPIO_ReadPin(KeyLeft_GPIO_Port,KeyLeft_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(btnDelay);
if(HAL_GPIO_ReadPin(KeyLeft_GPIO_Port,KeyLeft_Pin) == GPIO_PIN_RESET)
return KEY_Left;
}
#endif
#ifdef KeyDown_Pin
if(HAL_GPIO_ReadPin(KeyDown_GPIO_Port,KeyDown_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(btnDelay);
if(HAL_GPIO_ReadPin(KeyDown_GPIO_Port,KeyDown_Pin) == GPIO_PIN_RESET)
return KEY_Down;
}
#endif
#ifdef KeyUp_Pin
if(HAL_GPIO_ReadPin(KeyUp_GPIO_Port,KeyUp_Pin) == GPIO_PIN_SET)
{
HAL_Delay(btnDelay);
if(HAL_GPIO_ReadPin(KeyUp_GPIO_Port,KeyUp_Pin) == GPIO_PIN_SET)
return KEY_Up;
}
#endif
if(timeout != KEY_WAIT_ALWAYS)
{
if(HAL_GetTick() - tickstart > timeout)
{
break;
}
}
}
return KEY_NONE;
}
keyled.h 程序:
#include "main.h"
typedef enum{
KEY_Right = 0,
KEY_Left,
KEY_Down,
KEY_Up,
KEY_NONE,
}KEYS;
#define KEY_WAIT_ALWAYS 0
KEYS ScanPressedKey(uint32_t timeout);
#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_SET)
#define Buzzer_OFF() HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_RESET)
#endif
main.c 主程序
while (1)
{
KEYS curKey = ScanPressedKey(20);
switch(curKey)
{
case KEY_Right:
LED1_Toggle();
break;
case KEY_Left:
LED2_Toggle();
break;
case KEY_Down:
LED1_Toggle();
LED2_Toggle();
break;
case KEY_Up:
Buzzer_Toggle();
break;
default:
break;
}
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}