目录
1、开发板
开发板使用的是野火STM32F103RCT6min开发板
2、目的
使用HAL库,实现流水灯,KEY1控制流水灯的开始和暂停,KEY2控制流水灯的方向,初始化默认所有灯熄灭
3、代码
按键中断代码
KEY_EXTI.c
#include "./EXTI/KEY_EXTI.h"
extern uint8_t led_running;
extern uint8_t led_direction;
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启按键GPIO口的时钟*/
KEY1_INT_GPIO_CLK_ENABLE();
KEY2_INT_GPIO_CLK_ENABLE();
/* 选择按键1的引脚 */
GPIO_InitStructure.Pin = KEY1_INT_GPIO_PIN;
/* 设置引脚为输入模式 */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
/* 设置引脚不上拉也不下拉 */
GPIO_InitStructure.Pull = GPIO_NOPULL;
/* 使用上面的结构体初始化按键 */
HAL_GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/
HAL_NVIC_SetPriority(KEY1_INT_EXTI_IRQ, 0, 0);
/* 使能中断 */
HAL_NVIC_EnableIRQ(KEY1_INT_EXTI_IRQ);
/* 选择按键2的引脚 */
GPIO_InitStructure.Pin = KEY2_INT_GPIO_PIN;
/* 其他配置与上面相同 */
HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
/* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/
HAL_NVIC_SetPriority(KEY2_INT_EXTI_IRQ, 0, 0);
/* 使能中断 */
HAL_NVIC_EnableIRQ(KEY2_INT_EXTI_IRQ);
}
void EXTI0_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); // 清除中断标志
led_running = !led_running; // 切换开始/暂停状态
}
}
void EXTI15_10_IRQHandler(void)
{
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13); // 清除中断标志
led_direction = !led_direction; // 切换方向
}
}
KEY_EXTI.h
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f1xx.h"
//引脚定义
/*******************************************************/
#define KEY1_INT_GPIO_PORT GPIOA
#define KEY1_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE();
#define KEY1_INT_GPIO_PIN GPIO_PIN_0
#define KEY1_INT_EXTI_IRQ EXTI0_IRQn
#define KEY2_INT_GPIO_PORT GPIOC
#define KEY2_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE();
#define KEY2_INT_GPIO_PIN GPIO_PIN_13
#define KEY2_INT_EXTI_IRQ EXTI15_10_IRQn
/*******************************************************/
void EXTI_Key_Config(void);
#endif /* __EXTI_H */
流水灯代码
bsp_led.h
#ifndef __LED_H
#define __LED_H
#include "stm32f1xx.h"
#define LED_GPIO_PORT GPIOC
#define LED3_PIN GPIO_PIN_4
#define LED4_PIN GPIO_PIN_5
#define LED5_PIN GPIO_PIN_6
#define LED6_PIN GPIO_PIN_7
#define LED7_PIN GPIO_PIN_8
extern uint8_t led_running;
extern uint8_t led_direction;
void LED_Init(void);
void LED_Show(uint8_t index);
void TIM3_Init(uint16_t period);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
#endif /* __LED_H */
bsp_led.c
#include "./led/bsp_led.h"
TIM_HandleTypeDef htim3;
// 内部状态变量
uint8_t led_index = 0; // 当前点亮第几个灯
uint8_t led_running = 0; // 默认暂停
uint8_t led_direction = 0; // 方向,0为向右,1为向左
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct ; // 定义 GPIO 初始化结构体
__HAL_RCC_GPIOC_CLK_ENABLE(); // 使能 GPIOC 端口时钟
// 设置 PC4~PC8(LED3~LED7)为推挽输出,无上拉下拉,中速
GPIO_InitStruct.Pin = LED3_PIN | LED4_PIN | LED5_PIN | LED6_PIN | LED7_PIN; // 这几个宏定义应在 led.h 中定义为 GPIO_PIN_4~GPIO_PIN_8
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式
GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上拉下拉
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; // 中速输出
HAL_GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); // 初始化 GPIOC 的这几个引脚
// 初始时将所有 LED 熄灭(假设高电平熄灭,低电平点亮)
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8, GPIO_PIN_SET);
}
void LED_Show(uint8_t index)
{
// 将 5 个 LED 引脚保存到数组,便于用下标访问
uint16_t pins[5] = {LED3_PIN, LED4_PIN, LED5_PIN, LED6_PIN, LED7_PIN};
// 先将所有 LED 熄灭
for (int i = 0; i < 5; i++)
{
HAL_GPIO_WritePin(LED_GPIO_PORT, pins[i], GPIO_PIN_RESET); // 全部拉低(假设低电平熄灭)
}
// 如果 index 在 0~4 范围内,点亮对应编号的 LED
if (index < 5)
{
HAL_GPIO_WritePin(LED_GPIO_PORT, pins[index], GPIO_PIN_SET); // 指定引脚拉高,点亮
}
}
void TIM3_Init(uint16_t period)
{
__HAL_RCC_TIM3_CLK_ENABLE(); // 使能 TIM3 时钟
htim3.Instance = TIM3; // 选择使用的定时器是 TIM3
htim3.Init.Prescaler = 7200 - 1; // 设置预分频器,系统时钟72MHz / 7200 = 10kHz
htim3.Init.Period = period - 1; // 自动重装值,定时器计满周期为 period / 10ms
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
HAL_TIM_Base_Init(&htim3); // 初始化定时器
HAL_TIM_Base_Start_IT(&htim3); // 启动定时器并开启中断
HAL_NVIC_SetPriority(TIM3_IRQn, 1, 0); // 设置 TIM3 中断优先级为 1
HAL_NVIC_EnableIRQ(TIM3_IRQn); // 使能 TIM3 中断
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
// 判断是否是 TIM3 产生的中断,且 LED 状态为运行中
if (htim->Instance == TIM3 && led_running)
{
LED_Show(led_index); // 显示当前的 LED 灯
// 根据方向判断向左或向右移动
if (led_direction == 0) // 向右(编号增加)
{
led_index++; // 下一个灯编号
if (led_index >= 5) led_index = 0; // 超过4则回到0
}
else // 向左(编号减少)
{
if (led_index == 0) led_index = 4; // 如果当前是0,则跳转到最后一个
else led_index--; // 否则递减
}
}
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3); // 调用 HAL 库的 TIM3 中断处理函数
}
main.c程序中只需各个函数初始即可