STM32学习·HAL库速通篇(四)·GPIO输出与点灯实验

目录
1. GPIO 概述
GPIO(General Purpose Input Output)即通用输入输出端口,是 STM32 芯片可直接控制的引脚。通过将 GPIO 引脚与外部设备连接,可实现与外部设备的通讯、控制及数据采集等功能。所有 GPIO 引脚均具备基本的输入和输出能力:
| 功能类型 | 原理 | 核心作用 | 典型应用 |
| 输出 | 由 STM32 控制引脚输出高、低电平,实现开关控制 | 控制外部设备通断 / 状态 | LED 驱动、继电器 / 三极管控制 |
| 输入 | 检测外部输入的电平信号,通过电平高低区分不同状态。 | 检测外部电平 / 状态 | 按键检测、传感器信号采集 |
本章只介绍GPIO输出功能,详细可以参考:
2. 原理图
本章就需要三颗LED灯,我们开发板上3颗LED灯原理图如下:

3. 工程创建
创建工程可以参考:
STM32学习·HAL库速通篇(三)·如何在STM32CubeMX新建工程_stm32cubemx 配置cmsis库-CSDN博客
这里我们在此基础上进行修改,找到.ioc文件:

双击打开配置界面:

在右下角搜索相关引脚:

分别找到原理图示的三个引脚,将其配置成输出模式:

找到图示位置对引脚进行相关配置:


根据上图每个引脚都配置一下:

然后重新生成代码,找到gpio.c文件:

其中声明代码如下:
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, LED_G_Pin|LED_B_Pin|LED_R_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PBPin PBPin PBPin */
GPIO_InitStruct.Pin = LED_G_Pin|LED_B_Pin|LED_R_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
此时下载代码可以发现三个LED灯全部电亮。
4. 基础延时设置流水灯
延时(Delay)简单来说,就是让 STM32 芯片在执行完某一条 / 某一段指令后,暂停(等待)指定的时间,再继续执行后面的代码。
在 GPIO 应用中,延时是最常用的基础功能之一 ,比如控制 LED 灯闪烁时,需要让 LED 亮 1 秒、灭 1 秒,这个 “1 秒的等待” 就是通过延时实现的。
4.1 函数介绍
为了实现流水灯的功能,这里需要使用两个函数,其一设置 / 清除指定 GPIO 引脚的电平状态函数:
/**
* @brief 设置或清除选定的数据端口位。
*
* @note 该函数使用 GPIOx_BSRR 寄存器实现原子化的读/修改操作,
* 这样可以避免在读取和修改操作之间触发中断(IRQ)而导致的操作异常。
*
* @param GPIOx: 其中 x 可以是(根据所用器件而定,可选 A..G),用于选择 GPIO 外设
* @param GPIO_Pin: 指定要写入的端口位。
* 该参数可以是 GPIO_PIN_x 中的一个值,其中 x 可以是(0..15)。
* @param PinState: 指定要写入到选定端口位的值。
* 该参数可以是 GPIO_PinState 枚举类型的取值之一:
* @arg GPIO_PIN_RESET: 清除该端口位(置低电平)
* @arg GPIO_PIN_SET: 设置该端口位(置高电平)
* @retval 无
*/
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
/* 检查参数合法性 */
assert_param(IS_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_PIN_ACTION(PinState));
if (PinState != GPIO_PIN_RESET)
{
GPIOx->BSRR = GPIO_Pin; // 设置指定端口位(置1)
}
else
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u; // 清除指定端口位(置0)
}
}
其核心实现是利用 BSRR 寄存器的高低 16 位分别控制 “置高 / 置低”,避免中断干扰。
另一个是延时函数:
/**
* @brief 该函数通过变量自增的方式提供以毫秒为单位的最小延时。
* @note 在默认实现中,SysTick定时器是时间基准的来源。
* 它用于按固定时间间隔产生中断,在中断中uwTick变量会自增。
* @note 该函数被声明为__weak(弱定义),以便在用户文件中实现其他方案时可以重写此函数。
* @param Delay 指定延时的时长,单位为毫秒。
* @retval 无
*/
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick(); // 记录延时开始时的系统滴答值
uint32_t wait = Delay; // 待等待的延时时长
/* 增加一个频率值以保证最小等待时间(避免因中断时序导致延时不足) */
if (wait < HAL_MAX_DELAY)
{
wait += (uint32_t)(uwTickFreq);
}
/* 循环等待,直到达到指定的延时时长 */
while ((HAL_GetTick() - tickstart) < wait)
{
}
}
其中:
| 英文术语 | 中文译法 | 补充说明 |
| SysTick timer | SysTick 定时器 | STM32 内核自带的系统滴答定时器 |
| time base | 时间基准 | 提供统一时间参考的基础信号 |
| __weak | 弱定义 | C 语言特性,允许用户重定义同名函数 |
| uwTick | 系统滴答计数器 | HAL 库核心的毫秒级计时变量 |
| uwTickFreq | 系统滴答频率 | uwTick 的递增频率(默认 1kHz,即 1ms 递增 1) |
| HAL_MAX_DELAY | HAL 最大延时值 | HAL 库定义的延时上限(通常为 uint32_t 最大值) |
4.2 代码编写
来到主函数,我们下面实现三颗灯珠依次点亮,主要更改主函数代码:
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)
{
HAL_GPIO_WritePin(GPIOB, LED_G_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LED_B_Pin|LED_R_Pin, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOB, LED_B_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LED_G_Pin|LED_R_Pin, GPIO_PIN_SET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOB, LED_R_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, LED_G_Pin|LED_B_Pin, GPIO_PIN_SET);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}

观察实验可以发现,LED灯每隔500ms依次点亮(文章无法放视频,这里就不演示实验想象了)。
完整工程:


更多推荐
所有评论(0)