在數字電路中時鐘是整個電路的心臟,電路的的一舉一動都是根據時鐘節拍下進行的,隨著信息量逐漸提高,對硬件信息處理能力提出了更大的需求,時鐘作為數字硬件的關鍵成員,其性能需要我們關注,尤其在高速電路設計中對模擬轉換芯片對時鐘性能有很高的需求,因此正確選擇時鐘是很關鍵的一步,前提是我們要了解時鐘的關鍵參數咯。在數字電路中最常見的時鐘元件有晶振和鎖相環、時鐘緩沖器等,本節對外部定時器進行重點講解。
SysTick定時器的功能比較單一,主要是供給系統使用的,系統默認設置為1ms觸發一次中斷。而用戶想要使用自己的定時器,STM32提供的用戶定時器不但數量多且功能更加強大。不同型號的STM32提供的定時器數量不同。
STM32F4xx 系列微控制器具有多達14個定時器。其中包括2個基本定時器,10 個通用定時器2個高級定時器。其中最大定時器時鐘可通過 RCC_DCKCFGR 寄存器配置為 84MHz 或者 168MHz。一般是默認配置。
捕獲/比較通道:每一個通道對應著外部一個管腳,接收外部的一些信號或者輸出一些信號。
基本定時器TIM6和TIM7:和SysTick定時器的功能差不多,基板上就是定時計數以及驅動DAC的功能。
通用定時器TIM2、5、3、4、9、10、11、12、13、14:功能比基本定時器的功能多,且包含基本定時器的功能,多出來的功能包括輸入捕獲(通過捕獲通道,一個外接的管腳來測量外部信號的頻率和脈寬等)、輸出比較、PWM輸出(也對應一個專門的通道)、使用外部信號控制定時器和定時器串連的同步電路的應用等一些在特殊場合應用的功能。
高級定時器TIM1和TIM8:包括了通用定時器的所有功能,在通用定時器的基礎上增加了更加特殊更加專業的功能,主要是用于PWM控制一些工業上的電機,還有帶一些死區控制、急剎車等專業功能。
定時器計數模式:
向上計數模式:計數器從0計數到自動加載值(TIMx_ARR,相當于SysTick的重載數值寄存器),然后重新從0開始計數,達到設定的數值時產生一個計數器溢出事件。
向下計數模式:計數器從自動裝入的值(TIMx_ARR)開始向下計數到0,然后從自動裝入的值重新開始,并產生一個計數器向下溢出事件。
中央對齊模式(向上/向下計數):計數器從0開始計數到自動裝入的值-1,產生一個計數器溢出事件,然后向下計數到1并且產生一個計數器溢出事件;然后再從0開始重新計數。該模式簡單說明為先進行向上計數模式,當達到數值寄存器的值時,進行中斷服務,而計數器的值不會恢復為0重新向上計數,而是保持該值轉而采用向下計數模式,減到0時觸發中斷進行中斷服務,再采用向上計數模式,周而復始。
定時器的時鐘:
APB1和APB2總線上分別掛載的外設和定時器的最大時鐘頻率是不同的。
定時器的時基:
時鐘源:定時器時鐘 TIMxCLK,即內部時鐘 CK_INT,經 對應的APB 預分頻器后分頻提供
計數器時鐘:定時器時鐘經過 PSC 預分頻器之后,即 CK_CNT,用來驅動計數器計數,一般情況下該時鐘頻率值就是時鐘源的頻率值,為默認配置
計數器CNT:是一個 16 位/32的計數器
自動重裝載寄存器:這里面裝著計數器能計數的最大數值。當計數到這個值的時候,如果使能了中斷的話,定時器就產生溢出中斷
計時中斷時間:1/(TIMxCLK/(PSC+1)) * (ARR+1) 這里所有的加1是因為從0開始
輸入捕獲與輸出比較:
輸入捕獲:可以用來捕獲外部事件,比如引腳的電平變化(上升沿,下降沿),并記錄下變化的時間,通常可以用來測量外部信號的頻率或者電平持續的時間。
輸出比較:此項功能是用來控制一個輸出波形,當計數器與捕獲/比較寄存器的內容相同時,輸出比較功能做出相應動作,比如電平的翻轉。通常用于生產PWM波形。
STM32定時器定時中斷實驗:利用基本定時器實現定時1秒中斷,并在中斷處理函數中打印輸出字符
使用定時器必須知道定時器時鐘源是多少,本實驗使用基本定時器TIM6,掛載再APB1總線上,因此時鐘源大小為84MHz,設置分頻系數為8400-1,則計數器的時鐘頻率為10KHz,即一個CLK的周期為100us,想要實現1s中斷,則裝載寄存器的大小為1000-1。
第一步先配置時鐘
第二步配置定時器TIM6
第三步配置中斷
值得注意的是,STM32有很多片內外設,而一般情況下每一種片內外設的數量不唯一,因此要有啟動函數來啟動用戶想要的啟動的目標外設。如本節中定時器數量有很多,需要一定的定時器啟動函數區分不同的定時器,然后啟動目標定時器,而系統定時器只有一個,再整個工作過程中一直工作,不需要專門的啟動函數。HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)可以啟動定時器,HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)既可以啟動定時器,又可以使能定時器中斷。
//mian.c
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM6_Init();//定時器初始化,配置參數
MX_USART1_UART_Init();
printf("this is tim6 int testn");
HAL_TIM_Base_Start_IT(&htim6);//啟動定時器并使能中斷
while (1)
{ }
}
在定時器中斷處理函數中有很多不同類型的事件可以觸發定時器中斷,如輸入捕獲,輸出比較,由于向上計數到達指定數值時,計數器會重新更新數值,所以我們選擇數值更新事件。
所以在中斷處理中我們只需重寫回調函數HAL_TIM_PeriodElapsedCallback(htim);即可
//tim.c
//重寫回調函數完成邏輯功能
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim- >Instance == TIM6){ //判斷是不是基本定時器TIM6
printf("tim6 intn");
}
}
高級定時器功能分析
高級定時器和通用定時器在基本定時器的基礎上引入了外部引腳,可以輸入捕獲和輸出比較功能。高級控制定時器比通用定時器增加了可編程死區互補輸出、重復計數器、帶剎車(斷路)功能,這些功能都是針對工業電機控制方面。
功能分析如下:
①時鐘源:對于高級或者通用定時器來說,時鐘源不僅僅只有來自APB總線的內部時鐘,其時鐘源還可以來自外部,通過定時器連接外部的管腳引入進來,一般情況下我們都是使用內部時鐘。
②控制器:包括觸發控制器、從模式控制器以及編碼器接口。觸發控制器用來針對片內外設輸出觸發信號,比如為其它定時器提供時鐘和觸發 DAC/ADC 轉換。編碼器接口專門針對編碼器計數而設計。從模式控制器可以控制計數器復位、啟動、遞增/遞減、計數。
③時基單元:定時計數的核心,預分頻器 PSC:對輸入時鐘進行分頻得到計數器的驅動時鐘CK_CNT,計數器 CNT: 在外部時鐘的驅動下實時的進行計數,自動重載寄存器 ARR:用來存放與計數器,CNT 比較的值,如果兩個值相等就遞減重復計數器。
重復計數器 RCR:高級定時器特有,在定時器發生上溢或下溢事件時遞減重復計數器的值,只有當重復計數器為0 時才會生成更新事件。相當于有了一個緩沖,溢出時不會直接觸發中斷,而是時重復計數器減一,也就是可以延長計數時間,想要延長幾倍,重復計數器里的數值就是幾。
④輸入捕獲:輸入捕獲可以對輸入的信號的上升沿,下降沿或者雙邊沿進行捕獲,常用來測量輸入信號的脈寬和頻率,一個定時器可能有很多通道,每個通道對應一個管腳,但是一個定時器不會擁有超過4個通道。
外部通過管腳將信號輸入后,信號會經過一個輸入濾波器和邊沿檢測器。外部輸入的信號雜亂,使用濾波器進行濾波調整,過濾出用戶想要的頻率的信號;邊沿檢測器用來檢測輸入波形的頻率,以上升沿為例,第一次檢測到上升沿,將計數器的值CNT放入到捕獲寄存器CCR(捕獲寄存器就是用來記錄數值的),捕獲到下一次上升沿后再把計數器的值CNT放入到捕獲寄存器CCR,兩次數值相減就知道中間經歷了多少個上升沿,再根據中間經過的時間就可以算出頻率。
這里的預分頻器的作用是規定采集多少次上升沿才記錄一次。
⑤公共部分:公共部分就是CCR(capture compare),捕獲/比較寄存器,用來記錄特定數值。
⑥輸出比較:輸出一些固定頻率,且電平的寬度可以調節波形信號。輸出比較就是通過定時器的計數比較控制外部引腳對外輸出高低電平,比較輸出有很多種模式,其中PWM模式是輸出比較中使用的最多的模式。
輸出比較的基本原理為:在CCR中記錄一個值,專門用來與ARR(裝載寄存器)中的值進行比較比較的,因此可以這樣設定,當CNT(計數器中的值,不斷變化的)小于CCR中的值時輸出低電平,當CNT的值大于CCR中的值時輸出高電平。不會大于ARR中的值,因為ARR的值是用戶設定的最大值,超過就會溢出觸發中斷,CNT變回0重新計數。因此通過設置CCR中的值就可以調節高/低電平的寬度,這就是所謂的PWM波的原理。
互補輸出和死區控制
高級控制定時器比通用定時器增加了可編程死區互補輸出功能,常應用在工業電機控制方面,下面紅框中的寄存器就是用來實現此功能的。
H橋電機如下圖所示,從上圖中可以看到每個定時器通過DTG寄存器和輸出控制單元連接了CHx和CHxN兩根管腳,正是用來與H橋電機的OCx和OCxN相連
互補輸出:兩根管腳一個輸出高電平,另一個必須為低電平,在H橋電機中,OCx為高電平,OCxN必須為低電平,此時電機逆時針逆時針旋轉,反之電機順時針旋轉。倘若兩根管腳同時為高電平,則會導致電機損毀。如圖,互補輸出在一根管腳變為高電平的瞬間要求另一跟管腳變為低電平,但是這屬于理想狀態,實際上兩根管腳的電平變化一定會有延時,就會出現兩根管腳同時為高電平的情況,于是引入死區控制。
死區控制是當一根管腳由高電平變為低電平時,另一管腳不會立即變為高電平,延時一小段時間后再變為高電平,延時的這一小段時間就稱之為死區,插入死去就避免了電機燒毀的問題。DTG寄存器是配置死區發生器 (Dead-time generator setup),保存的值為死區持續的時間。
STM32定時器輸入捕獲實驗
輸入捕獲可以對輸入的信號的上升沿,下降沿或者雙邊沿進行捕獲,常用來測量輸入信號的脈寬和頻率。加入我們設置捕獲下降沿,可以使能中斷,捕獲到下降沿后產生中斷,在中斷中執行用戶程序。捕獲到下降沿后將計數器的值保存到捕獲寄存器中,當出現下一次下降沿后同樣會觸發中斷,也會把當前計數器的值保存到捕獲寄存器中。通過保存到捕獲寄存器中兩次數值的差值計信號頻率或者電平持續的時間。
如果想要捕獲脈寬,捕獲上升沿后應該立即設置為捕獲下降沿。value2-value1就是高電平持續的時間,也就是脈寬。
實驗:利用定時器2的輸入捕獲功能測量按下KEY6鍵后低電平持續的時間
說明:根據原理圖可得,按鍵KEY6的管腳為PA0,正常情況下管腳電平為高電平,按下后管腳電平為低電平。所以應當先設置捕獲下降沿,當捕獲到下降沿后立即設置未捕獲上升沿。兩簇計數器的差值即可得低電平持續的時間,但這知識理想狀態下,實際的操作過程中人有需要考慮的因素。
如果低電平的持續時間很長,那么計數器不可能無限增長,在計數時會產生N次溢出。所以有如下計算方法,當第一次捕獲到下降沿的時候,在捕獲中斷中我們將計數器的值清零并設置下一次捕獲為上升沿,這樣,低電平持續的時間就為T=N*ARR+CCRx2。在第二次捕獲到上升沿時,用戶可在上升沿捕獲中斷中統計時間,設置其他參數等。
步驟:
1.配置時鐘RCC。
2.選擇管腳PA0,配置為TIM2的通道1。
3.配置TIM2硬件。
4.TIM2協議參數配置。
5.中斷配置。
//mian.c
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();//初始化TIM2,配置寄存器參數
MX_USART1_UART_Init();
printf("this is tim2 cap testn");
HAL_TIM_Base_Start_IT(&htim2);//開啟定時器2,使能更新溢出中斷
HAL_TIM_IC_Start_IT (&htim2, TIM_CHANNEL_1);
//開啟定時器2輸入捕獲功能,使能捕獲中斷,使用通道1
while (1)
{}
}
//stm32f4xxxit.c
void TIM2_IRQHandler(void){ //中斷函數入口
HAL_TIM_IRQHandler(&htim2);
}
展開函數HAL_TIM_IRQHandler();可得如下
重寫回調函數
//tim.c
uint8_t fall_flag = 0; //下降沿捕獲標志位
uint32_t cap_value = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim- >Instance == TIM2) {
if(fall_flag) {
cap_value += 1000000;//每次溢出給cap_value增加重裝載寄存器中的值
printf("update int n");
}
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if(htim- >Instance == TIM2) {
if(!fall_flag){//當前捕獲到的是下降沿
printf("捕獲到的是下降沿n");
HAL_Delay(20); //延時20ms消抖
if( HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET) {
fall_flag = 1;
__HAL_TIM_DISABLE(htim);//關閉定時器
__HAL_TIM_SET_COUNTER(htim,0);//設置計數器的值為0
TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);//清除原來的設置
//設置為上升沿捕獲
TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
__HAL_TIM_ENABLE(htim); //使能開啟定時器
}
}else{
printf("捕獲到的是上升n");
fall_flag = 0; //當前捕獲的是上升沿,本次捕獲結束
//最終的時間=溢出的時間+當前計數器的值+延時時間
cap_value = cap_value + HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1) + 20000 ;
printf("低電平持續的時間=%d秒:%d毫秒:%d微秒n",
cap_value/1000000,cap_value%1000000/1000,cap_value%1000);
cap_value = 0; __HAL_TIM_DISABLE(htim);//關閉定時器
TIM_RESET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1);//清除原來的設置
//設置為下降沿捕獲
TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
__HAL_TIM_ENABLE(htim); //打開定時器
HAL_Delay(20);
}
}
}
關鍵功能函數說明:
STM32定時器輸入捕之PWM呼吸燈實驗
PWM(Pulse Width Modulation):脈沖寬度調制.
占空比:就是輸出的PWM中,高電平保持的時間與該PWM的時鐘周期的時間之比 .
輸出一個波形,該波形的脈寬和頻率均可調節,把這種波形叫做PWM波。通過調節脈寬可以控制電機的速度,燈的亮滅,舵機的角度等多種應用,整個波形的平均電壓取決于占空比,占空比越大,平均電壓越高,則電機越快。
PWM應用:它是利用微處理器的數字輸出來對模擬電路進行控制的一種非常有效的技術,廣泛應用于測量,通信,功率控制與變換等許多領域。脈沖寬度調制(PWM)是一種對模擬信號電平進行數字編碼的方法。通過高分辨率計數器的使用,方波的占空比被調制用來對一個具體模擬信號的電平進行編碼。常見應用有:電機控制,DAC輸出等。
輸出比較的基本原理為:在CCR中記錄一個值(一定比ARR中的值小),專門用來與ARR(裝載寄存器)中的值進行比較比較的,因此可以這樣設定,當CNT(計數器中的值,不斷變化的)小于CCR中的值時輸出低電平,當CNT的值大于CCR中的值時輸出高電平。不會大于ARR中的值,因為ARR的值是用戶設定的最大值,超過就會溢出觸發中斷,CNT變回0重新計數。因此通過設置CCR中值的大小就可以調節高/低電平的寬度,這就是所謂的PWM波的原理。
PWM輸出模式:
PWM輸出極性:1.高電平有效 2.低電平有效
輸出高電平和輸出低電平都叫做通道有效,至于是哪一種,需要用戶自己去配置他的輸出極性。例如配置PWM輸出極性為低電平有效,且計數器采用PWM1模式下遞增方式,則計數器的值小于CCR時,輸出低電平,計數器的值大于CCR時,輸出高電平。
呼吸燈是由亮逐漸變暗,再由暗逐漸變亮的過程,而不是瞬間亮,瞬間滅。因為電平變化的速度很快,微觀實際上燈就是瞬間亮,瞬間滅,但是人眼無法分辨。宏觀上就是通過平均電壓來表現,在單位時間內通過配置多個有規律變化的占空比的大小就可以實現呼吸燈。
由上述LED燈的電器原理圖可知,PF7管腳的低電平持續時間越長,燈越亮,也就是占空比越小,燈越亮。本實驗采用采用PWM1模式下遞增方式低電平有效。
步驟:
1.配置時鐘RCC.
2.選擇管腳PF7,配置為TIM11的通道1。
3.配置TIM11硬件。
4.TIM11協議參數配置。
//mian.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
void SystemClock_Config(void);
//此函數用來調節TIM11比較寄存器的大小
void TIM11_Set_Compare(uint32_t compare) {
TIM11- >CCR1 = compare;
}
int main(void) {
int32_t compare = 0;
uint8_t dir = 0;//計數模式標志位
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM11_Init();
MX_USART1_UART_Init();
printf("this is pwm led testn");
//啟動PWM定時器
HAL_TIM_PWM_Start(&htim11, TIM_CHANNEL_1);
while (1) {
if(!dir){ //向上計數
compare += 10;
if(compare >=1000) {
compare = 1000-1;
dir = 1;
}
}else{ //向下計數
compare -= 10;
if(compare<=0) {
compare = 0;
dir = 0;
}
}
TIM11_Set_Compare(compare);//設置不同CCR值調節呼吸燈亮度
HAL_Delay(20); //沒有延時的話現象看不到,必須有一個電平的持續時間
//這20ms內亮度不變,但是肉眼不可見
//燈緩慢亮緩慢滅
}
}
-
微控制器
+關注
關注
48文章
7570瀏覽量
151623 -
中斷處理
+關注
關注
0文章
94瀏覽量
10987 -
PWM波
+關注
關注
0文章
99瀏覽量
16903 -
定時器中斷
+關注
關注
0文章
49瀏覽量
11232 -
stm32定時器
+關注
關注
0文章
13瀏覽量
2300
發布評論請先 登錄
相關推薦
評論