引言

随着嵌入式技术在智能控制、工业自动化等领域的广泛应用,基于 STM32 系列微控制器的开发能力已成为嵌入式工程师的核心技能之一。本次实践以 STM32F103 核心板为硬件载体,融合 “硬件编程 - 电路仿真 - 代码管理” 三大关键环节,构建完整的嵌入式开发流程:
其一,通过 HAL 库与 STM32CubeMX 工具,实现 GPIO 端口控制下的 LED 流水灯周期闪烁,并进一步引入中断模式,结合杜邦线模拟的开关信号,解决信号抖动导致的中断多次响应问题,深化对 STM32 中断原理与 HAL 库开发方法的理解;
其二,借助 Proteus8.15 仿真平台,完成 LED 流水灯与中断控制电路的原理图绘制,加载 Keil 编译生成的.hex 文件进行仿真验证,实现 “设计 - 仿真 - 调试” 的闭环,降低实物开发中的试错成本。
这两者相互结合既覆盖 STM32 硬件开发的核心技术点,又兼顾电路设计的可视化验证与代码管理的规范性,为后续嵌入式项目开发奠定坚实基础。


本文内容基于已经配置好cubemx、keil5和Proteus8.17环境,如果各位还没配置好相应环境的话,我会放在参考资料供大家学习。

一、流水灯实现

1. cubemx配置

1.1. 选择CPU型号

点击下方画圈处,搜索STM32f103c8t6,双击确认,进入环境配置。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.2. 确认时钟源

进入工程后打开RCC选项,选择Crystal/Ceramic Resonator,即使用外部晶振作为HSE的时钟源。
在这里插入图片描述

1.3. 配置IO口

这个工程简单控制一个LED流水灯,我配置三个IO,大家可以根据自己的开发板情况来配置,这里选定控制引脚PA5、PB9、PC13,通过搜索框搜索可以定位IO口的引脚位置,图中会闪烁显示,配置PA5、PB9、PC13的属性为GPIO_Output。
在这里插入图片描述

1.4. 配置系统时钟

开发板的外部晶振为8MHz,我们填入8;通道选择LSE;PLLM选择为/1;倍频系数N选择为x9;系统时钟选择PLLCLK;系统时钟设定为72Mz;APB1分频系数选择为/2即PCLK1位36MHz;APB2分频系数选择为/1即PCLK2位72MHz。
在这里插入图片描述

1.5. 配置工程属性

为了防止出现,烧录以后仿真器无法连接的情况,我们在Pinout里将SYS里面的Debug设置成Serial Wire,这样问题得到解决。
在这里插入图片描述
接着选择Project Manager选项,配置工程的名称,路径等等,最后点击生成。
在这里插入图片描述
在这里插入图片描述

2. keil5编写流水灯代码

点击进入main.c文件对主函数进行如下修改即可

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();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
		    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		
		    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);  // 灯1亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  // 灯1灭
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);  // 灯2亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);  // 灯2灭
				HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);  // 灯3亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  // 灯3灭
		
  }
  /* USER CODE END 3 */
}

3. 实物演示

实物展示如下

VID_20251008_013129

二、基于中断的流水灯控制

1. 中断实现原理

1.1 中断基本概念

中断是STM32微控制器响应外部或内部事件的重要机制。当配置PB3引脚为外部中断模式时,该引脚上的电平变化会触发中断请求,CPU暂停当前执行的程序,转去执行中断服务函数,完成后再返回原程序继续执行。

1.2 STM32外部中断处理流程
步骤 处理过程 说明
1 引脚电平变化 PB3引脚检测到上升沿/下降沿触发信号
2 EXTI线检测 EXTI3线检测到PB3引脚的电平变化
3 中断请求生成 EXTI向NVIC发送中断请求
4 NVIC仲裁 NVIC根据优先级决定是否响应中断
5 上下文保存 CPU自动保存现场(PC、寄存器等)
6 跳转ISR 程序跳转到对应的中断服务函数
7 中断处理 执行用户编写的中断处理代码
8 中断清除 清除中断挂起标志位
9 上下文恢复 恢复之前保存的现场信息
10 返回主程序 继续执行被中断的程序
1.3 GPIO与EXTI映射关系
GPIO引脚 EXTI线 中断向量 说明
PA3/PB3/PC3… EXTI3 EXTI3_IRQn 同一EXTI线可映射到多个GPIO引脚
PB3 EXTI3 EXTI3_IRQn 通过SYSCFG_EXTICR寄存器配置
1.4 中断触发模式配置
触发模式 配置寄存器 适用场景
上升沿触发 EXTI_RTSR 按键释放、信号从低到高跳变
下降沿触发 EXTI_FTSR 按键按下、信号从高到低跳变
双边沿触发 EXTI_RTSR + EXTI_FTSR 电平变化检测、编码器计数
1.5 NVIC优先级配置要点
配置项 作用 推荐设置
抢占优先级 决定中断能否嵌套 根据重要性设置
子优先级 同抢占优先级时的仲裁 通常设置为0
使能中断 开启中断响应 必须使能
中断分组 定义优先级位分配 通常选择分组2或3

通过以上配置,当PB3引脚产生指定的电平变化时,系统能够可靠地触发中断并执行相应的处理程序,为流水灯的控制提供了灵活的事件响应机制。

2. cubemx配置

在流水配置的基础上,我们增加PB3作为我们外部中断源,点击我们的PB3引脚选择中断模式,如下图所示。
在这里插入图片描述
配置好后,我们的引脚会变为绿色。然后,点击左侧的NVIC选项,按下图顺序配置。

3. keil5编写流水灯代码

点击进入main.c文件对main函数进行修改,在主函数main上方定义一个中断标志并且重定义中断反馈。
在这里插入图片描述
在这里插入图片描述
中断标志函数构建

int led_flag=0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    
        if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==1)//当PB3置于高电平时,将标志置为1
        {
            led_flag=1;
        }
        if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3)==0)//当PB3置于低电平时,将标志置为0
        {
            led_flag=0;
        }
    
  
}

主函数main如下

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();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
		    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		

		if(led_flag==1)//当中断标志位为1时,流水灯工作
    {
		    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);  // 灯1亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  // 灯1灭
			if(led_flag==1)//当中断标志位为1时,流水灯工作
			{
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);  // 灯2亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);  // 灯2灭
			if(led_flag==1)//当中断标志位为1时,流水灯工作
			{
				HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);  // 灯3亮
				HAL_Delay(1000); // 延时1s
				HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  // 灯3灭
			}
			
		 }	
		}
		
		else
		{
		    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);  
		    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);  
		}
  }
  /* USER CODE END 3 */
}

4. 实物演示

实物展示如下

VID_20251008_013917

三、Proteus仿真

1. proteus工程建立

点击首页的新建工程,修改我们的工程名字和保存路径,最好是不要有中文。
在这里插入图片描述
在这里插入图片描述

一路next遇到下面界面我们创建固件项目,选择系列和芯片如下
在这里插入图片描述
再一路next指导finish结束,这样就建立完毕。
在这里插入图片描述

2. 配置原理图并进行仿真

流水灯及中断控制实验需要将三个流水灯和一个开关配置到相应端口就行了。如下图所示。
在这里插入图片描述
最后双击STM32进行配置,包括选择工程.hex路径及72M系统时钟如下
在这里插入图片描述

3. 实物演示

流水灯仿真如下

VID_20251008_141739

中断控制仿真如下

VID_20251008_142019

四、总结

通过这次完整的STM32流水灯实验,我深刻体会到了从零开始构建嵌入式项目的全过程。刚开始接触STM32CubeMX时,面对各种配置选项确实有些不知所措,但一步步跟着配置下来,发现这个图形化工具确实大大简化了底层配置的复杂度。特别是在时钟树配置环节,第一次理解了为什么需要精确配置各个时钟分频系数——这直接关系到后续延时函数的准确性。

在中断控制部分,我遇到了一个很实际的问题:按键抖动导致中断多次触发。通过查阅资料和反复试验,最终在中断服务函数中加入了状态判断逻辑,有效解决了这个问题。这个过程让我明白,嵌入式开发不仅要会写代码,更要理解硬件特性,软件硬件必须紧密结合。Proteus仿真的加入为整个开发流程增添了重要一环。在实物焊接前,通过仿真可以快速验证电路设计和程序逻辑的正确性,大大减少了硬件调试时间。特别是在仿真中观察到LED的亮灭状态和预期完全一致时,那种成就感是实实在在的。

总的来说,这次实验让我从理论到实践完整地走了一遍嵌入式开发流程,虽然过程中遇到了不少问题,但每个问题的解决都让我对STM32的理解更加深入。

五、参考资料

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐