STM32 基于HAL库的LED流水灯

一、STM32CubeMX安装

(1)如果未安装 Java 环境,直接安装STM32CubeMX将会出现报错;

在这里插入图片描述

1.1下载Java

Java 官网下载
    下载地址: https://www.java.com/zh_CN/download/windows-64bit.jsp(尽量安装最新版 64 位的Java)
    下载方法:打开官网下载地址,点击 同意并开始免费下载;

在这里插入图片描述

(1)打开 jre-8u261-windows-x64.exe 安装包,勾选更改目标文件夹,点击 安装;
在这里插入图片描述

(2)选择合适的安装目录,点击 下一步;
在这里插入图片描述
(3)等待自动安装;
在这里插入图片描述

(4)安装完毕,点击 关闭;

在这里插入图片描述

1.2CubeMX 官网下载

1.下载地址: 官网下载地址 --> https://www.st.com/stm32cubemx
     下载方法:打开官网下载地址,点击 获取软件;

在这里插入图片描述
2.选择对应的版本进行下载。(需要登陆账号,其中 Linux 和 MacOS 的配置文件和 Windows 安装包在同一个文件中)

在这里插入图片描述
在这里插入图片描述

云盘下载
    下载地址:https://pan.baidu.com/s/1-7z6Q0Mlscaw8yiCZzfkug(提取码:5eby)
    下载方法:直接下载。(云盘收录了 STM32Cube 系列软件)

1.3CubeMX 安装

1.安装 Java 后,打开 SetupSTM32CubeMX-6.0.0.exe 文件,其他系统安装参考 Readme.html,点击 Next;
在这里插入图片描述
2.勾选 I accpt,点击 Next;
在这里插入图片描述
3.勾选第一个,点击 Next;
在这里插入图片描述

4.选择合适的安装路径,点击 Next;(若路径未创建,会提示路径将被创建);
在这里插入图片描述
在这里插入图片描述

5.根据需求勾选,点击 Next;

在这里插入图片描述
6程序自动安装,安装完成后,点击 Next;
在这里插入图片描述

7提示安装成功和一个卸载程序被创建在安装目录的 Uninstaller 文件夹中,点击 Done;

在这里插入图片描述

8打开 STM32CubeMX 软件;
在这里插入图片描述

9软件界面如下;

在这里插入图片描述

二、CubeMX项目创建

1.打开安装好的STMCubeMX
在这里插入图片描述

2.点击HLP->Manage embedded software
在这里插入图片描述
3.会跳出来一个选择型号界面 勾选上你要安装的HAL库, 点击“Install Now” 直到安装成功。 如下图:在这里插入图片描述

4回到STMCubeMX的主界面,创建新项目:(选择ACCESS TO MCU SELECTOR)
在这里插入图片描述
5.点击system core,进入SYS,在debug下选择serial wire:

在这里插入图片描述

6.配置时钟,进入上面的rcc,有两个时钟,一个是hse和lse,我们要用是GPIO接口,而这些接口都在APB2里:

在这里插入图片描述

7接下来观察时钟架构,APB2总线的时钟由hse控制,同时在这个界面得把PLLCLK右边选上:

在这里插入图片描述

8.将hse那里设为Crystal/Ceramic Resonator:
在这里插入图片描述
9.接下来就是点击相应的引脚设置输出寄存器了,就是output那一项,一共选了三个,是PA0 PA1 PA3 开关接PA15
在这里插入图片描述

在这里插入图片描述
10.点击project manager,配置好自己的路径和项目名,然后IDE那项改为MDK-ARM进入 code generate界面,选择生成初始化.c/.h文件,后面点击generate code,选择open project:在这里插入图片描述
11.打开.uvprojx文件(或者在上一步选择open project)
在这里插入图片描述

三、项目代码

STM32 LED控制程序功能分块说明

1. 头文件包含和宏定义部分

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"

功能说明

  • 包含必要的头文件
  • main.h:包含HAL库核心头文件和项目配置
  • gpio.h:包含GPIO外设的初始化函数声明

2. 全局变量定义部分

/* USER CODE BEGIN PV */
uint8_t led_mode = 0;      // 0:流水灯模式, 1:全亮模式, 2:全灭模式
uint8_t current_led = 0;   // 当前亮的LED索引
/* USER CODE END PV */

功能说明

  • led_mode:控制程序工作模式的状态变量
    • 0 = 流水灯模式(LED依次点亮)
    • 1 = 全亮模式(所有LED同时亮)
    • 2 = 全灭模式(所有LED同时灭)
  • current_led:记录流水灯模式下当前点亮的LED序号

3. 函数声明部分

/* USER CODE BEGIN PFP */
void LED_Flow_Mode(void);    // 流水灯模式控制函数
void LED_All_On(void);       // 全亮模式控制函数  
void LED_All_Off(void);      // 全灭模式控制函数
void Check_Switch(void);     // 开关检测函数
/* USER CODE END PFP */

功能说明

  • 声明所有自定义函数,便于编译器识别
  • 这些函数在主函数之前声明,确保调用时已被识别

4. 主函数初始化部分

/* USER CODE BEGIN 2 */
/* 初始状态:所有LED熄灭 */
LED_All_Off();
/* USER CODE END 2 */

功能说明

  • 系统初始化完成后执行的代码
  • 设置LED初始状态为全灭
  • 确保程序启动时所有LED处于可控状态

5. 主循环部分

/* USER CODE BEGIN WHILE */
while (1)
{
  /* 检测开关状态 */
  Check_Switch();
  
  /* 根据模式执行相应的LED控制 */
  switch(led_mode)
  {
    case 0:  // 流水灯模式
      LED_Flow_Mode();
      break;
      
    case 1:  // 全亮模式
      LED_All_On();
      HAL_Delay(100);  // 短延时,减少CPU占用
      break;
      
    case 2:  // 全灭模式
      LED_All_Off();
      HAL_Delay(100);  // 短延时,减少CPU占用
      break;
      
    default:
      led_mode = 0;
      break;
  }
/* USER CODE END WHILE */

功能说明

  • 无限循环:程序的主要执行部分
  • 模式检测:每次循环都检查开关状态
  • 模式切换:根据led_mode值执行不同的LED控制模式
  • 延时优化:在全亮/全灭模式中使用短延时减少CPU占用率

6. 开关检测函数

void Check_Switch(void)
{
  static uint32_t last_press_time = 0;
  static uint8_t last_switch_state = 1;  // 默认上拉为高电平
  
  uint8_t current_switch_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15);
  
  // 检测下降沿(开关按下)
  if(last_switch_state == 1 && current_switch_state == 0)
  {
    // 简单的按键消抖,检测时间间隔
    if(HAL_GetTick() - last_press_time > 200)  // 200ms消抖
    {
      led_mode = (led_mode + 1) % 3;  // 循环切换模式:0→1→2→0
      last_press_time = HAL_GetTick();
    }
  }
  
  last_switch_state = current_switch_state;
}

功能说明

  • 状态检测:读取PA15引脚的电平状态
  • 边沿检测:检测开关从高电平到低电平的跳变(按下动作)
  • 按键消抖:通过时间间隔判断,防止机械开关抖动导致的误触发
  • 模式切换:每次有效按键将led_mode循环递增(0→1→2→0)

7. 流水灯模式函数

void LED_Flow_Mode(void)
{
  static uint32_t last_change_time = 0;
  
  // 每1秒切换一次LED
  if(HAL_GetTick() - last_change_time >= 1000)
  {
    // 熄灭所有LED
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);   // PA0高电平,LED1灭
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);   // PA1高电平,LED2灭
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);   // PA3高电平,LED3灭
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  // PC13高电平,板载LED灭
    
    // 根据当前索引点亮对应的LED
    switch(current_led)
    {
      case 0:  // LED1亮
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
        break;
        
      case 1:  // LED2亮
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
        break;
        
      case 2:  // LED3亮
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
        break;
        
      case 3:  // 板载LED亮
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
        break;
    }
    
    // 更新LED索引
    current_led = (current_led + 1) % 4;
    last_change_time = HAL_GetTick();
  }
}

功能说明

  • 定时控制:使用系统滴答定时器实现1秒间隔
  • 循环点亮:按顺序依次点亮PA0→PA1→PA3→PC13
  • 状态保持:每个LED点亮1秒后切换到下一个
  • 索引管理:current_led变量记录当前点亮位置,循环0-3

8. 全亮模式函数

void LED_All_On(void)
{
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);   // PA0低电平,LED1亮
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);   // PA1低电平,LED2亮
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);   // PA3低电平,LED3亮
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);  // PC13低电平,板载LED亮
}

功能说明

  • 同时点亮:将所有LED引脚设置为低电平
  • 简单控制:无定时逻辑,持续保持全亮状态

9. 全灭模式函数

void LED_All_Off(void)
{
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);   // PA0高电平,LED1灭
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);   // PA1高电平,LED2灭
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);   // PA3高电平,LED3灭
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  // PC13高电平,板载LED灭
}

功能说明

  • 同时熄灭:将所有LED引脚设置为高电平
  • 初始状态:也用作程序的初始状态设置

程序工作流程总结

  1. 启动初始化 → 所有LED熄灭
  2. 主循环检测 → 持续检测开关状态
  3. 模式切换 → 按键触发模式循环切换
  4. LED控制 → 根据当前模式执行相应显示效果
  5. 状态保持 → 直到下一次按键改变模式

这个程序实现了完整的LED控制功能,通过物理开关可以在三种显示模式间切换,展示了STM32 HAL库的基本GPIO操作和状态机编程思想。

四、实践结果

mmexport1760022977844

proteus仿真

1.配置供电网
在这里插入图片描述
在这里插入图片描述

2.添加HEX文件
在这里插入图片描述
3.仿真图
在这里插入图片描述

STM32 LED控制实验总结与心得

实验总结

标题完成的功能

  • ✅ 控制4个LED灯(3个外接+1个板载)
  • ✅ 实现3种显示模式:流水灯、全亮、全灭-
  • ✅ 通过按键切换模式-
  • ✅ 用三种不同方法编程实现
  • 技术要点

    1. GPIO配置 - 输出控制LED,输入检测按键
    1. 时钟使能 - 使用外设前必须先开启时钟
    1. 按键消抖 - 200ms延时防止误触发
    1. 状态管理 - 用变量记录当前模式和LED状态

学习心得

  1. 编程方法的演进
  2. 寄存器方式 → 理解了硬件底层工作原理,知道每个配置位的含义标准库方式 → 学会了使用官方库函数,代码更规范
  3. HAL库方式 → 掌握了现代嵌入式开发流程,
  4. 效率最高

遇到的困难与解决

链接错误
因为启动文件缺失,学会检查项目结构- 按键抖动:通过软件消抖解决,理解了实际工程问题-
模式切换:用状态机思想设计,代码更清晰### 3. 实践收获- 从理论到实践的跨越:看手册→写代码→调试→成功运行- 理解了"点亮LED"是嵌入式开发的"Hello World"- 学会了使用STM32CubeMX提高开发效率- 掌握了Keil MDK的基本调试方法### 4. 工程思维培养- 代码要分层:硬件操作与业务逻辑分离- 考虑可靠性:按键消抖、异常处理- 注重可维护性:添加注释、模块化设计## 未来展望这个实验是STM32学习的起点,后续可以:- 加入中断处理- 使用定时器精确控制- 添加通信功能(UART、I2C等)- 移植到RTOS实现多任务
最大的体会:嵌入式开发既要懂硬件原理,又要会软件设计,只有亲手实践才能真正掌握。从最初的寄存器配置到最后的HAL库应用,每一步都是成长!

感谢友情链接
https://blog.csdn.net/Brendon_Tan/article/details/107685563
https://blog.csdn.net/weixin_56102526/article/details/120877293

https://blog.csdn.net/weixin_46129506/article/details/120780184

https://blog.csdn.net/LX567567/article/details/133994620

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐