<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > STM32之系統(tǒng)滴答定時(shí)器

          STM32之系統(tǒng)滴答定時(shí)器

          作者: 時(shí)間:2016-11-19 來源:網(wǎng)絡(luò) 收藏

          一、SysTick(系統(tǒng)滴答定時(shí)器)概述

          本文引用地址:http://www.ex-cimer.com/article/201611/318497.htm

            操作系統(tǒng)需要一個(gè)滴答定時(shí)器周期性產(chǎn)生中斷,以產(chǎn)生系統(tǒng)運(yùn)行的節(jié)拍。在中斷服務(wù)程序里,基于優(yōu)先級(jí)調(diào)度的操作系統(tǒng)會(huì)根據(jù)進(jìn)程優(yōu)先級(jí)切換任務(wù),基于時(shí)間片輪轉(zhuǎn)系統(tǒng)會(huì)根據(jù)時(shí)間片切換任務(wù)??傊?,滴答定時(shí)器是一個(gè)操作系統(tǒng)的“心跳”。

            Cortex-M3在內(nèi)核部分封裝了一個(gè)滴答定時(shí)器--SysTick,在之前的ARM內(nèi)核通常是不會(huì)把定時(shí)器做進(jìn)內(nèi)核,定時(shí)器都是SOC廠商自己制作的外設(shè)。顯然,Cortex-M3封裝了這么一個(gè)定時(shí)器,對(duì)于將操作系統(tǒng)移植到不同SOC廠商生產(chǎn)的Cortex-M3系類MCU上,帶來了極大的方便。Cortex-M3內(nèi)核統(tǒng)一了這樣的一個(gè)系統(tǒng)滴答定時(shí)器,移植操作系統(tǒng)的時(shí)候可以使用內(nèi)核的定時(shí)器,而忽略掉不同廠商生產(chǎn)定時(shí)器帶來的分歧。

          二、SysTick control and status register(STK_CTRL)

            SysTick的控制是極其簡(jiǎn)單的,它的控制和狀態(tài)都匯聚在同一個(gè)寄存器STK_CTRL上。

            STK_CTRL的每一位的含義英文解釋都是很清晰的,不必多說。需要額外討論的是COUNTFLAG標(biāo)志位,這個(gè)標(biāo)志位代表的含義是:當(dāng)計(jì)數(shù)為0時(shí),也即STK_VAL計(jì)數(shù)至0時(shí),此標(biāo)志位置1。

            經(jīng)過筆者一番摸索,對(duì)此位有更多的看法。

          COUNTFLAG:  

          1、此位與SysTick的中斷無(wú)關(guān),不是中斷標(biāo)志位,可以算作事件標(biāo)志位(計(jì)數(shù)至0事件)。

          2、此位可以用作軟件查詢

          3、讀寫此寄存器都會(huì)硬件自動(dòng)更新COUNTFLAG的值,當(dāng)然此位的值軟件也是可以改寫的。也就是說,倘若我們輪訓(xùn)查看COUNTFLAG是否置1(也就是計(jì)數(shù)是否結(jié)束)。當(dāng)SysTick硬件上計(jì)數(shù)為0,COUNTFLAG因此硬件自動(dòng)置1。在我們軟件讀取STK_CTRL的時(shí)候,其實(shí)SysTick的STK_VAL的值已經(jīng)不是0(因?yàn)樽詣?dòng)重裝,并且可能計(jì)時(shí)幾個(gè)CLK了)。這個(gè)時(shí)候我們讀取到了COUNTFLAG的標(biāo)志位的1,同時(shí)也將COUNTFLAG自動(dòng)清零。

          三、滴答定時(shí)器應(yīng)用之精準(zhǔn)延時(shí)函數(shù)

          1、函數(shù)實(shí)現(xiàn)思路

            函數(shù)實(shí)現(xiàn)使用“輪詢狀態(tài)位COUNTFLAG”實(shí)現(xiàn)精準(zhǔn)延時(shí)節(jié)拍10us。

            在使用的時(shí)候,首先調(diào)用函數(shù)SysTick_Init配置SysTick的定時(shí)周期為10us。在延時(shí)函數(shù)中,當(dāng)啟動(dòng)定時(shí)器后,就調(diào)用函數(shù)SysTick_GetFlagStatus輪詢是否定時(shí)10us結(jié)束,如果結(jié)束就更新一下延時(shí)節(jié)拍變量nTime。

            由于SysTick定時(shí)器自動(dòng)重裝計(jì)數(shù)器初值,而且SysTick_GetFlagStatus在檢測(cè)到SET的時(shí)候,COUNTFLAG也自動(dòng)清理。所以軟件不必裝定時(shí)器初值,也不必手動(dòng)清除標(biāo)志位COUNTFLAG。

          2、函數(shù)實(shí)現(xiàn)代碼



          #include "bsp_sysTick.h"/*** @brief  讀取SysTick的狀態(tài)位COUNTFLAG* @param  無(wú)* @retval The new state of USART_FLAG (SET or RESET).*/static FlagStatus SysTick_GetFlagStatus(void) {if(SysTick->CTRL&SysTick_CTRL_COUNTFLAG_Msk) {return SET;}else{return RESET;}}/*** @brief  清除SysTick的狀態(tài)位COUNTFLAG* @param  無(wú)* @retval 無(wú)*/static void SysTick_ClearFlag(void){       SysTick->CTRL &= ~ SysTick_CTRL_COUNTFLAG_Msk;}/*** @brief  配置系統(tǒng)滴答定時(shí)器 SysTick* @param  無(wú)* @retval 1 = failed, 0 = successful*/uint32_t SysTick_Init(void){/* SystemFrequency / 1    1ms中斷一次* SystemFrequency / 100     10us中斷一次* SystemFrequency / 1 1us中斷一次*//* 設(shè)置定時(shí)周期為10us  */if (SysTick_Config(SystemCoreClock / 100)) { /* Capture error */ return (1);}/* 關(guān)閉滴答定時(shí)器且禁止中斷  */SysTick->CTRL &= ~ (SysTick_CTRL_ENABLE_Msk  SysTick_CTRL_TICKINT_Msk);                                                  return (0);}/*** @brief   us延時(shí)程序,10us為一個(gè)單位* @param  *        @arg nTime: Delay_us( 1 ) 則實(shí)現(xiàn)的延時(shí)為 1 * 10us = 10us* @retval  無(wú)*/void Delay_us(__IO uint32_t nTime){     /* 清零計(jì)數(shù)器并使能滴答定時(shí)器 */  SysTick->VAL   = 0;  SysTick->CTRL =  SysTick_CTRL_ENABLE_Msk;     for( ; nTime > 0 ; nTime--){/* 等待一個(gè)延時(shí)單位的結(jié)束 */while(SysTick_GetFlagStatus() != SET);}/* 關(guān)閉滴答定時(shí)器 */SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;}
          View Code

          3、函數(shù)的優(yōu)點(diǎn)和缺陷

          優(yōu)點(diǎn):

            使用輪詢法實(shí)現(xiàn)精準(zhǔn)延時(shí)是可靠的,因?yàn)橛布詣?dòng)重裝定時(shí)器初值,只要我們?cè)谙乱淮斡?jì)數(shù)結(jié)束(為0)之前,將節(jié)拍計(jì)數(shù)變量nTime更新,那么這個(gè)延時(shí)函數(shù)就是可靠的。

            使用輪詢法的另一個(gè)好處是沒有用到全局變量,完全是局部變量搞定了所需功能。倘若使用中斷延時(shí),必須利用全局變量給精準(zhǔn)延時(shí)函數(shù)傳遞參數(shù)。

          缺陷:

            由于使用的是輪詢法,有可能被其他的中斷打斷,假設(shè)其他的中斷的服務(wù)時(shí)間有很長(zhǎng),使得“在下一次計(jì)數(shù)結(jié)束(為0)之前,沒有將節(jié)拍計(jì)數(shù)變量nTime更新”,那么延時(shí)的時(shí)間將要增長(zhǎng)。

          4、注意

            此延時(shí)函數(shù)的最小分辨率不能設(shè)置為1us,最好設(shè)置為>=10us,這是因?yàn)檩営?xùn)的周期和1us相比具有可比性,時(shí)間誤差太大。

          四、滴答定時(shí)器應(yīng)用之程序段計(jì)時(shí)

          1、函數(shù)實(shí)現(xiàn)思路

            首先對(duì)滴答定時(shí)器初始化,計(jì)時(shí)節(jié)拍數(shù)是計(jì)數(shù)器的最大值。在感興趣的程序段開始處,啟動(dòng)定時(shí)器,在程序段的結(jié)束處關(guān)閉定時(shí)器。倘若這段時(shí)間很長(zhǎng),超過了計(jì)數(shù)器的計(jì)數(shù)最大值,就會(huì)在中斷函數(shù)中對(duì)溢出次數(shù)進(jìn)行計(jì)數(shù)。最終的程序段時(shí)間決定于計(jì)數(shù)器的數(shù)據(jù)寄存器SysTick->VAL中的剩余值和中斷溢出次數(shù)。

            另外為了使程序能夠?qū)Σ煌某绦蚨位蛘卟煌闆r下的程序段進(jìn)行計(jì)時(shí),使用了一個(gè)結(jié)構(gòu)體定義保存計(jì)時(shí)數(shù)據(jù)的結(jié)構(gòu)體類型。在對(duì)程序段進(jìn)行計(jì)時(shí)的時(shí)候,通過一個(gè)運(yùn)行指針指向所要保存的變量中。  

          2、函數(shù)代碼  

          ① User_SysTick.c



          /*********************************************************************************計(jì)時(shí)最小單位:1/72M s*計(jì)時(shí)最大長(zhǎng)度:2^32/72M = 59.65 s*使用方法:*(1) 定義一個(gè)保存計(jì)時(shí)數(shù)據(jù)的TimingVarTypeDef類型變量Time*(2) 初始化*       SysTick_Time_Init(&Time);*(3) 在while循環(huán)中放置啟動(dòng)/停止函數(shù)*     while(1){*            SysTick_Time_Start();*         測(cè)試運(yùn)行時(shí)間的代碼*            SysTick_Time_Stop();*        }*******************************************************************************//* 定義保存未使用DMA時(shí)測(cè)試程序段運(yùn)行時(shí)間的變量 */TimingVarTypeDef Time;/* 指針指向當(dāng)前保存時(shí)間的變量 */TimingVarTypeDef * CurrentTimingVar; /* 系統(tǒng)滴答定時(shí)器的中斷次數(shù) */uint32_t TimeupTimes;/*** @brief  配置系統(tǒng)滴答定時(shí)器 SysTick* @param  無(wú)* @retval 1 = failed, 0 = successful*/uint32_t SysTick_Init(void){/* 設(shè)置定時(shí)周期為最大定時(shí)數(shù)SysTick_LOAD_RELOAD_Msk  */if (SysTick_Config(SysTick_LOAD_RELOAD_Msk)) { /* Capture error */ return (1);}/* 關(guān)閉滴答定時(shí)器且禁止中斷  */SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;                                                  return (0);} /*** @brief  滴答定時(shí)器 SysTick 計(jì)時(shí)初始化* @param  初始化計(jì)時(shí)變量的成員--計(jì)時(shí)次數(shù)* @retval 無(wú)*/void SysTick_Time_Init(TimingVarTypeDef * TimingVar){/* 指針指向當(dāng)前保存時(shí)間的變量 */CurrentTimingVar = TimingVar;/* 計(jì)時(shí)次數(shù)初始化 */    CurrentTimingVar->SetSaveTimesNum = SaveTimesBufNum - 2;}/*** @brief  滴答定時(shí)器 SysTick 計(jì)時(shí)啟動(dòng)* @param  無(wú)* @retval 無(wú)*/void SysTick_Time_Start(void){/* 判斷已經(jīng)計(jì)時(shí)次數(shù)是否達(dá)到設(shè)置的計(jì)時(shí)次數(shù) */if(CurrentTimingVar->SaveTimesTemp < CurrentTimingVar->SetSaveTimesNum){/* 滴答定時(shí)器的數(shù)據(jù)寄存器清零 */SysTick->VAL = 0;/* 滴答定時(shí)器中斷次數(shù)清零 */TimeupTimes = 0;/* 啟動(dòng)滴答定時(shí)器 */SysTick->CTRL =  SysTick_CTRL_ENABLE_Msk; }}/*** @brief  滴答定時(shí)器 SysTick 計(jì)時(shí)停止并保存處理數(shù)據(jù)* @param  無(wú)* @retval 無(wú)*/void SysTick_Time_Stop(void){/* 保存已經(jīng)計(jì)時(shí)次數(shù) */    uint32_t TimesTemp = CurrentTimingVar->SaveTimesTemp;/* 保存設(shè)置計(jì)時(shí)總次數(shù) */uint32_t SetSaveTimesNum = CurrentTimingVar->SetSaveTimesNum;uint32_t i,TimeWidthAverageTemp = 0; /* 保存設(shè)置計(jì)時(shí)總次數(shù) */  if(SysTick->CTRL & SysTick_CTRL_ENABLE_Msk){/* 關(guān)閉滴答定時(shí)器 */SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;/* 計(jì)算計(jì)時(shí)總時(shí)間 */CurrentTimingVar->TimeWidth[TimesTemp] =  SysTick_LOAD_RELOAD_Msk * TimeupTimes + (SysTick_LOAD_RELOAD_Msk - SysTick->VAL + 1);/* 判斷計(jì)時(shí)次數(shù)是否滿 */if((++TimesTemp) == SetSaveTimesNum){/* 計(jì)算平均值 */for(i = 0;i < SetSaveTimesNum; i++){TimeWidthAverageTemp += CurrentTimingVar->TimeWidth[i];}CurrentTimingVar->TimeWidthAvrage = TimeWidthAverageTemp/SetSaveTimesNum;    }/* 已經(jīng)計(jì)時(shí)次數(shù)變量加1 */CurrentTimingVar->SaveTimesTemp++;    }}
          View Code

          ② User_SysTick.h



          #define SaveTimesBufNum 4                           /* 計(jì)時(shí)存儲(chǔ)區(qū)的大小 */typedef struct {uint32_t SetSaveTimesNum;                     /* 設(shè)置計(jì)時(shí)總次數(shù) */uint32_t SaveTimesTemp;                        /* 已經(jīng)計(jì)時(shí)的次數(shù) */uint32_t TimeWidth[SaveTimesBufNum];        /* 計(jì)時(shí)存儲(chǔ)區(qū) */uint32_t TimeWidthAvrage;                     /* 平均計(jì)時(shí)長(zhǎng)度 */} TimingVarTypeDef;                                /*  計(jì)時(shí)變量類型 */extern TimingVarTypeDef Time;extern uint32_t TimeupTimes;extern uint32_t SysTick_Init(void);extern void SysTick_Time_Init(TimingVarTypeDef * TimingVar);extern void SysTick_Time_Start(void);extern void SysTick_Time_Stop(void);
          View Code

          ③ stm32f10x_it.c



          /*** @brief  This function handles SysTick Handler.* @param  None* @retval None*/void SysTick_Handler(void){TimeupTimes++;}
          View Code

          參考資料:《STM32F10xxx Cortex-M3 programming manual.pdf》

               《STM32庫(kù)開發(fā)實(shí)戰(zhàn)指南》



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();