鄭忠楷,蔣學(xué)程,羅志灶
(閩江學(xué)院 物理學(xué)與電子信息工程系,福州 350108)
STM32中SysTick延時(shí)中斷的優(yōu)先級(jí)調(diào)整*
鄭忠楷,蔣學(xué)程,羅志灶
(閩江學(xué)院 物理學(xué)與電子信息工程系,福州 350108)
本文就STM32單片機(jī)的SysTick延時(shí)中斷及中斷處理中進(jìn)行中斷優(yōu)先級(jí)調(diào)整進(jìn)行了一些討論,主要是在同時(shí)存在串口中斷時(shí)的情況下進(jìn)行研究,并具體分析了一個(gè)Delay_us()庫函數(shù)和串行中斷響應(yīng)的程序?qū)嵗?。在多個(gè)中斷并存的情況下,SysTick延時(shí)中斷的優(yōu)先級(jí)直接影響中斷的CPU/系統(tǒng)資源占用和服務(wù)響應(yīng)時(shí)間,因此對(duì)其研究很有必要。
SysTick中斷、中斷優(yōu)先級(jí)、單片機(jī)、延時(shí)
自從ARM公司2007年首次推出Cortex內(nèi)核,意法半導(dǎo)體公司推出了一款高性能的基于Cortex-M3內(nèi)核的32位的STM32[1-3],其主頻可以達(dá)到72 MHz,有著十分方便易用的庫函數(shù)給用戶使用,但同時(shí)也帶來了許多意想不到的問題。比如說其中最常用到的SysTick延時(shí)中斷和與其相關(guān)的Delay_us()庫函數(shù),在使用的時(shí)候就有很多需要注意的地方,不然有時(shí)會(huì)造成意外的錯(cuò)誤,甚至有死機(jī)的可能。本文主要針對(duì)SysTick中斷在有串口中斷存在時(shí)如何調(diào)整二者優(yōu)先級(jí)進(jìn)行研究和討論。
STM32固件庫是STM32庫函數(shù)集合的總稱,STM32固件庫可以從意法半導(dǎo)體官網(wǎng)下載。固件庫首先將MCU的各個(gè)設(shè)備中所有寄存器的配置字進(jìn)行預(yù)先定義,然后封裝在對(duì)應(yīng)的結(jié)構(gòu)體或枚舉變量中,待用戶調(diào)用對(duì)應(yīng)的固件庫函數(shù)時(shí),會(huì)根據(jù)用戶傳入的參數(shù)從這些封裝好的結(jié)構(gòu)體或枚舉變量中取出對(duì)應(yīng)的配置字,最后寫入寄存器中,完成對(duì)底層寄存器的配置。采用固件庫形式,可以加速程序開發(fā),用戶不必每個(gè)寄存器一個(gè)一個(gè)地細(xì)細(xì)分析,可直接面對(duì)程序功能的編寫程序。基于STM32的這個(gè)固件庫,程序員可以快速開發(fā)ARM微控制器,這個(gè)庫文件寫的非常齊全方便,可以讓程序員在外設(shè)的硬件配置上節(jié)省很多時(shí)間。但是程序員還是需要根據(jù)許多具體實(shí)際情況熟悉外設(shè)的硬件結(jié)構(gòu)和寄存器結(jié)構(gòu)功能來學(xué)習(xí)使用庫文件,而且要考慮具體使用時(shí)的軟件環(huán)境和對(duì)應(yīng)版本,隨著硬件的更新升級(jí),STM32固件庫也推出了2.02版、3.15版、3.5版等版本。
1.1 STM32 SysTick延時(shí)中斷簡(jiǎn)介
幾乎每個(gè)版本中都有對(duì)應(yīng)的SysTick延時(shí)中斷[4],它具有自動(dòng)重載和溢出中斷的功能,所有基于Cortex-M3處理器的微控制器都可以由這個(gè)定時(shí)器獲得一定的時(shí)間間隔。采用SysTick延時(shí)中斷可以很容易地完成單片機(jī)系統(tǒng)的簡(jiǎn)單延時(shí)、節(jié)拍確定,SysTick延時(shí)中斷實(shí)質(zhì)上是對(duì)一個(gè)定時(shí)器的配置及其中斷函數(shù)的編寫,但是使用中有很多要注意的細(xì)節(jié),在很多場(chǎng)合它被形象稱為“滴答定時(shí)器中斷”,因?yàn)樗恢苯佑迷谲浖到y(tǒng)中提供節(jié)拍。在單任務(wù)的應(yīng)用程序中,其程序架構(gòu)決定了它執(zhí)行任務(wù)的串行性,這就引出一個(gè)問題:當(dāng)一個(gè)任務(wù)出現(xiàn)問題時(shí),就會(huì)牽連到后續(xù)的任務(wù),進(jìn)而導(dǎo)致整個(gè)系統(tǒng)崩潰。要解決這個(gè)問題就要使用實(shí)時(shí)操作系統(tǒng)(RTOS),因?yàn)镽TOS采用并行的任務(wù)架構(gòu),單一任務(wù)的崩潰并不會(huì)牽連到整個(gè)系統(tǒng),但是RTOS的任務(wù)調(diào)度需要軟件系統(tǒng)為其提供一個(gè)節(jié)拍,這也就是SysTick延時(shí)中斷的重要性和“滴答定時(shí)器”名稱的由來。正因?yàn)榇耍谑褂脤?shí)時(shí)操作系統(tǒng)(RTOS)時(shí)為了保證任務(wù)調(diào)度的最高優(yōu)先級(jí),必須把SysTick延時(shí)中斷的優(yōu)先級(jí)設(shè)置為最高。
1.2 Delay_us()庫函數(shù)簡(jiǎn)介及其特點(diǎn)
即便在沒有采用實(shí)時(shí)操作系統(tǒng)(RTOS)的場(chǎng)合,程序依舊采用單任務(wù)串行架構(gòu),在一些簡(jiǎn)單應(yīng)用場(chǎng)合(比如控制LED的閃爍、鍵盤防抖等基本程序)還是要用到簡(jiǎn)單的延時(shí)函數(shù),這時(shí)其實(shí)就是讓CPU做一些簡(jiǎn)單的無用工作,浪費(fèi)一點(diǎn)CPU時(shí)間,等待外部中斷,等待一個(gè)確定的時(shí)間。這時(shí)如果用簡(jiǎn)單的while()或者for()空循環(huán),則不容易精確地控制時(shí)間的長短,STM32的固件庫非常體貼地給用戶提供了Delay_us()函數(shù),這樣用戶可以方便地設(shè)計(jì)比較簡(jiǎn)單準(zhǔn)確的延時(shí)程序。
但是這個(gè)延時(shí)程序也是基于SysTick延時(shí)中斷的,仔細(xì)分析其庫函數(shù)源文件SysTick.C,不難發(fā)現(xiàn)其中Delay_us(__IO u32 nTime)函數(shù)中設(shè)置了一個(gè)名為TimingDelay的32位變量,再在SysTick延時(shí)中斷中將其遞減,然后又在Delay_us(__IO u32 nTime)中使用“while(TimingDelay !=0);”循環(huán)死等SysTick延時(shí)中斷,將其遞減為零。這里實(shí)際上留下了一個(gè)巨大的bug,如果有一個(gè)中斷的優(yōu)先級(jí)比SysTick延時(shí)中斷高,打斷了SysTick延時(shí)中斷,則會(huì)導(dǎo)致SysTick延時(shí)中斷不能發(fā)生,系統(tǒng)就必然陷在while()循環(huán)中導(dǎo)致死機(jī)。若要避免出現(xiàn)這種情況,就必須保證SysTick延時(shí)中斷始終處在中斷優(yōu)先級(jí)的最高一級(jí),可以在每個(gè)時(shí)間片完成一次TimingDelay變量的遞減。
幾乎所有的微處理器都具有中斷及響應(yīng)、中斷處理的一套軟硬件設(shè)備和流程,為了實(shí)現(xiàn)多個(gè)中斷的響應(yīng),當(dāng)然要對(duì)它們進(jìn)行優(yōu)先級(jí)劃分,STM32也不例外。STM32中的中斷優(yōu)先級(jí)還有搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)的區(qū)別[4],中斷搶占優(yōu)先級(jí)是指當(dāng)多個(gè)中斷同時(shí)發(fā)生時(shí)哪個(gè)中斷優(yōu)先搶占資源,這里的資源指的是CPU處理時(shí)間和內(nèi)存等資源。中斷響應(yīng)優(yōu)先級(jí)是指在相同的中斷搶占優(yōu)先級(jí)中的優(yōu)先級(jí)劃分,也就是說當(dāng)多個(gè)搶占優(yōu)先級(jí)中斷同時(shí)發(fā)生時(shí),或者高優(yōu)先級(jí)中斷結(jié)束后,同優(yōu)先級(jí)的中斷中CPU優(yōu)先處理哪個(gè)中斷。
在STM32中,可以人為地設(shè)定各個(gè)設(shè)備中斷的優(yōu)先級(jí),這樣就可以對(duì)它們的觸發(fā)、響應(yīng)的優(yōu)先級(jí)做出合理的規(guī)劃。同時(shí),如果沒有合理的規(guī)劃好中斷優(yōu)先級(jí),很可能給單片機(jī)系統(tǒng)帶來不可預(yù)計(jì)的后果,也可能陷入不停地循環(huán)——遞歸的中斷調(diào)用中,甚至可能造成系統(tǒng)死機(jī)。前述的Delay_us()庫函數(shù)中的SysTick延時(shí)中斷被高一級(jí)中斷打斷之后進(jìn)入死循環(huán)導(dǎo)致死機(jī)就是一個(gè)例子。
3.1 實(shí)例程序分析
在一個(gè)簡(jiǎn)單的單片機(jī)程序“串口接收數(shù)據(jù)-控制LED閃燈次數(shù)”中,要用到串口中斷和PC機(jī)通信以及Delay_us()函數(shù)完成LED閃燈延時(shí),其中的Delay_us()函數(shù)就要用到SysTick中斷。最初,我們把Delay_us()函數(shù)簡(jiǎn)單地寫在了串口中斷處理函數(shù)USARTx_IRQHandler()里,結(jié)果發(fā)現(xiàn)單片機(jī)常常意外死機(jī)。多次跟蹤調(diào)試后發(fā)現(xiàn),只要進(jìn)入U(xiǎn)SARTx_IRQHandler()中斷,延時(shí)程序Delay_us()函數(shù)就經(jīng)常不再正常工作,LED也就不再繼續(xù)閃爍??梢娫谑褂肧TM32時(shí),不能像使用51單片機(jī)或者AVR單片機(jī)那樣用一個(gè)簡(jiǎn)單使能中斷、禁止中斷指令來解決這個(gè)問題,問題的關(guān)鍵在于多個(gè)中斷之間的優(yōu)先級(jí)調(diào)整來分配CPU資源。解決的辦法是,將SysTick中斷的搶占優(yōu)先級(jí)設(shè)高,讓它能夠打斷USARTx中斷隨時(shí)獲得CPU資源,在一個(gè)系統(tǒng)中Delay_us()函數(shù)要完成最基本的延時(shí)功能,從前面對(duì)SysTick.C文件中它的分析可知,它往往需要獲得最高的中斷優(yōu)先級(jí)才能保證不陷入“while(TimingDelay !=0);”死循環(huán),因?yàn)镾ysTick中斷一旦被打斷,TimingDelay變量就不能完成遞減,“while(TimingDelay !=0);”死循環(huán)就會(huì)發(fā)生。
前述的LED閃燈程序死機(jī),究其實(shí)質(zhì)就是因?yàn)榇谥袛郩SARTx服務(wù)子程序的優(yōu)先級(jí)比SysTick中斷來的高,打斷了SysTick中斷,使得TimingDelay變量的遞減過程串口中斷USARTx服務(wù)子程序被破壞,所以在Delay_us()函數(shù)中發(fā)生了“while(TimingDelay !=0);”死循環(huán),系統(tǒng)陷入了死機(jī)。
3.2 STM32的串口庫函數(shù)及其中斷設(shè)置
在STM32中有多個(gè)硬件串口設(shè)備可以訪問,因此當(dāng)設(shè)置好串口設(shè)備的相應(yīng)I/O口輸入/輸出特性后,在其硬件庫中可以直接調(diào)用串口發(fā)送函數(shù)USART_SendData(USARTx,data),將data發(fā)到串口USARTx,也可以在串口接收中斷函數(shù)USARTx_IRQHandler()里面寫下對(duì)應(yīng)串口USARTx的接收中斷處理函數(shù)。但是,這里由于串口接收事件是被動(dòng)的、未知的,所以我們采用了中斷的方式來完成,因此需要設(shè)置其對(duì)應(yīng)的中斷優(yōu)先級(jí),具體代碼如下:
NVIC_SetPriority(SysTick_IRQn,0x00);
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
//中斷搶占先等級(jí)1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
//中斷響應(yīng)優(yōu)先級(jí)2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//打開中斷
NVIC_Init(&NVIC_InitStructure);
在這個(gè)程序?qū)嵗?用“NVIC_SetPriority(SysTick_IRQn,0x00);”將SysTick中斷的搶占優(yōu)先級(jí)設(shè)置為0(最高),把“NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1”設(shè)置為次高(把串口中斷的搶占優(yōu)先級(jí)設(shè)置為1),這樣既保證了SysTick中斷處于中斷優(yōu)先級(jí)的最高一層不會(huì)被其他中斷打斷,Delay_us()函數(shù)不會(huì)進(jìn)入死循環(huán),又保證了串口函數(shù)的優(yōu)先級(jí)為次高不被其他程序打斷,閃燈次數(shù)有著一定的實(shí)時(shí)性。
3.3 程序運(yùn)行結(jié)果
經(jīng)過以上優(yōu)先級(jí)調(diào)整后,多次實(shí)驗(yàn)結(jié)果表明:程序順利運(yùn)行完成了PC上位機(jī)控制下位機(jī)完成LED閃燈次數(shù)的功能結(jié)果表明下位機(jī)沒有再次進(jìn)入死循環(huán)。
[1] 張炳先,王密,潘俊.基于卡爾曼濾波的光學(xué)遙感影像高精度復(fù)原處理[J].武漢大學(xué)學(xué)報(bào):信息科學(xué)版,2015,40(7):964-969.
[2] 劉軍.例說STM32[M].北京:北京航空航天大學(xué)出版社,2012.
[3] Texas Instruments.德州儀器高性能模擬器件高校應(yīng)用指南,2014.
[4] JosephYiu.Coretex-M3權(quán)威指南[M]. 宋巖,譯.北京:北京航空航天大學(xué)出版社,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
福建省科技廳農(nóng)業(yè)科技計(jì)劃重點(diǎn)項(xiàng)目(2013N0027) 蔬菜大棚的智能化改造;福建省教育廳青年教師培育計(jì)劃項(xiàng)目(JB12166) 分布式太陽能面板自動(dòng)跟蹤伺服系統(tǒng);福建省教育廳青年教師培育計(jì)劃項(xiàng)目(JA09186) 基于電流刺激模型的新型電刺激儀。
TP368.1
A
?迪娜
2016-11-21)