新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > STM32定時器詳解 -----影子寄存器,預裝寄存器

        STM32定時器詳解 -----影子寄存器,預裝寄存器

        作者: 時間:2016-11-26 來源:網絡 收藏
        ● 重復計數器被重置為TIMx_RCR寄存器中的內容
        ● 預分頻器的緩存器被加載為預裝載(TIMx_PSC寄存器)的值。
        ● 當前的自動加載寄存器被更新為預裝載值(TIMx_ARR寄存器中的內容)。注:如果因為計數器溢出而產生更新,自動重裝載將在計數器重載入之前被更新,因此下一個周期將是預期的值(計數器被裝載為新的值)。
        下面是一些計數器在不同時鐘頻率下的操作的例子:
        內部時鐘分頻因子為1,TIMx_ARR=0x6時的計數器時序圖:
        內部時鐘分頻因子為2時的計數器時序圖:
        內部時鐘分頻因子為4,TIMx_ARR=0x36時的計數器時序圖:
        注:在此無論是中心對齊模式2或3都是在溢出時與UIF標志一起使用
        內部時鐘分頻因子為N,計數器時序圖如下:
        ARPE=1時的更新事件(計數器下溢),計數器時序圖如下:
        計數器寄存器各位的描述如下:
        位15:0 ARR[15:0]: 自動重裝載的值 (Prescaler value)
        ARR包含了將要裝載入實際的自動重裝載寄存器的值。 詳細參考數據手冊13.3.1節:有關ARR的更新和動作。 當自動重裝載的值為空時,計數器不工作。
        4.重復計數器
        前面解釋了計數器上溢/下溢時更新事件(UEV)是如何產生的,然而事實上它只能在重復計數達到0的時候產生。這個特性對產生PWM信號非常有用。
        這意味著在每N次計數上溢或下溢時,數據從預裝載寄存器傳輸到影子寄存器(TIMx_ARR自動重載入寄存器,TIMx_PSC預裝載寄存器,還有在比較模式下的捕獲/比較寄存器TIMx_CCRx),N是TIMx_RCR重復計數寄存器中的值。
        重復計數器在下述任一條件成立時遞減:
        ● 向上計數模式下每次計數器溢出時,
        ● 向下計數模式下每次計數器下溢時,
        ● 中央對齊模式下每次上溢和每次下溢時。雖然這樣限制了PWM的最大循環周期為128,但它能夠在每個PWM周期2次更新占空比。在中央對齊模式下,因為波形是對稱的,如果每個PWM周期中僅刷新一次比較寄存器,則最大的分辨率為2xTck。
        重復計數器是自動加載的,重復速率是由TIMx_RCR寄存器的值定義。當更新事件由軟件產生(通過設置TIMx_EGR 中的UG位)或者通過硬件的從模式控制器產生,則無論重復計數器的值是多少,立即發生更新事件,并且TIMx_RCR寄存器中的內容被重載入到重復計數器。
        下圖為不同模式下更新速率的例子,及TIMx_RCR的寄存器設置
        重復計數器各位的描述如下:
        位15:8 保留位,始終讀為0。
        位7:0 REP[7:0]: 重復計數器的值 (Repetition counter value) 開啟了預裝載功能后,這些位允許用戶設置比較寄存器的更新速率(即周期性地從預裝載寄存器傳輸到當前寄存器);如果允許產生更新中斷,則會同時影響產生更新中斷的速率。
        每次向下計數器REP_CNT達到0,會產生一個更新事件并且計數器REP_CNT重新從REP值開始計數。由于REP_CNT只有在周期更新事件U_RC發生時才重載REP值,因此對TIMx_RCR寄存器寫入的新值只在下次周期更新事件發生時才起作用。 這意味著在PWM模式中,(REP+1)對應著:
        - 在邊沿對齊模式下,PWM周期的數目;
        - 在中心對稱模式下,PWM半周期的數目;
        5.控制寄存器1
        控制寄存器1各位的描述如下:
        位15:10 保留,始終讀為0。
        位9:8 CKD[1:0]:時鐘分頻因子 (Clock division)
        這2位定義在定時器時鐘(CK_INT)頻率、死區時間和由死區發生器與數字濾波器(ETR,TIx)所用的采樣時鐘之間的分頻比例。
        00:tDTS = tCK_INT
        01:tDTS = 2 x tCK_INT
        10:tDTS = 4 x tCK_INT
        11:保留,不要使用這個配置
        位7 ARPE:自動重裝載預裝載允許位 (Auto-reload preload enable)
        0:TIMx_ARR寄存器沒有緩沖;
        1:TIMx_ARR寄存器被裝入緩沖器。
        位6:5 CMS[1:0]:選擇中央對齊模式 (Center-aligned mode selection)
        00:邊沿對齊模式。計數器依據方向位(DIR)向上或向下計數。
        01:中央對齊模式1。計數器交替地向上和向下計數。配置為輸出的通道(TIMx_CCMRx寄存器中CCxS=00)的輸出比較中斷標志位,只在計數器向下計數時被設置。
        10:中央對齊模式2。計數器交替地向上和向下計數。配置為輸出的通道(TIMx_CCMRx寄存器中CCxS=00)的輸出比較中斷標志位,只在計數器向上計數時被設置。
        11:中央對齊模式3。計數器交替地向上和向下計數。配置為輸出的通道(TIMx_CCMRx寄存器中CCxS=00)的輸出比較中斷標志位,在計數器向上和向下計數時均被設置。
        在計數器開啟時(CEN=1),不允許從邊沿對齊模式轉換到中央對齊模式。
        位4 DIR:方向 (Direction)
        0:計數器向上計數;
        1:計數器向下計數。
        當計數器配置為中央對齊模式或編碼器模式時,該位為只讀。
        位3 OPM:單脈沖模式 (One pulse mode)
        0:在發生更新事件時,計數器不停止;
        1:在發生下一次更新事件(清除CEN位)時,計數器停止。
        位2 URS:更新請求源 (Update request source)
        軟件通過該位選擇UEV事件的源
        0:如果使能了更新中斷或DMA請求,則下述任一事件產生更新中斷或DMA請求:
        −計數器溢出/下溢
        −設置UG位
        −從模式控制器產生的更新
        1:如果使能了更新中斷或DMA請求,則只有計數器溢出/下溢才產生更新中斷或DMA請求
        位1 UDIS:禁止更新 (Update disable)
        軟件通過該位允許/禁止UEV事件的產生
        0:允許UEV。更新(UEV)事件由下述任一事件產生:
        −計數器溢出/下溢
        −設置UG位
        −從模式控制器產生的更新 具有緩存的寄存器被裝入它們的預裝載值。(更新影子寄存器)
        1:禁止UEV。不產生更新事件,影子寄存器(ARR、PSC、CCRx)保持它們的值。如果設置了UG位或從模式控制器發出了一個硬件復位,則計數器和預分頻器被重新初始化。
        位0 CEN:使能計數器 (Counter enable)
        0:禁止計數器;
        1:使能計數器。
        在軟件設置了CEN位后,外部時鐘、門控模式和編碼器模式才能工作。觸發模式可以自動地通過硬件設置CEN位。
        6.事件產生寄存器
        位15:8 保留,始終讀為0。
        位7 BG:產生剎車事件 (Break generation) 該位由軟件置’1’,用于產生一個剎車事件,由硬件自動清’0’。
        0:無動作;
        1:產生一個剎車事件。此時MOE=0、BIF=1,若開啟對應的中斷和DMA,則產生相應的中斷和DMA。
        位6 TG:產生觸發事件 (Trigger generation) 該位由軟件置’1’,用于產生一個觸發事件,由硬件自動清’0’。
        0:無動作;
        1:TIMx_SR寄存器的TIF=1,若開啟對應的中斷和DMA,則產生相應的中斷和DMA。
        位5 COMG:捕獲/比較事件,產生控制更新 (Capture/Compare control update generation) 該位由軟件置’1’,由硬件自動清’0’。
        0:無動作;
        1:當CCPC=1,允許更新CCxE、CCxNE、OCxM位。
        該位只對擁有互補輸出的通道有效。
        位4 CC4G:產生捕獲/比較4事件 (Capture/Compare 4 generation) 參考CC1G描述。
        位3 CC3G:產生捕獲/比較3事件 (Capture/Compare 3 generation) 參考CC1G描述。
        位2 CC2G:產生捕獲/比較2事件 (Capture/Compare 2 generation) 參考CC1G描述。
        位1 CC1G:產生捕獲/比較1事件 (Capture/Compare 1 generation) 該位由軟件置’1’,用于產生一個捕獲/比較事件,由硬件自動清’0’。
        0:無動作;
        1:在通道CC1上產生一個捕獲/比較事件:
        若通道CC1配置為輸出: 設置CC1IF=1,若開啟對應的中斷和DMA,則產生相應的中斷和DMA。
        若通道CC1配置為輸入: 當前的計數器值被捕獲至TIMx_CCR1寄存器;設置CC1IF=1,若開啟對應的中斷和DMA,則產生相應的中斷和DMA。
        若CC1IF已經為1,則設置CC1OF=1。
        位0 UG:產生更新事件 (Update generation) 該位由軟件置’1’,由硬件自動清’0’。
        0:無動作;
        1:重新初始化計數器,并產生一個更新事件。注意預分頻器的計數器也被清’0’(但是預分頻系數不變)。若在中心對稱模式下或DIR=0(向上計數)則計數器被清’0’;若DIR=1(向下計數)則計數器取TIMx_ARR的值。
        關于剎車事件,觸發事件,捕獲比較事件的描述,詳見數據手冊13章
        程序分析:
        固件庫函數分析:
        STM32的高級定時器功能十分強大,但相應的功能強大就意味著結構復雜。復雜的結構帶來的是復雜的庫函數。
        高級定時器TIM1和TIM8一共有著80多個庫函數,如果對其一一介紹,不但浪費時間,浪費精力,還有可能變成類似《固件庫使用手冊》一樣的東西。在學習的時候,我們對事物的認知總是螺旋上升的,尤其是我們做嵌入式開發,當遇到一個新的系統或者硬件,指望著看一遍數據手冊,就完全掌握其使用方法是不可能的。所以,我們先建立起一個最簡單,最基礎的實驗,方便對新事物有著一個感性的直觀的認知。有了清晰的認知,明白了基本原理后,后面的學習速度就會大大加快,也能的心應手了.看數據手冊和固件庫函數的時候,不要圖快,不要浮躁,指望著看看相關的資料,復制下固件庫例程的代碼把程序搞定,這不叫“寫代碼”,這叫“移植”。基礎打的不牢靠,對于細節問題理解的不清晰,是不可能真正的學好ARM的.如果想繼續學習的話,你會發現,你“節省”的時間,在越來越深入后,就會給你帶來雙倍的“節省時間”長的麻煩.
        ----------作者的心得在"stm32f10x_tim.h"中可以看到如下定義:
        typedef struct { uint16_t TIM_Prescaler; uint16_t TIM_CounterMode; uint16_t TIM_Period; uint16_t TIM_ClockDivision; uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;
        庫函數TIM_TimeBaseInit()的原型如下
        void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct) { uint16_t tmpcr1 = 0; assert_param(IS_TIM_ALL_PERIPH(TIMx)); assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode)); assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision)); tmpcr1 = TIMx->CR1; if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)|| (TIMx == TIM4) || (TIMx == TIM5)) { tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS))); tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode; } if((TIMx != TIM6) && (TIMx != TIM7)) { tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD)); tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision; } TIMx->CR1 = tmpcr1; TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ; TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler; if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17)) { TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter; } TIMx->EGR = TIM_PSCReloadMode_Immediate; }
        正如函數名,和結構體名所描述的,這個函數的作用為,初始化TIM1的時基部分.
        結合著數據手冊和上面的高級定時器框圖和時鐘簡介可知,我們使用高級定時器TIM1中斷時對TIM1的時基配置順序如下所示。
        在此例中,我們可以這樣定義他.
        TIM_TimeBaseStructure.TIM_Prescaler=(18000-1); //時鐘預分頻 TIM_TimeBaseStructure.TIM_Period=(4000-1); //定時器初始值 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上計數模式 TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 時鐘分割 TIM_CKD_DIV1 為 0x0 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); //初始化定時器的值
        上面的初始化流程圖已經說明,
        定時器中斷頻率 = 時鐘頻率/(時鐘預分頻+1)/(計數器裝載值+1)
        所以我們要達到1S間隔的跑馬燈,定時器的中斷頻率為1Hz,所以這里只要時鐘分頻的值與定時器的計數器的裝載值之積為72MHZ且不越界即可
        關于計數模式,在stm32f10x.h中有如下的定義
        #define TIM_CounterMode_Up ((uint16_t)0x0000) #define TIM_CounterMode_Down ((uint16_t)0x0010) #define TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020) #define TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040) #define TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060)
        上一頁 1 2 下一頁

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 铜陵市| 清水县| 双鸭山市| 巨鹿县| 启东市| 元朗区| 湖南省| 东乌珠穆沁旗| 康马县| 阿尔山市| 沅江市| 沈丘县| 建德市| 昭觉县| 滦南县| 神木县| 大新县| 宜黄县| 河津市| 克拉玛依市| 子长县| 台山市| 新乡市| 新民市| 房产| 佛冈县| 监利县| 邮箱| 繁昌县| 同心县| 临武县| 威信县| 巴林左旗| 若尔盖县| 屏南县| 祁门县| 兴化市| 雅安市| 贵阳市| 道孚县| 仁怀市|