STM32+HAL库实现外部中断嵌套

 【外部中断理论可参考:【小趴菜STM32开发笔记2】---- 外部中断

目录

1 Cubemx新建工程

2 配置系统时钟

3 配置引脚 

3.1 配置4个LED引脚为GPIO_Output

3.2 配置4个按键为中断模式(GPIO_EXTIx)

 3.3 设置中断优先级

4 生成代码

5 进入Keil,补充代码

5.1 HAL库的中断处理流程

5.2 工程源码

5.2.1  main函数

5.2.2 中断回调函数

6 实验现象  


1 Cubemx新建工程

        (略)


2 配置系统时钟

 


3 配置引脚 

3.1 配置4个LED引脚为GPIO_Output

【Tip】自定义引脚标签

3.2 配置4个按键为中断模式(GPIO_EXTIx)

       

 3.3 设置中断优先级

 【这里中断号5和中断号9共用一条中断线】


4 生成代码

        (略)


5 进入Keil,补充代码

5.1 HAL库的中断处理流程

MX_GPIO_Init() 中调用HAL库使能中断函数和设置中断优先级:

             

 在 HAL_NVIC_EnableIRQ() 中调用 NVIC_EnableIRQ() 

 

 当触发中断时,处理器查表跳转到中断服务程序 EXTIx_IRQHandler(void)

 中断服务程序 EXTIx_IRQHandler (void) 中调用外部中断通用处理函数HAL_GPIO_EXTI_IRQHandler (uint16_t GPIO_Pin) ,该函数作为HAL库提供的外部中断接口函数,参量为触发中断的引脚

 系统自带了一个弱引用的中断回调函数,通过__weak修饰,没有任何执行代码,仅有一个避免编译警告的语句:UNUSED(GPIO_Pin)  

 需要在main.c中重写中断回调函数 HAL_GPIO_EXTI_Callback() ,并补全中断所需要执行的任务函数

5.2 工程源码

5.2.1  main函数

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


//定义4个计数变量,用于LED闪烁次数计数
uint8_t LED0_Count;  
uint8_t LED1_Count;
uint8_t LED2_Count;
uint8_t LED3_Count;

void SystemClock_Config(void);

int main(void)
{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  while (1)
  {
		//初始时刻4个LED同时闪烁
		HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
		HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
		HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
		HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);
		HAL_Delay(500);
  }
}

5.2.2 中断回调函数

//微秒级的延时
void delay_us(uint32_t delay_us)
{    
  volatile unsigned int num;
  volatile unsigned int t;
 
  for (num = 0; num < delay_us; num++)
  {
    t = 11;
    while (t != 0)
    {
      t--;
    }
  }
}
//毫秒级的延时
void delay_ms(uint16_t delay_ms)
{    
  volatile unsigned int num;
  for (num = 0; num < delay_ms; num++)
  {
    delay_us(1000);
  }
}


/* USER CODE BEGIN 4 */

//重写中断回调服务函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{	
	if(GPIO_Pin == KEY0_Pin)   //判断中断源为KEY0
	{
		while(KEY0_Pin ==0);
		for(LED0_Count=0;LED0_Count<20;LED0_Count++)  //翻转20次,闪烁10次
		{
			delay_ms(100);
			HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
		}
	}
	
	if(GPIO_Pin == KEY1_Pin)   //判断中断源为KEY1
	{
		while(KEY1_Pin ==0);
		for(LED1_Count=0;LED1_Count<20;LED1_Count++)
		{
			delay_ms(100);
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
		}
	}
	
	if(GPIO_Pin == KEY2_Pin)  //判断中断源为KEY2
	{
		while(KEY2_Pin ==0);
		for(LED2_Count=0;LED2_Count<20;LED2_Count++)
		{
			delay_ms(100);
			HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin);
		}
	}
	
	if(GPIO_Pin == KEY3_Pin)  //判断中断源为KEY3
	{
		while(KEY3_Pin ==0);
		for(LED3_Count=0;LED3_Count<20;LED3_Count++)
		{
			delay_ms(100);
			HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin);
		}
	}
}

/* USER CODE END 4 */

        这里在中断回调函数里调用了重构的阻塞延时函数,那为什么不直接用HAL库自带的HAL_Delay 进行延时呢?

        答:因为HAL_Delay 的延时是通过嘀嗒定时器(system tick timer)的定时器中断实现的,而嘀嗒定时器的中断优先级在默认情况下是低于外部中断优先级的,因此在触发外部中断执行回调函数时,遇到优先级更低的HAL_Delay ,那么请问这时候低优先级的HAL_Delay 能否打断高优先级的中断抢先执行呢?肯定是不能的吧,因此程序就卡死在HAL_Delay这一步,无法往下继续运行。

        当然,除了重构延时函数外,也可以增大嘀嗒定时器的中断优先级(需确保该操作不能影响系统其他功能的正常执行)


6 实验现象  

外部中断嵌套

4个按键分别控制4个LED翻转10次,key0和key1可以抢占key2和key3的执行

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Embedded Boy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值