APP下载

STM32中SysTick延时中断的优先级调整*

2017-04-14郑忠楷蒋学程罗志灶

单片机与嵌入式系统应用 2017年3期
关键词:死机固件中断

郑忠楷,蒋学程,罗志灶

(闽江学院 物理学与电子信息工程系,福州 350108)

STM32中SysTick延时中断的优先级调整*

郑忠楷,蒋学程,罗志灶

(闽江学院 物理学与电子信息工程系,福州 350108)

本文就STM32单片机的SysTick延时中断及中断处理中进行中断优先级调整进行了一些讨论,主要是在同时存在串口中断时的情况下进行研究,并具体分析了一个Delay_us()库函数和串行中断响应的程序实例。在多个中断并存的情况下,SysTick延时中断的优先级直接影响中断的CPU/系统资源占用和服务响应时间,因此对其研究很有必要。

SysTick中断、中断优先级、单片机、延时

引 言

自从ARM公司2007年首次推出Cortex内核,意法半导体公司推出了一款高性能的基于Cortex-M3内核的32位的STM32[1-3],其主频可以达到72 MHz,有着十分方便易用的库函数给用户使用,但同时也带来了许多意想不到的问题。比如说其中最常用到的SysTick延时中断和与其相关的Delay_us()库函数,在使用的时候就有很多需要注意的地方,不然有时会造成意外的错误,甚至有死机的可能。本文主要针对SysTick中断在有串口中断存在时如何调整二者优先级进行研究和讨论。

1 STM32固件库简介

STM32固件库是STM32库函数集合的总称,STM32固件库可以从意法半导体官网下载。固件库首先将MCU的各个设备中所有寄存器的配置字进行预先定义,然后封装在对应的结构体或枚举变量中,待用户调用对应的固件库函数时,会根据用户传入的参数从这些封装好的结构体或枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置。采用固件库形式,可以加速程序开发,用户不必每个寄存器一个一个地细细分析,可直接面对程序功能的编写程序。基于STM32的这个固件库,程序员可以快速开发ARM微控制器,这个库文件写的非常齐全方便,可以让程序员在外设的硬件配置上节省很多时间。但是程序员还是需要根据许多具体实际情况熟悉外设的硬件结构和寄存器结构功能来学习使用库文件,而且要考虑具体使用时的软件环境和对应版本,随着硬件的更新升级,STM32固件库也推出了2.02版、3.15版、3.5版等版本。

1.1 STM32 SysTick延时中断简介

几乎每个版本中都有对应的SysTick延时中断[4],它具有自动重载和溢出中断的功能,所有基于Cortex-M3处理器的微控制器都可以由这个定时器获得一定的时间间隔。采用SysTick延时中断可以很容易地完成单片机系统的简单延时、节拍确定,SysTick延时中断实质上是对一个定时器的配置及其中断函数的编写,但是使用中有很多要注意的细节,在很多场合它被形象称为“滴答定时器中断”,因为它被直接用在软件系统中提供节拍。在单任务的应用程序中,其程序架构决定了它执行任务的串行性,这就引出一个问题:当一个任务出现问题时,就会牵连到后续的任务,进而导致整个系统崩溃。要解决这个问题就要使用实时操作系统(RTOS),因为RTOS采用并行的任务架构,单一任务的崩溃并不会牵连到整个系统,但是RTOS的任务调度需要软件系统为其提供一个节拍,这也就是SysTick延时中断的重要性和“滴答定时器”名称的由来。正因为此,在使用实时操作系统(RTOS)时为了保证任务调度的最高优先级,必须把SysTick延时中断的优先级设置为最高。

1.2 Delay_us()库函数简介及其特点

即便在没有采用实时操作系统(RTOS)的场合,程序依旧采用单任务串行架构,在一些简单应用场合(比如控制LED的闪烁、键盘防抖等基本程序)还是要用到简单的延时函数,这时其实就是让CPU做一些简单的无用工作,浪费一点CPU时间,等待外部中断,等待一个确定的时间。这时如果用简单的while()或者for()空循环,则不容易精确地控制时间的长短,STM32的固件库非常体贴地给用户提供了Delay_us()函数,这样用户可以方便地设计比较简单准确的延时程序。

但是这个延时程序也是基于SysTick延时中断的,仔细分析其库函数源文件SysTick.C,不难发现其中Delay_us(__IO u32 nTime)函数中设置了一个名为TimingDelay的32位变量,再在SysTick延时中断中将其递减,然后又在Delay_us(__IO u32 nTime)中使用“while(TimingDelay !=0);”循环死等SysTick延时中断,将其递减为零。这里实际上留下了一个巨大的bug,如果有一个中断的优先级比SysTick延时中断高,打断了SysTick延时中断,则会导致SysTick延时中断不能发生,系统就必然陷在while()循环中导致死机。若要避免出现这种情况,就必须保证SysTick延时中断始终处在中断优先级的最高一级,可以在每个时间片完成一次TimingDelay变量的递减。

2 STM32系统的中断优先级

几乎所有的微处理器都具有中断及响应、中断处理的一套软硬件设备和流程,为了实现多个中断的响应,当然要对它们进行优先级划分,STM32也不例外。STM32中的中断优先级还有抢占优先级和响应优先级的区别[4],中断抢占优先级是指当多个中断同时发生时哪个中断优先抢占资源,这里的资源指的是CPU处理时间和内存等资源。中断响应优先级是指在相同的中断抢占优先级中的优先级划分,也就是说当多个抢占优先级中断同时发生时,或者高优先级中断结束后,同优先级的中断中CPU优先处理哪个中断。

在STM32中,可以人为地设定各个设备中断的优先级,这样就可以对它们的触发、响应的优先级做出合理的规划。同时,如果没有合理的规划好中断优先级,很可能给单片机系统带来不可预计的后果,也可能陷入不停地循环——递归的中断调用中,甚至可能造成系统死机。前述的Delay_us()库函数中的SysTick延时中断被高一级中断打断之后进入死循环导致死机就是一个例子。

3 程序实例及其研究

3.1 实例程序分析

在一个简单的单片机程序“串口接收数据-控制LED闪灯次数”中,要用到串口中断和PC机通信以及Delay_us()函数完成LED闪灯延时,其中的Delay_us()函数就要用到SysTick中断。最初,我们把Delay_us()函数简单地写在了串口中断处理函数USARTx_IRQHandler()里,结果发现单片机常常意外死机。多次跟踪调试后发现,只要进入USARTx_IRQHandler()中断,延时程序Delay_us()函数就经常不再正常工作,LED也就不再继续闪烁。可见在使用STM32时,不能像使用51单片机或者AVR单片机那样用一个简单使能中断、禁止中断指令来解决这个问题,问题的关键在于多个中断之间的优先级调整来分配CPU资源。解决的办法是,将SysTick中断的抢占优先级设高,让它能够打断USARTx中断随时获得CPU资源,在一个系统中Delay_us()函数要完成最基本的延时功能,从前面对SysTick.C文件中它的分析可知,它往往需要获得最高的中断优先级才能保证不陷入“while(TimingDelay !=0);”死循环,因为SysTick中断一旦被打断,TimingDelay变量就不能完成递减,“while(TimingDelay !=0);”死循环就会发生。

前述的LED闪灯程序死机,究其实质就是因为串口中断USARTx服务子程序的优先级比SysTick中断来的高,打断了SysTick中断,使得TimingDelay变量的递减过程串口中断USARTx服务子程序被破坏,所以在Delay_us()函数中发生了“while(TimingDelay !=0);”死循环,系统陷入了死机。

3.2 STM32的串口库函数及其中断设置

在STM32中有多个硬件串口设备可以访问,因此当设置好串口设备的相应I/O口输入/输出特性后,在其硬件库中可以直接调用串口发送函数USART_SendData(USARTx,data),将data发到串口USARTx,也可以在串口接收中断函数USARTx_IRQHandler()里面写下对应串口USARTx的接收中断处理函数。但是,这里由于串口接收事件是被动的、未知的,所以我们采用了中断的方式来完成,因此需要设置其对应的中断优先级,具体代码如下:

NVIC_SetPriority(SysTick_IRQn,0x00);

NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;

//中断抢占先等级1

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

//中断响应优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

//打开中断

NVIC_Init(&NVIC_InitStructure);

在这个程序实例中,用“NVIC_SetPriority(SysTick_IRQn,0x00);”将SysTick中断的抢占优先级设置为0(最高),把“NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1”设置为次高(把串口中断的抢占优先级设置为1),这样既保证了SysTick中断处于中断优先级的最高一层不会被其他中断打断,Delay_us()函数不会进入死循环,又保证了串口函数的优先级为次高不被其他程序打断,闪灯次数有着一定的实时性。

3.3 程序运行结果

经过以上优先级调整后,多次实验结果表明:程序顺利运行完成了PC上位机控制下位机完成LED闪灯次数的功能结果表明下位机没有再次进入死循环。

结 语

[1] 张炳先,王密,潘俊.基于卡尔曼滤波的光学遥感影像高精度复原处理[J].武汉大学学报:信息科学版,2015,40(7):964-969.

[2] 刘军.例说STM32[M].北京:北京航空航天大学出版社,2012.

[3] Texas Instruments.德州仪器高性能模拟器件高校应用指南,2014.

[4] JosephYiu.Coretex-M3权威指南[M]. 宋岩,译.北京:北京航空航天大学出版社,2013.

Priority Adjustment of SysTick Delay Interrupt in STM32

Zheng Zhongkai,Jiang Xuecheng,Luo Zhizao

(Department of Physics&Electronic Information Engineering,Minjiang University,Fuzhou 350108,China)

In the paper,the interrupt priority adjustment of STM32 MCU’s SysTick delay interrupt and reponse is discussed,in the case that the serial port interrupt at the same time happen.The Delay_us() library functions and a serial interrupt response example are analyzed.In the case of themultiple interrupts coexistence,the priority of SysTick delay interrupt directly affects the CPU/system resource usage and the service response time,so it is necessary to study the system.

SysTick interrupt;interrupt priority;microcontroller;delay

福建省科技厅农业科技计划重点项目(2013N0027) 蔬菜大棚的智能化改造;福建省教育厅青年教师培育计划项目(JB12166) 分布式太阳能面板自动跟踪伺服系统;福建省教育厅青年教师培育计划项目(JA09186) 基于电流刺激模型的新型电刺激仪。

TP368.1

A

�迪娜

2016-11-21)

猜你喜欢

死机固件中断
电脑死机时在干什么
提醒
跟踪导练(二)(5)
千里移防,卫勤保障不中断
脸死机了
基于固件的远程身份认证
提取ROM固件中的APP
一种通过USB接口的可靠固件升级技术
多路手机固件升级工具设计
AT89C51与中断有关的寄存器功能表解