【STM32】Cortex-M3的中断优先级分组

1 前言

这篇文章算是自己这半个月,终于从中断优先级分组的坑里爬出来的一点个人经验的总结吧,其中的各种问题也确实在网上资料偏少,所以抛砖引玉吧。

2 遇到的问题

首先,介绍一下我所遇到的问题。我在开发板上搞1838红外遥控接收的时候,使用了一份例程,用Systick获得延时,用EXTI获取红外接收头的响应。然后在整合进自己的工程的时候出现了问题(我自己的工程配置了Tim6)。具体的表现就是,一旦操作了红外遥控器,在EXTI的中断处理中运行到Systick的延时处理的时候,发现Systick的中断处理函数无法进入,延时卡死了。

2.1 具体的代码

EXTI的NVIC配置:

TIM6的NVIC配置:

Systick在配置后重新将优先级配置到了最高:

在我的想象中,systick的优先级最高,其次是TIM,再其次是EXTI。负责延时的Systick是最高优先级可以在EXTI中嵌套。

但是实际上的现象是,会在EXTI的处理中的Func_Delay_us(2)的位置卡死。

void EXTI9_5_IRQHandler(void)
{
	
	if(EXTI_GetITStatus(EXTI_Line7)!=RESET)
	{
		
		while(1)
		{
			if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_7)==Bit_SET)
			{
				u1a_pulse_duration = 0;
				//获取高电平的时长
				while( GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_7) )
				{
					u1a_pulse_duration ++;
					Func_Delay_us(2);     // 延时 n*10us
					if(u1a_pulse_duration >= 250)
					{
						break;	 // 超时溢出   
					}
				}

Func_Delay_us( ) 的while循环处会死循环,因为“u1s_TimingDelay”不会在SysTick的中断处理中自减。

void Func_Delay_us(__IO u32 nTime)
{ 
	u1s_TimingDelay = nTime;	

	// 使能滴答定时器  
	SysTick->CTRL |=  SysTick_CTRL_ENABLE_Msk;

	while(u1s_TimingDelay != 0);
}

void SysTick_Handler(void)
{
	if (u1s_TimingDelay != 0x00)
	{ 
		u1s_TimingDelay--;
	}
}

3 中断优先级分组

根据网上以及入手的大部份资料,都基本上是如下的一派说辞,优先级根据优先级分组分为抢占优先级和子优先级云云。

但是我觉得大部分都没有明确的指出,STM32F103的5个优先级分组对于一个系统来说是唯一的,也就是说不是同时存在5个分组,它不是5个盘子。我把手里的中断像放豆子似的随便放到某个盘子里,而是选择了一中优先级分组的方式则决定了这个系统从此以后以某一种分组的方式来处理优先级。

其次,分为抢占优先级和子优先级没有问题,这很好理解,但是只有抢占优先级是可以中断嵌套的,而子优先级虽然区分先后顺序但是并不能进行中断嵌套,这个点真的是没有解释清楚。上图的最后也仅仅是一句,“如果抢占优先级相同则根据子优先级的编号越小则优先级越高”,没有直接点出子优先级不能中断嵌套。

4 复盘问题

首先是对于一个系统只需要配置一次优先级分组。可以看到上面的代码中EXIT的配置了分组1,而TIM6的配置分组0。实际在main()的初始化中,先初始化了EXIT的,再初始化了TIM6的。也就因此最后系统被配置成了中断优先级分组0。

而中断优先级分组0的意思是,所有优先级的4个bit都用来组成子优先级,大家都没有抢断优先级。如果在理解了抢断和子优先级的区别后,就很好理解这意味着所有的中断都无法相互抢断嵌套了。

所以才会出现,在EXIT的中断处理中,SysTick的中断处理无法进入,因为二者是平级的无法相互抢断。

5 最后

摊手,确实最后借助这个问题比较好的理解了中断优先级的问题。现在回过头来看,这个问题确实也不算大,最多也就归结于读二手资料导致的理解不充分吧。用作抛砖引玉吧。

经验分享 程序员 微信小程序 职场和发展