單片機mcu—time定時器詳解

STM32定時器分了好幾個類別,各個類別針對功能作用都不大相同。

分別有: 1.高級定時器 、2.通用定時器、 3.基本定時器、 4.看門狗定時器 、 5.SysTick定時器 

其中看門狗定時器和SysTick定時器本篇筆記闡述,這裏主要記下對平時使用定時器作用的計時計數器的一些自己的理解。 
按照參考手冊中的定義 高級定時器 通用定時器 基本定時器,這三個定時器成上下級的關係,即基本定時器有的功能通用定時器都有,而且還增加了向下、向上/向下計數器、PWM生成、輸出比較、輸入捕獲等等功能;而高級定時器又包含了通用定時器的所有功能,另外還增加了死區互補輸出、剎車信號、加入重複計數器等等。(這裏等等功能請參考《STM32參考手冊》) 
      所以學習STM32 定時器實際就是學習一下高級定時器,然後適當的刪減後就是後面的兩種定時器了。 
假若不涉及輸出輸入,定時器的最基本用法就是計數定時作用了本篇筆記主要針對這部分的理解所寫下的。 

高級定時器中一共有20個寄存器: 

TIMx_CR1、TIMx_CR2、TIMx_SMCR、TIMx_DIER、TIMx_SR、TIMx_EGR、TIMx_CCMR1、TIMx_CCMR2、 
TIMx_CCER、TIMx_CNT、TIMx_PSC、TIMx_ARR、TIMx_RCR、TIMx_CCR1、TIMx_CCR2、TIMx_CCR3、 
TIMx_CCR4、TIMx_BDTR、TIMx_DCR、TIMx_DMAR 
好吧一堆寄存器光看都看到眼花繚亂了,當然不是所有寄存器都涉及到才能讓定時器工作的,例如最基本的定時功能所涉及的只有幾個與時基功能相關的寄存器,TIMx_CNT(計數器寄存器)、TIMx_PSC(預分頻器寄存器)、TIMx_ARR(自動裝載寄存器)、TIMx_RCR(重複次數寄存器)。參考手冊中有那麼 衣服定時器的框圖。這幾個寄存器的關係如圖所示的: 

CK_PSC這根時鐘線上的時鐘源的選擇,即給定時器計數計時的時鐘源的輸入方式,有四種方式,分別是內部時鐘,外部時鐘模式1,外部時鐘模式2,內部觸發。這部分日後再說,這裏暫且使用最常用的內部時鐘方式,既是當內部時鐘爲72MHz 的內部時鐘源。 
如圖所示的,時鐘源首先進入預分頻器,然後再進入預先裝入自動重裝載寄存器的計數器中,當計數器溢出時產生一次中斷和一次事件更新。除了多了一個PSC,其他的基本和51單片機很相似,初次看參考手冊中的功能描述中出現了好多次“更新事件(UEV)”。這究竟是怎麼的一樣東西呢? 在這裏有個新概念叫“影子寄存器”,在上圖中,可以看到PSC、ARR、REP(重複計數器中的低八位)這三個寄存器框框下都有個黑影,每次這三個寄存器就是影子寄存器,如果看到參考手冊全圖中還可以看到另外還有幾個框框下也有陰影部分的,這幾個寄存器也是影子寄存器。何謂影子寄存器呢,例如PSC寄存器可以理解爲有兩個,一個是用戶可以訪問到的寄存器,可讀可寫,另一部分就是客戶訪問不到的但其裝載值和實際寄存器是密切關聯的,當程序在運行中改寫PSC 這時候影子寄存器的作用就體現了,因爲立刻寫入的值可能會大於或小於目前正在運行的寄存器中的數值,而真實在運行時候的正是這個影子寄存器中的值,而程序寫入的是可訪問的寄存器,只有當產生一個更新事件的時候影子寄存器纔會讀入訪問寄存器中的值,這樣就可以防止突然修改而產生的非正常中斷或不會中斷等異常問題。當然在控制器CR1中控制這個影子寄存器是否起作用,不起作用的話就是立即寫入這個數值到寄存器中。

另外高級定時器中還有RCR重複次數寄存器這個,也是比較簡單的事件更新(UEV) 都是在RCR爲0的情況下產生計數器溢出而產生的,當RCR中不爲0的時候計數器溢出只會使得重複次數寄存器遞減而不會產生UEV,這樣就可以使得定時器的定時情況得以延長,而相當於有16位的分頻器,16位的計數器,再加入16位的重複次數,一共48位的計數定時器。詳細看參考手冊,這個很好理解。 

    基本的基時單元就是上面提及的這幾個,下面看看3.0庫是如何實習的基本使用

  1. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 

  2.         
  3.       TIM_DeInit(TIM2);                                           //重新將Timer設置爲缺省值 
  4.         
  5.       TIM_InternalClockConfig(TIM2);                              //採用內部時鐘給TIM2提供時鐘源       
  6.       TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;            //預分頻係數爲36000-1,這樣計數器時鐘爲72MHz/36000 = 2kHz        
  7.       TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //設置時鐘分割       
  8.       TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //設置計數器模式爲向上計數模式        
  9.       TIM_TimeBaseStructure.TIM_Period = 2000 - 1;           //設置計數溢出大小,每計2000個數就產生一個更新事件 
  10.       TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);         //將配置應用到TIM2中 
  11.       TIM_ClearFlag(TIM2, TIM_FLAG_Update);                  //清除溢出中斷標誌   
  12.         
  13.       TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);                //開啓TIM2的中斷 
  14. 以上是一個最基本的定時器配置的代碼,載自網上被轉載無數次的地方…… 
  15. 中斷函數自己按照需求寫,這裏不多說。 
  16. 在庫中的初始化函數和初始化數據類型有3類,TIM_TimeBaseInitTypeDef、TIM_OCInitTypeDef、TIM_ICInitTypeDef 
  17. 與基時參數相關的數據類型是TIM_TimeBaseInitTypeDef 

  18. typedef struct 

  19.   uint16_t TIM_Prescaler;     

  20.   uint16_t TIM_CounterMode;       
  21.   uint16_t TIM_Period;           

  22.   uint16_t TIM_ClockDivision;    
  23.   uint8_t TIM_RepetitionCounter; 
  24. } TIM_TimeBaseInitTypeDef;
以上是從庫stm32f10x_tim.h中 截取的代碼,整體的數據結構可以中這段註釋中得知,不懂E文的要麼翻字典要麼翻庫函數中文翻譯 

版本(當然這個是2.0的庫,有部分會和3.0後的版本很不相同),這部分的數據類型還是很一樣的,不多說。  
接着就是TIM_TimeBaseInit()這個函數了,在stm32f10x_tim.c的224行中 

  1. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct) 

  2.   uint16_t tmpcr1 = 0; 

  3.   /* Check the parameters */ 
  4.   assert_param(IS_TIM_ALL_PERIPH(TIMx));  
  5.   assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode)); 
  6.   assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision)); 

  7.   tmpcr1 = TIMx->CR1;   

  8.   if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)|| 
  9.      (TIMx == TIM4) || (TIMx == TIM5))  
  10.   { 
  11.     /* Select the Counter Mode */ 
  12.     tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS))); 
  13.     tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode; 
  14.   } 
  15.    
  16.   if((TIMx != TIM6) && (TIMx != TIM7)) 
  17.   { 
  18.     /* Set the clock division */ 
  19.     tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD)); 
  20.     tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision; 
  21.   } 

  22.   TIMx->CR1 = tmpcr1; 

  23.   /* Set the Autoreload value */ 
  24.   TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ; 
  25.    
  26.   /* Set the Prescaler value */ 
  27.   TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler; 
  28.       
  29.   if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))   
  30.   { 
  31.     /* Set the Repetition Counter value */ 
  32.     TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter; 
  33.   } 

  34.   /* Generate an update event to reload the Prescaler and the Repetition counter 
  35.      values immediately */ 
  36.   TIMx->EGR = TIM_PSCReloadMode_Immediate;            
  37. }
可以看3.0後的函數裏把所有的TIMx都加入一個函數裏面做判斷了,不需要和2.0的區分TIM1和TIM 兩類函數,比較其基本操作都一樣無非就是多了一個兩個寄存器而已。
轉自芯片之家

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章