【STM32】定时器程序
00. 目錄
文章目錄
- 00. 目錄
- 01. 通用定時器簡介
- 02. 通用定時器時鐘
- 03. 定時器配置步驟
- 04. 硬件設計
- 05. 程序示例
- 06. 附錄
- 07. 聲明
01. 通用定時器簡介
STM32F4 的通用定時器包含一個 16 位或 32 位自動重載計數器(CNT),該計數器由可編程預分頻器(PSC)驅動。STM32F4 的通用定時器可以被用于:測量輸入信號的脈沖長度(輸入捕獲)或者產生輸出波形(輸出比較和 PWM)等。 使用定時器預分頻器和 RCC 時鐘控制器預分頻器,脈沖長度和波形周期可以在幾個微秒到幾個毫秒間調整。STM32F4 的每個通用定時器都是完全獨立的,沒有互相共享的任何資源。
STM3 的通用 TIMx (TIM2~TIM5 和 TIM9~TIM14)定時器功能包括:
16 位/32 位(僅 TIM2 和 TIM5)向上、向下、向上/向下自動裝載計數器(TIMx_CNT),注意:TIM9~TIM14 只支持向上(遞增)計數方式。
16 位可編程(可以實時修改)預分頻器(TIMx_PSC),計數器時鐘頻率的分頻系數為 1~65535 之間的任意數值。
3)4 個獨立通道(TIMx_CH14,TIM9TIM14 最多 2 個通道),這些通道可以用來作為:
A.輸入捕獲
B.輸出比較
C.PWM 生成(邊緣或中間對齊模式) ,注意:TIM9~TIM14 不支持中間對齊模式
D.單脈沖模式輸出
4)可使用外部信號(TIMx_ETR)控制定時器和定時器互連(可以用 1 個定時器控制另外一個定時器)的同步電路。
5)如下事件發生時產生中斷/DMA(TIM9~TIM14 不支持 DMA):
A.更新:計數器向上溢出/向下溢出,計數器初始化(通過軟件或者內部/外部觸發)
B.觸發事件(計數器啟動、停止、初始化或者由內部/外部觸發計數)
C.輸入捕獲
D.輸出比較
E.支持針對定位的增量(正交)編碼器和霍爾傳感器電路(TIM9~TIM14 不支持)
F.觸發輸入作為外部時鐘或者按周期的電流管理(TIM9~TIM14 不支持)
02. 通用定時器時鐘
定時器的時鐘來源有 4 個:
1)內部時鐘(CK_INT)
2)外部時鐘模式 1:外部輸入腳(TIx)
3)外部時鐘模式 2:外部觸發輸入(ETR),僅適用于 TIM2、TIM3、TIM4
4)內部觸發輸入(ITRx):使用 A 定時器作為 B 定時器的預分頻器(A 為 B 提供時鐘)。
這些時鐘,具體選擇哪個可以通過 TIMx_SMCR 寄存器的相關位來設置。這里的 CK_INT時鐘是從 APB1 倍頻的來的,除非 APB1 的時鐘分頻數設置為 1(一般都不會是 1),否則通用定時器 TIMx 的時鐘是 APB1 時鐘的 2 倍,當 APB1 的時鐘不分頻的時候,通用定時器 TIMx的時鐘就等于 APB1 的時鐘。這里還要注意的就是高級定時器以及 TIM9~TIM11 的時鐘不是來自 APB1,而是來自 APB2 的。
這里順帶介紹一下 TIMx_CNT 寄存器,該寄存器是定時器的計數器,該寄存器存儲了當前定時器的計數值。
03. 定時器配置步驟
3.1 TIM3 時鐘使能。
TIM3 是掛載在 APB1 之下,所以我們通過 APB1 總線下的時鐘使能函數來使能 TIM3。調用的函數是:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能 TIM3 時鐘3.2 初始化定時器參數 數, 設置 自動重裝值 , 分頻系數 ,計數方式 等。
在庫函數中,定時器的初始化參數是通過初始化函數 TIM_TimeBaseInit 實現的:
void TIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);第一個參數是確定是哪個定時器,這個比較容易理解。第二個參數是定時器初始化參數結構體指針,結構體類型為TIM_TimeBaseInitTypeDef,下面我們看看這個結構體的定義:
typedef struct {uint16_t TIM_Prescaler;uint16_t TIM_CounterMode;uint16_t TIM_Period;uint16_t TIM_ClockDivision;uint8_t TIM_RepetitionCounter; } TIM_TimeBaseInitTypeDef;這個結構體一共有 5 個成員變量,要說明的是,對于通用定時器只有前面四個參數有用,最后一個參數 TIM_RepetitionCounter 是高級定時器才有用的,這里不多解釋。
第一個參數 TIM_Prescaler 是用來設置分頻系數的,剛才上面有講解。
第二個參數 TIM_CounterMode 是用來設置計數方式,上面講解過,可以設置為向上計數,向下計數方式還有中央對齊計數方式,比較常用的是向上計數模式 TIM_CounterMode_Up 和向下計數模式 TIM_CounterMode_Down。
第三個參數是設置自動重載計數周期值,這在前面也已經講解過。
第四個參數是用來設置時鐘分頻因子。
針對 TIM3 初始化范例代碼格式:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = 5000; TIM_TimeBaseStructure.TIM_Prescaler =7199; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);3.3 設置 TIM3_DIER 允許更新中斷。
因為我們要使用 TIM3 的更新中斷,寄存器的相應位便可使能更新中斷。在庫函數里面定時器中斷使能是通過 TIM_ITConfig 函數來實現的:
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);第一個參數是選擇定時器號,這個容易理解,取值為 TIM1~TIM17。
第二個參數非常關鍵,是用來指明我們使能的定時器中斷的類型,定時器中斷的類型有很多種,包括更新中斷 TIM_IT_Update,觸發中斷 TIM_IT_Trigger,以及輸入捕獲中斷等等。
第三個參數就很簡單了,就是失能還是使能。
例如我們要使能 TIM3 的更新中斷,格式為:
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );3.4 TIM3 中斷優先級設置。
在定時器中斷使能之后,因為要產生中斷,必不可少的要設置 NVIC 相關寄存器,設置中斷優先級。之前多次講解到用 NVIC_Init 函數實現中斷優先級的設置。
3.5 允許 TIM3 工作,也就是使能 TIM3 。
光配置好定時器還不行,沒有開啟定時器,照樣不能用。我們在配置完后要開啟定時器,通過 TIM3_CR1 的 CEN 位來設置。在固件庫里面使能定時器的函數是通過 TIM_Cmd 函數來實現的:
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)這個函數非常簡單,比如我們要使能定時器 3,方法為:
TIM_Cmd(TIM3, ENABLE); //使能 TIMx 外設3.6 編寫中斷服務函數。
在最后,還是要編寫定時器中斷服務函數,通過該函數來處理定時器產生的相關中斷。在中斷產生后,通過狀態寄存器的值來判斷此次產生的中斷屬于什么類型。然后執行相關的操作,我們這里使用的是更新(溢出)中斷,所以在狀態寄存器 SR 的最低位。在處理完中斷之后應該向 TIM3_SR 的最低位寫 0,來清除該中斷標志。
在固件庫函數里面,用來讀取中斷狀態寄存器的值判斷中斷類型的函數是
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t)該函數的作用是,判斷定時器 TIMx 的中斷類型 TIM_IT 是否發生中斷。比如,我們要判斷定時器 3 是否發生更新(溢出)中斷,方法為:
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){}固件庫中清除中斷標志位的函數是:
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT)該函數的作用是,清除定時器 TIMx 的中斷 TIM_IT 標志位。使用起來非常簡單,比如我們在TIM3 的溢出中斷發生后,我們要清除中斷標志位,方法是:
TIM_ClearITPendingBit(TIM3, TIM_IT_Update )這里需要說明一下,固件庫還提供了兩個函數用來判斷定時器狀態以及清除定時器狀態標志位的函數 TIM_GetFlagStatus 和 TIM_ClearFlag,他們的作用和前面兩個函數的作用類似。只是在 TIM_GetITStatus 函數中會先判斷這種中斷是否使能,使能了才去判斷中斷標志位,而TIM_GetFlagStatus 直接用來判斷狀態標志位。
04. 硬件設計
用到的硬件資源有:
1) 指示燈 DS0 和 DS1
2) 定時器 TIM3
將通過 TIM3 的中斷來控制 DS1 的亮滅,DS1 是直接連接到 PF10 上的,這個前面已經有介紹了。而 TIM3 屬于 STM32F4 的內部資源,只需要軟件設置即可正常工作。
05. 程序示例
timer.h
#ifndef __TIMER_H__ #define __TIMER_H__#include "sys.h"//定時器初始化 void TIM3_Int_Init(u16 arr, u16 psc);#endif /*__TIMER_H__*/timer.c
#include "timer.h" #include "led.h"//定時器初始化 //arr:自動重裝值。 //psc:時鐘預分頻數 //定時器溢出時間計算方法:Tout=((arr+1)*(psc+1))/Ft us. //Ft=定時器工作頻率,單位:Mhz //這里使用的是定時器3! void TIM3_Int_Init(u16 arr, u16 psc) {TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;NVIC_InitTypeDef NVIC_InitStruct;//初始化定時器時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//初始化定時器TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = arr;TIM_TimeBaseInitStruct.TIM_Prescaler = psc;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//使能更新中斷TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//中斷初始化NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_InitStruct);//使能定時器TIM_Cmd(TIM3, ENABLE);}//中斷處理函數 void TIM3_IRQHandler(void) {if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET){LED2 = !LED2;}//清除中斷標志位TIM_ClearITPendingBit(TIM3, TIM_IT_Update); }main.c
#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "beep.h" #include "key.h" #include "exti.h" #include "iwdg.h" #include "wwdg.h" #include "timer.h"int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);delay_init(168);LED_Init();KEY_Init();LED1 = 0;LED2 = 0;//定時器初始化TIM3_Int_Init(5000 - 1, 8400 - 1);while(1){LED1 = !LED1;delay_ms(300);} }結果驗證
DS1 不停閃爍(每 600ms 閃爍一次),而 DS0 也是不停的閃爍,但是閃爍時間較 DS0 慢(1s 一次)
06. 附錄
6.1 【STM32】STM32系列教程匯總
網址:【STM32】STM32系列教程匯總
07. 聲明
該教程參考了正點原子的《STM32 F4 開發指南》
總結
以上是生活随笔為你收集整理的【STM32】定时器程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【STM32】定时器相关函数和类型
- 下一篇: 【STM32】PWM程序