【STM32F407VGT6】8.7HAL库按键点灯
本文介绍了基于STM32的GPIO控制实现方法,主要包含按键检测和LED控制功能。首先通过CUBEMX配置GPIO,使用HAL库函数实现GPIO状态读取(HAL_GPIO_ReadPin)、电平设置(HAL_GPIO_WritePin)和翻转(HAL_GPIO_TogglePin)等基础操作。文中提供了多个实验示例
·
一.CUBEMX配置GPIO

二.代码语句
(1)读取GPIO状态
HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_10) == GPIO_PIN_RESET
//读取GPIO状态,判断是否为高电平
(2)翻转小灯
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13);//小灯反转
(3)配置小灯高低电平
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET);//小灯高低电平设置
(5)利用标签配置引脚示例
给引脚打标签,无需通过引脚号定位引脚,可以通过标签定位
HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
(6)一次设置三小灯状态示例
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
三.实验
1.三个按键分别控制三个灯
(按PE10(KEY2)亮灯PE13,按PE11亮PE14,按PE12亮PE14)
/* USER CODE BEGIN PFP */
uint8_t key(uint16_t GPIO_Pin);//声明函数
/* USER CODE END PFP */
//检测按键是否(被按+松开)的函数
/* USER CODE BEGIN 4 */
uint8_t key(uint16_t GPIO_Pin)
{
if(HAL_GPIO_ReadPin(GPIOE, GPIO_Pin) == GPIO_PIN_RESET)//按键被按下
{
HAL_Delay(50); //延时防抖动
if(HAL_GPIO_ReadPin(GPIOE, GPIO_Pin) == GPIO_PIN_RESET)
{
while(HAL_GPIO_ReadPin(GPIOE, GPIO_Pin) == GPIO_PIN_RESET);
//按键持续被按,则在循环中,直到松开按键,返回1
return 1;
}
}
return 0;
}
/* USER CODE END 4 */
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
//主循环
if(key(GPIO_PIN_10))
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13);//翻转小灯
}
if(key(GPIO_PIN_11))
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_14);
}
if(key(GPIO_PIN_12))
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_15);
}
}
/* USER CODE END 3 */
2.一个按键循环打开三个灯
(PE10按一下PE13亮,再按PE14亮,再按PE15亮)
只修改主循环
/* USER CODE BEGIN PD */
uint8_t i=0;
//i声明成全局变量
/* USER CODE END PD */
if(key(GPIO_PIN_10))
{
i++;
}
switch(i)
{
case 1:
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14|GPIO_PIN_15,GPIO_PIN_SET);
break;
}
case 2:
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13|GPIO_PIN_15,GPIO_PIN_SET);
break;
}
case 3:
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13|GPIO_PIN_14,GPIO_PIN_SET);
i=0;
break;
}
}
}
/* USER CODE END 3 */
3.长按小灯亮起,松开灯灭
/* USER CODE BEGIN 3 */
HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin);
if( HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET);
}
}
/* USER CODE END 3 */
4.一个按键切换三种亮灯花样
if(key(GPIO_PIN_10))
{
i++;
}
switch(i)
{
case 1://流水灯
{
while(!(key(GPIO_PIN_10)==1))
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_SET);
HAL_Delay(100);
}
i++;
break;
}
case 2://14常亮,13、15轮流闪烁
{
while(!(key(GPIO_PIN_10)==1))
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13|GPIO_PIN_14,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_15,GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_14|GPIO_PIN_15,GPIO_PIN_RESET);
HAL_Delay(100);
}
i++;
break;
}
case 3://13、14轮流闪烁两下,15不亮
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15,GPIO_PIN_SET);
while(!(key(GPIO_PIN_10)==1))
{
uint8_t u;
for(u=0;u<3;u++)
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_13);
HAL_Delay(100);
}
for(u=0;u<3;u++)
{
HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_14);
HAL_Delay(100);
}
}
i++;
break;
}
case 4://全部熄灭
{
while(!(key(GPIO_PIN_10)==1))
{
HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15,GPIO_PIN_SET);
}
i=1;
break;
}
}
}
/* USER CODE END 3 */
(1)问题:
有时按按键以后小灯形式无变化。
while(!(key(GPIO_PIN_10)==1)) 循环,这个循环会持续阻塞程序,直到再次按下按键才会退出。
例如在 case 1 中,流水灯循环时,程序被卡在 while 里,此时即使按下按键,key() 函数虽然能检测到按键,但外层的 if(key(GPIO_PIN_10)) 根本没有机会执行(因为程序没跳出 while 循环)。
只有当 while 循环退出后(即再次按下按键),i 才会加 1,切换到下一个模式。
(2)解决:
/* USER CODE BEGIN 3 */
// 主循环中先检测按键,按下则切换模式
if(key(GPIO_PIN_10))
{
i++; // 每次按键按下,切换到下一个模式
if(i > 4) // 边界判断:超过最大模式则回到1
i = 1;
// 切换模式时,先关闭所有灯,避免状态残留
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
HAL_Delay(50); // 短暂延时,确保状态切换明显
}
// 根据当前模式执行对应逻辑(非阻塞,每次循环执行一次)
switch(i)
{
case 1:
{
static uint8_t flow_step = 0; // 静态变量记录流水灯步骤
static uint32_t flow_last_time = 0;
// 每隔100ms切换一次灯,避免用HAL_Delay阻塞
if(HAL_GetTick() - flow_last_time > 100)
{
flow_last_time = HAL_GetTick();
// 先关闭所有灯
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
// 按步骤点亮对应灯
switch(flow_step)
{
case 0: HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET); break;
case 1: HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET); break;
case 2: HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_RESET); break;
}
flow_step++;
if(flow_step >= 3)
flow_step = 0;
}
break;
}
case 2: // 14常亮,13、15轮流闪烁
{
static uint32_t blink_last_time = 0;
static uint8_t blink_state = 0;
// 14常亮
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
// 每隔100ms切换13和15的状态
if(HAL_GetTick() - blink_last_time > 100)
{
blink_last_time = HAL_GetTick();
blink_state = !blink_state;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, blink_state ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, blink_state ? GPIO_PIN_RESET : GPIO_PIN_SET);
}
break;
}
case 3: // 13、14轮流闪烁两下,15不亮
{
static uint8_t flash_step = 0;
static uint32_t flash_last_time = 0;
static uint8_t count = 0;
// 15始终不亮
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_15, GPIO_PIN_SET);
if(HAL_GetTick() - flash_last_time > 100)
{
flash_last_time = HAL_GetTick();
flash_step++;
if(flash_step % 2 == 1) // 奇数次:闪烁13
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
}
else // 偶数次:关闭13
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13, GPIO_PIN_SET);
if(count < 2) // 只闪烁2次
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_RESET);
count++;
}
else // 闪烁完成后重置计数
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_14, GPIO_PIN_SET);
count = 0;
flash_step = 0;
}
}
}
break;
}
case 4: // 全部熄灭
{
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
break;
}
}
/* USER CODE END 3 */
更多推荐



所有评论(0)