stm32内核外设Systick与普通外设中断优先级比较的验证实验

2019-07-19来源: eefocus关键字:stm32内核  外设Systick  普通外设  中断优先级

最近又遇到了使用Systick来产生精确计时,然后又涉及到了Systick的中断优先级的问题。我们老板认为Systick属于内核外

设,中断优先级应该比普通外设高。然后我们说,在网上看到的是,Systick的中断优先级ST官方默认设置15(1111b),然

后换算为4位(M4用4位来表示优先级分组)是3(抢占优先级),3(响应优先级),其实是最低的,但老板说虽然它是最低的,但它是跟CPU紧耦合的内核外设,它依然能打断优先级比它高的普通外设,当然我们也有点不确定网上说的就是对的(还是老板说的就是错的,==)。于是就做了一个对比实验,测试到底是Systick到底能否打断中断优先级比它高的。


实验环境条件如下:MDK v5.21a,stm32f429IGT6的MCU。


设置Systick的中断优先级为7(1,3),10ms产生一个中断,初始化Systick代码如下:


/**

  * @brief  启动系统滴答定时器 SysTick

  * @param  无

  * @retval 无

  */

void SysTick_Init(void)

{

/* SystemFrequency / 1000    1ms中断一次

* SystemFrequency / 100000  10us中断一次

* SystemFrequency / 1000000 1us中断一次

*/

if (SysTick_Config(SystemCoreClock / 100))

/* Capture error */ 

while (1);

}

}


__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)

{

  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */


  SysTick->LOAD  = ticks - 1;                                  /* set reload register */

//  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */

  NVIC_SetPriority (SysTick_IRQn, 7); //设置Systick中断优先级为7(1,3)

  SysTick->VAL   = 0;                                          /* Load the SysTick Counter Value */

  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |

                   SysTick_CTRL_TICKINT_Msk   |

                   SysTick_CTRL_ENABLE_Msk;                    /* Enable SysTick IRQ and SysTick Timer */

  return (0);                                                  /* Function successful */

}


Systick的中断服务函数如下:


/*Systick中断服务函数*/

void SysTick_Handler(void)

{

LED_RED;

Delay(0xffff);//普通的软件延时

}


然后配置两个按键KEY1和KEY2,产生两个外部中断EXTI(上升沿中断),NVIC的Group分组为

Group2。分别设置KEY1的外部中断优先级为15(3,3),KEY2的外部中断优先级为3(0,3),代码如下:


void EXTI_Key_Config(void)

{

/*定义一个XXXX_InitTypeDef类型的结构体*/

NVIC_InitTypeDef NVIC_InitStructure;

GPIO_InitTypeDef GPIO_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;


/*开启按键对应GPIO*/

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOC,ENABLE);

/*开启SYSCFG时钟,外部中断需要*/

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

/*配置NVIC为优先级组1*/

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

/*配置中断源:按键1*/

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

/*配置抢占优先级1*/

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;

/*配置子优先级1*/

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

/*使能中断通道*/

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);


/*配置中断源:按键2*/

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;

/*配置抢占优先级1*/

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

/*配置子优先级1*/

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

NVIC_Init(&NVIC_InitStructure);


/*中断引脚配置*/

/*外部中断引脚配置为输入模式无上下拉*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_Init(GPIOA,&GPIO_InitStructure);

/*按键2*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;

GPIO_Init(GPIOC,&GPIO_InitStructure);

/*配置外部中断*/

/*将引脚连接到外部中断线上*/

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);

/* 选择EXTI中断源*/

EXTI_InitStructure. EXTI_Line = EXTI_Line0;

/*中断模式*/

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

/*上升沿触发*/

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

/*使能中断*/

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);


/*按键2*/

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource13);


EXTI_InitStructure. EXTI_Line = EXTI_Line13;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

/*下降沿触发*/

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

EXTI_ClearITPendingBit(EXTI_Line0);

EXTI_ClearITPendingBit(EXTI_Line13);

}


KEY1和KEY2的外部中断服务函数如下:


/*按键1中断服务函数*/

void EXTI0_IRQHandler(void)

{

if (EXTI_GetITStatus(EXTI_Line0) != RESET)

{


LED_GREEN;

while(1)

{

}

EXTI_ClearITPendingBit(EXTI_Line0);

}

EXTI_ClearITPendingBit(EXTI_Line0);

}


/*按键2中断服务函数*/

void EXTI15_10_IRQHandler(void)

{

if (EXTI_GetITStatus(EXTI_Line13) != RESET) 

{

LED_WHITE

while(1)

{

}

EXTI_ClearITPendingBit(EXTI_Line13);

}

EXTI_ClearITPendingBit(EXTI_Line13);

}



最后是主函数的代码:


int main(void)

{


/* 初始化系统滴答定时器 */

SysTick_Init();

EXTI_Key_Config();

/* LED 端口初始化 */

LED_GPIO_Config();

/* 控制LED灯 */

while (1)

{

}

}


实验设计的条件如下:


中断 KEY1 Systick KEY2

优先级(抢占、响应) 15(3,3) 7(1,3) 3(0,3)

现象 亮绿灯 亮红灯 亮白灯

另外,从代码可以看出,KEY1和KEY2的中断服务函数都是亮灯后死循环(只是为了做实验而已,中断服务函数里绝不允许放死循环,应该服从“快进快出”的原则),Systick的中断服务函数是亮灯后延时一段时间。(亮灯都是控制的亮同一个灯,使之产生不同颜色,方便区分)


实验现象如下:

程序下到板子里开始跑后,未操作前,一直亮红灯,当第一次按下按键1后,会闪一下绿灯然后亮红灯,再按按键1,无反应(还是亮红灯);然后按下按键2,亮白灯,一直亮白灯,再按按键1,无反应(还是亮白灯)。


实验现象分析:

未操作前,亮红灯,因为每10ms产生一次Systick中断,红灯一次置位就会一直亮;


当按下KEY1后,会闪一下绿灯然后亮红灯,这是因为KEY1的中断优先级虽然比Systick低,但是当执行完Systick中断后还是会去执行KEY1的中断,称为“咬尾中断”,然后当Systick产生中断后再返回Systick中断;再按KEY1,无反应,是因为代码中在退出按键1中断前加了个死循环,未清除KEY1的中断标志位,所以进不去;


然后按下KEY2,一直亮白灯,是因为KEY2的中断优先级比Systick高,能抢占(虽然从灯上没体现出来),而且KEY2的中断里也加了个死循环,退不出来。也就是说,当KEY2的中断在执行的时候,虽然Systick的时间到了,产生了Systick中断,但还是打断不了KEY2的中断,因为优先级没它(KEY2)高。


实验结论:

Systick虽然作为与CPU紧耦合的内核外设,但其中断优先级并不比普通外设要高,并不因为它是内核外设而特殊,它还是遵循中断优先级高低的规则来响应。


实验注意:

设置Systick中断优先级的时候,不能通过修改__NVIC_PRIO_BITS的大小,比如改成3,使Systick中断优先级为7。不能那么改,而应该和上面代码一样,采用直接赋值的办法。因为==__NVIC_PRIO_BITS表示的是M4所有中断分组所用的位数,不是普通的设置成Systick中断优先级的数字==;


另外,NVIC分组设置,最好设置为Group2,两位表示抢占优先级(主优先级),两位表示响应优先级(子优先级),方便对比。



关键字:stm32内核  外设Systick  普通外设  中断优先级 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic468591.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32F1系列单片机USB外设相关寄存器的定义
下一篇:关于Stm32内核外设Systick与普通外设中断优先级的比较

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm32 Ctext-M3内核最简单的多任务RTOS
任务:不能在所有任务里串口打印,因为串口打印非常的占用cpu,除非使用dma传输。说一下移植,只需要实现以下代码_uint32 fac_us;//SysTick定时器void set_systick(_uint32 ms){ fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用 SysTick->LOAD = ms * SystemCoreClock/1000-1; NVIC_SetPriority(SysTick_IRQn,(1<<__NVIC_PRIO_BITS)-1); SysTick->VAL = 0; SysTick->CTRL
发表于 2019-09-25
stm32 Ctext-M3内核最简单的多任务RTOS
关于Stm32内核外设Systick与普通外设中断优先级的比较
 有网友经实验验证,Systick虽然作为与CPU紧耦合的内核外设,但其中断优先级并不比普通外设要高,并不因为它是内核外设而特殊,它还是遵循中断优先级高低的规则来响应。https://blog.csdn.net/To_be_a_fisher/article/details/84986790Systick优先级是最低的https://www.cnblogs.com/jieruishu/p/4444701.htmlSystick虽然作为与CPU紧耦合的内核外设,但其中断优先级并不比普通外设要高,并不因为它是内核外设而特殊,它还是遵循中断优先级高低的规则来响应。  NVIC_SetPriority
发表于 2019-07-19
STM32F1(Cortex M3内核)位带操作
 本文参考《STM32_参考手册》2.3.2 位段               《CM3权威指南》第五章 存储器系统Cortex M3内核有两个位带区,对应的是片上RAM区和片上外设的最低的1MB地址范围,而位带别名区里面的每个字对应位带区的一个比特,也就是对位带别名区的一个字的操作相当于对位带区对应一个位的置零或者置一。Cortex M3的位带区和位带别名区如下图所示。从位带区到位带别名区有如下的映射关系:bit_word_addr =bit_band_base + (byte_offset×32) + (bit_num
发表于 2019-07-12
STM32F1(Cortex M3内核)位带操作
STM32F4的CCM内存之一
我们知道STM32F4当中有个CCM内存,如图所示,这个内存是挂在D总线上直接和内核相连,因此除了内核之外谁都不能访问,那么我们怎么将其利用起来呢? 首先,我们可以使用Keil的设置选项,将IRAM2打勾,让编译器选择什么时候使用这个内存。显然,我们还可以将这两个地址修改一下,将IRAM1改为0x10000000,这样,编译器就会优先分配CCM内存。 我们来看看结果,在MAP文件中,表明确实使用了这段内存,但是因为我们使用的内存较少, 还没有用到CCM。 这种自动分配的方式有什么问题呢?这段内存是内核专有的,除了内核任何其它总线都不能访问,这就意味着,一旦编译器将数据分配到CCM中,而同时使用了DM
发表于 2019-06-14
STM32F4的CCM内存之一
stm32之滴答定时器(1):滴答定时器在内核的位置
    之所以要讲这个滴答定时器,是因为它很特殊,stm32的定时器有内部也有外部的,而滴答定时器是在cortex内核里面的,明白滴答定时器,就可以根据这个思路去对stm32有更深的了解,可以说起到一个举一反三的作用吧。    滴答定时器在stm32手册中可以说是一笔带过,只是讲解了寄存器怎么用,很多童鞋可能对这个滴答定时器还是一头雾水,这第一篇先参考cortex-m3的内核手册讲一下滴答定时器在内核的位置。    在内核文件core_cm3.h(内核文件哦(⊙o⊙))中可以看到systick的地址#define
发表于 2018-10-16
stm32之滴答定时器(1):滴答定时器在内核的位置
STM32外设驱动---SysTick精准延时
单片机:STM32F103 库函数:V3.5 描述:利用系统内核文件core_cm3.c内部SysTick实现1ms,1us的精准延时,时钟72MHz,涉及中断服务SysTick_Handler的注册。delay.h#ifndef     __DELAY_H__#define     __DELAY_H__#include "stm32f10x.h" extern  void DelayMs(__IO uint32_t nTime);extern  void DelayUs(__IO ui
发表于 2019-02-14
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved