STM32之TIM通用定時器


本文介紹如何使用STM32標准外設庫配置並使用定時器,定時器就是設置一個計時器,待計時時間到之后產生一個中斷,程序接收到中斷之后可以執行特定的程序,跟現實中的鬧鍾功能類似。與延時功能不同,定時器計時過程中程序可以執行其他程序。最簡單直觀的應用為定時翻轉指定IO引腳。本例程使用通用定時器TIM3,每100ms翻轉GPIOB的Pin5輸出,如果該引腳外接有LED燈,可以看到LED燈周期性的閃爍。

STM32F103VE系列共有8個定時器,分為基本定時器、通用定時器和高級定時器,其中通用定時器包括TIM2/3/4/5共4個,如果一個定時器不夠用,可以啟動其他幾個定時器。

本文適合對單片機及C語言有一定基礎的開發人員閱讀,MCU使用STM32F103VE系列。

 

TIM通用定時器分為兩部分,初始化和控制。

1.    初始化分兩步:通用中斷、TIM。

1.1. 通用中斷:優先級分組、中斷源、優先級、使能

  • 優先級分組:設定合適的優先級分組
  • 中斷源:選擇指定的TIM中斷源:TIM3_IRQn
  • 優先級:設定合適的優先級
  • 使能:調用庫函數即可

1.2. TIM:時鍾、預分頻器、定時器周期、分頻因子、計數模式、初始化定時器、開啟定時器中斷、使能計數器。

結構體:

typedef struct{

  uint16_t TIM_Prescaler;

  uint16_t TIM_CounterMode;

  uint16_t TIM_Period;

  uint16_t TIM_ClockDivision;

  uint8_t TIM_RepetitionCounter;

} TIM_TimeBaseInitTypeDef;   
  • 時鍾:需要使能定時器時鍾
  //開啟定時器時鍾,即內部時鍾CK_INT=72M
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  • 預分頻器:默認定時器時鍾頻率為72M,那么預分頻器設置為71,那么一次計數為1us
  //時鍾預分頻數為71,則計數器計數一次時間為1us    
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  • 定時器周期:設置為999,那么產生一次定時器中斷的時間為1ms    
  //自動重裝載寄存器為999,則產生一次中斷時間為1ms
  TIM_TimeBaseStructure.TIM_Period = 1000 - 1;   
  • 計數模式:一般選擇向上計數模式
  // 計數器計數模式,選擇向上計數模式
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  • 時鍾分頻因子:一般選擇1分頻
  // 時鍾分頻因子,選擇1分頻
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  • 重復計數器的值:僅對高級定時器有效,無需設置
  • 初始化定時器:調用庫函數即可
  //初始化定時器
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  • 開啟定時器中斷
  //開啟計數器中斷
  TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
  • 使能計數器
  //使能計數器
  TIM_Cmd(TIM3, ENABLE); 

2.    處理

2.1. 中斷服務函數

定時器TIM3的中斷服務函數名稱為TIM3_IRQHandler ()。

  void TIM3_IRQHandler(void);

2.2. 中斷處理

中斷服務函數中調用TIM_GetITStatus ()函數判定中斷標志位狀態以確定中斷是否發生,調用TIM_ClearITPendingBit ()函數清除中斷標志位。

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
  {  
     TIM_ClearITPendingBit(TIM3, TIM_IT_Update);         
  }      

2.3.    計時

在定時器中斷服務函數中累加一個全局變量,在中斷外查詢該全局變量,如果達到預期的定時時間,則清除此全局變量,並執行相應的操作。

舉例來說,如果想要200ms執行某操作,那么該全局變量累加到200之后,將該全局變量置為0,然后再執行相應的操作。

 

完整代碼(僅自己編寫的部分)

  1 uint8_t times;
  2 
  3 void GPIO_OutputConfig(void)
  4 {        
  5     //定義一個GPIO_InitTypeDef類型的結構體
  6     GPIO_InitTypeDef GPIO_InitStructure;
  7 
  8     //開啟指定端口的GPIO外設時鍾
  9     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 10     
 11     //選擇要控制的GPIO引腳
 12     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    
 13 
 14     //設置引腳速率為50MHz
 15     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
 16 
 17     //設置引腳模式為通用推挽輸出
 18     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
 19 
 20     //調用庫函數,初始化GPIO
 21     GPIO_Init(GPIOB, &GPIO_InitStructure);    
 22 
 23     //設置初始狀態
 24     GPIO_ResetBits(GPIOB, GPIO_Pin_5);
 25 }
 26 
 27 //中斷優先級配置
 28 void TIM_NVICConfig(void)
 29 {
 30     NVIC_InitTypeDef NVIC_InitStructure; 
 31     
 32     // 設置中斷組為2
 33     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        
 34     // 設置中斷來源為TIM3
 35     NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ;    
 36     // 設置搶占優先級為0
 37     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     
 38     // 設置子優先級為3
 39     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;    
 40     // 使能
 41     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 42     
 43     NVIC_Init(&NVIC_InitStructure);
 44 }
 45 
 46 //TIM配置
 47 void TIM_Config(void)
 48 {
 49     TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
 50         
 51     //開啟定時器時鍾,即內部時鍾CK_INT=72M
 52     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
 53     
 54     //時鍾預分頻數為71,則計數器計數一次時間為1us
 55     TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
 56 
 57     //自動重裝載寄存器為999,則產生一次中斷時間為1ms
 58     TIM_TimeBaseStructure.TIM_Period = 1000 - 1;    
 59 
 60     // 計數器計數模式,選擇向上計數模式
 61     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
 62 
 63     // 時鍾分頻因子,選擇1分頻
 64     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
 65         
 66     // 重復計數器的值,高級定時器有效
 67 //    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
 68     
 69     //初始化定時器
 70     TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
 71         
 72     //開啟計數器中斷
 73     TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
 74         
 75     //使能計數器
 76     TIM_Cmd(TIM3, ENABLE);    
 77 }
 78 
 79 //定時器初始化函數
 80 void TIM_Init(void)
 81 {
 82     TIM_Config();
 83     TIM_NVICConfig();
 84 }
 85 
 86 //TIM3中斷服務函數
 87 void TIM3_IRQHandler(void)
 88 {
 89     if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) 
 90     {    
 91         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);           
 92         times++;
 93     }             
 94 }
 95 
 96 int main(void)
 97 {    
 98     GPIO_OutputConfig();     
 99     TIM_Init();
100 
101     //每100ms翻轉一次GPIOB pin5
102     while(1)
103     {
104         if(times == 100)
105         {
106             GPIO_SetBits(GPIOB, GPIO_Pin_5);
107         }else if(times >= 200){
108             GPIO_ResetBits(GPIOB, GPIO_Pin_5);
109             times = 0;
110         }
111     }
112 }

 

仿真結果

程序編譯成功后,點擊開始仿真,點擊,顯示邏輯分析窗口,點擊Setup,顯示設置串口,點擊新建,然后輸入要查看的端口,可同時查看多個端口,比如要查看PORTB.5,那么輸入(PORTB & 0x00000020) >>5,Display type選擇Bit,Color中選擇合適的顏色,點擊Close關閉對話框,點擊運行程序,可在邏輯分析串口看到該端口的波形。通過鼠標滾輪可對顯示波形進行縮放。

示例仿真波形如下:

 

從仿真結果來看,PORTB.5每隔100ms電平會翻轉一次,跟程序設計一致,因此TIM定時器有效。

 

源碼下載:(不包括工程文件和庫文件)

https://files.cnblogs.com/files/greatpumpkin/TIM_general.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM