STM32 中断控制LED流水灯(HAL库,Proteus仿真)
本文介绍了基于STM32F103的HAL库中断控制LED流水灯实验,通过STM32CubeMX配置GPIO输出和外部中断,实现LED流水灯及外部中断启停控制。实验采用软件消抖解决按键抖动问题,并利用Proteus进行仿真验证。实验步骤包括:1)使用STM32CubeMX配置GPIO和中断参数;2)在Keil中编写中断回调函数和主循环控制代码;3)硬件连接与功能测试。实验成功实现了LED流水灯效果,
STM32 中断控制LED流水灯(HAL库,Proteus仿真)
一、实验目的
- 深入理解STM32中断系统的工作原理,包括外部中断的触发机制及中断服务程序执行流程。
- 熟练掌握STM32CubeMX软件的使用,能够完成GPIO端口(输出/输入)及外部中断的配置,生成Keil工程代码。
- 掌握基于HAL库的STM32开发方法,实现GPIO输出控制LED流水灯,以及外部中断控制流水灯启停功能。
- 观察并分析机械抖动(杜邦线模拟开关插拔)对中断响应的影响,理解软件消抖的原理与实现。
- 掌握Proteus 8.17版本的使用,完成STM32F103C8T6核心板相关电路的绘制、程序加载与仿真验证。
二、实验环境
| 类别 | 具体内容 |
|---|---|
| 硬件设备 | STM32F103C8T6核心板、3只LED灯(红/绿/蓝)、杜邦线若干 |
| 软件工具 | STM32CubeMX、Keil MDK-ARM 5、Proteus 8.17、Windows 111操作系统 |
三、实验原理
1. GPIO输出控制原理
STM32的GPIO(通用输入/输出)端口可配置为推挽输出模式,通过向GPIO输出数据寄存器(ODR)写入高低电平,控制外部负载(如LED)的通断。当GPIO引脚输出低电平时,LED回路导通,LED点亮;输出高电平时,回路断开,LED熄灭。本实验中3只LED分别连接到STM32的3个GPIO输出引脚,通过循环切换引脚电平实现流水灯效果。
2. 外部中断原理
中断是CPU暂停当前任务、优先处理紧急事件的机制,外部中断由硬件电平变化触发。STM32F103的GPIO引脚可配置为外部中断源(如PA5对应EXTI5),支持上升沿、下降沿或双边沿触发。当引脚电平满足触发条件时,会触发中断请求,CPU响应后跳转到中断服务程序(ISR)执行,执行完毕后返回原任务。
在HAL库中,外部中断的处理通过重写HAL_GPIO_EXTI_Callback()函数实现,该函数是中断服务程序的核心回调接口,用于编写自定义中断逻辑(如控制流水灯启停标志)。
3. 按键抖动与消抖原理
杜邦线模拟开关插拔时,金属触点会因物理接触不稳定产生“抖动”,导致引脚电平在短时间内快速切换(如高→低→高→低),进而触发多次中断。为解决该问题,本实验采用软件消抖:在中断回调函数中,触发中断后延时20ms,跳过抖动期,再读取引脚稳定电平,确保中断响应的有效性。
四、实验步骤
任务一:基于STM32硬件的LED流水灯与中断控制实现
1. STM32CubeMX配置(工程创建与引脚配置)
-
打开STM32CubeMX,点击“New Project”,搜索并选择“STM32F103C8T6”芯片,点击“Start Project”。
-
配置系统时钟:进入“RCC”界面,选择“HSE”为“Crystal/Ceramic Resonator”,配置时钟为72MHz。


-
GPIO输出配置(LED控制):
- 选择PB9、PA2、PC15引脚,配置为“GPIO_Output”模式;
- 引脚参数设置:输出类型为“Push-Pull”,上拉/下拉为“Pull-Up”,速度为“Low”;

-
GPIO中断配置(开关控制):
-
选择PB5引脚,配置为“GPIO_EXTI0”模式;
-
引脚参数设置:上拉/下拉为“No Pull-Down and no pull-up”(默认低电平,接高电平时触发);
-
进入“NVIC Settings”界面,勾选“EXTI0 line interrupt”,使能中断,优先级默认(抢占优先级0,子优先级0);
-
进入“GPIO”界面,点击PA0引脚“GPIO mode and configuration”,设置“Trigger Edge”为“Rising and Falling Edge”(双边沿触发,检测高低电平切换)。

-
-
其他配置:


-
生成工程:
- 进入“Project Manager”界面,设置工程名称(如“STM32_Interrupt_LED”),选择工程路径,工具链/IDE选择“MDK-ARM”;
- 点击“Generate Code”,生成Keil工程并打开。
2. Keil MDK代码编写与编译
-
代码编写(main.c文件):
- 在“/* USER CODE BEGIN PV /”与“/ USER CODE END PV */”之间定义流水灯控制标志:
// 1. 定义一个全局标志位,用于从中断传递“暂停”指令给主循环 volatile uint8_t flag = 0; // 0: 不暂停, 1: 暂停 // 2. 使用一个变量来记录当前点亮的LED,实现“从暂停处继续” uint8_t c_led = 0; // 0: PB9, 1: PC15, 2: PA2 - 在“/* USER CODE BEGIN WHILE */”的while(1)循环中,添加流水灯控制逻辑:
/* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // 检查中断设置的暂停标志 if (!flag) { // 如果不暂停,执行流水灯逻辑 // 熄灭当前点亮的LED switch(c_led) { case 0: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET); break; case 1: HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET); break; case 2: HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); break; } // 更新到下一个LED c_led = (c_led + 1) % 3; // 点亮新的LED switch(c_led) { case 0: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET); break; case 1: HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET); break; case 2: HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); break; } // 延时,控制流水灯速度 HAL_Delay(1000); } // 如果暂停标志为1,则什么也不做,LED状态保持不变 } /* USER CODE END 3 */ - 在“/* USER CODE BEGIN 4 /”与“/ USER CODE END 4 */”之间,重写外部中断回调函数:
/* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { // 确保中断来自我们想要的引脚 (PB5) if (GPIO_Pin == GPIO_PIN_5) { // 读取PB5的当前电平 // 假设插入时为高电平 (GPIO_PIN_SET),不插入时为低电平 (GPIO_PIN_RESET) if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_5) == GPIO_PIN_SET) { // PB5为高电平:设置暂停标志 flag = 1; } else { // PB5为低电平:清除暂停标志,允许继续 flag = 0; } } } /* USER CODE END 4 */
- 在“/* USER CODE BEGIN PV /”与“/ USER CODE END PV */”之间定义流水灯控制标志:
-
代码编译:
- 点击Keil工具栏“Build”按钮,编译工程;
- 编译无错误后,点击“Rebuild”生成Hex文件(路径:工程目录→Objects→工程名.hex)。

3. 硬件连接与测试
-
硬件连接:
- LED与STM32连接:3只LED的阳极连接PB9、PA2、PC15,阴极接地(GND);
- 开关(杜邦线)与STM32连接:杜邦线一端接PB5,另一端可切换连接3.3V(高电平)或GND(低电平)。
-
程序下载:通过ST-Link串口工具,将Keil生成的Hex文件下载到STM32F103核心板。
-
功能测试:
-
将PA0杜邦线接3.3V:观察到LED按“PB9→PC15→PA2”顺序周期闪烁(流水灯运行);
-
将PA0杜邦线接GND:观察到LED立即熄灭(流水灯停止);
-
快速插拔PA0杜邦线:观察抖动对中断的影响,验证软件消抖效果。

-
任务二:Proteus电路绘制与仿真
1. Proteus新建项目与元器件添加
- 打开Proteus 8.15,点击“New Project”,设置项目名称(如“STM32_Interrupt_LED_Simulation”),选择保存路径,点击“Next”;
- 选择“Create a schematic from scratch”,点击“Next”;
- 元器件添加:点击“Pick Devices”,在搜索框中输入元器件名称并添加,所需元器件如下:
| 元器件名称 | Proteus搜索关键词 | 数量 |
|---|---|---|
| STM32F103C8 | STM32F103C8 | 1 |
| LED | LED | 各1 |
| 限流电阻 | RES | 3 |
| 电源 | POWER | 1 |
| 接地 | GROUND | 1 |
| 单刀单掷开关 | SWITCH | 1 |
2. 电路绘制
-
放置元器件:将添加的元器件拖拽到Proteus原理图界面,按合理布局摆放;
-
电路连接:
- 电源与接地:将POWER(3.3V)和GROUND放置到界面,用于提供电源和接地;
- LED回路:LED阳极→RES→STM32的PB9/PC15/PA2,LED阴极→GROUND;
- 中断控制回路:SWITCH-SPDT的中间引脚接STM32的PB6,两端引脚接POWER(3.3V

-
电路检查:确认所有连接无误,无悬空引脚(除STM32未使用引脚外)。
3. 仿真设置与运行
-
加载Hex文件:双击STM32F103C8元器件,在弹出的“Edit Component”窗口中,点击“Program File”后的“…”,选择Keil生成的Hex文件,点击“OK”;
-
仿真运行:
- 点击Proteus工具栏“Start Simulation”按钮,启动仿真;
- 切换SWITCH-SPDT开关:
- 开关接POWER(PB5低电平):观察LED流水灯运行;
- 开关接GROUND(PB5高电平):观察LED停止并熄灭;
- 记录仿真现象,验证功能符合预期。
五、实验现象与分析
1. 硬件实验现象
| 操作 | 实验现象 |
|---|---|
| PB5接3.3V | LED按“PB9(1000ms亮)→PC15(1000ms亮)→PA2(1000ms亮)”循环,形成流水灯效果 |
| PB5接空 | 所有LED立即熄灭,流水灯停止运行 |
| 快速插拔PB5杜邦线 | 未加消抖时:LED频繁启停、闪烁异常;加20ms消抖后:LED启停稳定,无异常闪烁 |
2. Proteus仿真现象
仿真现象与硬件实验完全一致:开关接3.3V时流水灯运行,接GND时流水灯停止,消抖后无抖动干扰,功能符合设计预期。
3. 现象分析
- 流水灯原理验证:通过GPIO输出高低电平切换,成功实现LED周期闪烁,证明GPIO输出配置与HAL库函数(
HAL_GPIO_WritePin()、HAL_Delay())使用正确; - 中断控制原理验证:PB5电平变化触发外部中断,通过回调函数修改
led_run_flag实现流水灯启停,证明中断配置与回调函数重写正确; - 抖动现象分析:未消抖时,杜邦线插拔产生的电平抖动触发多次中断,导致
led_run_flag频繁切换;添加20ms延时后,跳过抖动期读取稳定电平,有效解决了抖动问题,验证软件消抖的有效性。
六、实验结论
- 本次实验成功实现了基于STM32F103C8T6的中断控制LED流水灯功能:通过STM32CubeMX完成GPIO与外部中断配置,基于HAL库编写流水灯与中断逻辑,硬件测试与Proteus仿真均满足“高电平运行、低电平停止”的需求;
- 深入理解了STM32中断系统原理:包括外部中断触发条件、NVIC优先级配置、中断回调函数执行流程;
- 掌握了软件消抖的实现方法:通过20ms延时跳过抖动期,有效解决了杜邦线模拟开关的抖动问题,确保中断响应的稳定性;
- 熟练掌握了STM32CubeMX、Keil MDK、Proteus三款工具的协同使用流程,为后续STM32项目开发奠定基础。
七、实验心得
- 工具协同的重要性:STM32CubeMX简化了寄存器配置流程,Keil提供高效的代码编写与编译环境,Proteus则实现了无硬件依赖的功能验证,三者结合大幅提升了嵌入式开发效率;
- 中断与消抖的关键细节:中断回调函数中需严格判断引脚编号,避免误响应;软件消抖的延时时间需合理(20ms),过短无法消抖,过长影响实时性;
- 仿真与硬件的互补性:Proteus仿真可提前验证代码逻辑,减少硬件烧录次数,降低硬件损坏风险;硬件测试则能发现仿真中忽略的问题(如实际抖动干扰),两者结合确保实验成功。
简化了寄存器配置流程,Keil提供高效的代码编写与编译环境,Proteus则实现了无硬件依赖的功能验证,三者结合大幅提升了嵌入式开发效率;
2. 中断与消抖的关键细节:中断回调函数中需严格判断引脚编号,避免误响应;软件消抖的延时时间需合理(20ms),过短无法消抖,过长影响实时性;
3. 仿真与硬件的互补性:Proteus仿真可提前验证代码逻辑,减少硬件烧录次数,降低硬件损坏风险;硬件测试则能发现仿真中忽略的问题(如实际抖动干扰),两者结合确保实验成功。
更多推荐



所有评论(0)