l 16位的向上、向下、向上/向下(中心對齊)計數模式,支援自動重灌載
l 16位的預分頻器
l 每個定時器都有多個獨立通道,每個通道可用於
* 輸入捕獲
* 輸出比較
* PWM輸出
* 單脈衝模式
l 高階定時器還可以產生互補輸出
l 可以產生中斷/DMA請求:
* 更新事件:計數器向上/向下溢位,計數器初始化(通過軟或者內部/外部觸發)
* 觸發事件:計數器啟動,停止,初始化或者有內部/外部觸發計數
* 輸入捕獲
* 輸出比較
一、定時器之計數模式
(一) 計數模式
向上計數
計數器從0向上計數(遞增)到自動裝載值,然後再次回到0開始計數,併產生一個計數溢位事件
向下計數
計數器從自動裝載值向下計數(遞減)到0,然後再次回到自動裝載值開始計數,併產生一個計數器向下溢位事件
中央對齊模式(向上/向下計數)
計數器從0開始計數到自動裝載值-1,併產生一個計數器溢位事件,然後再向下計數到0+1,併產生一個計數溢位事件,然後再向上計數。
(二)定時器的溢位時間計算
time=(ARR+1)*(PSC+1)/Tclk
ARR為自動裝載值
PSC:預分頻係數
Tclk:定時器的APB時鐘,通常等於系統時鐘
如:
tclk為72M
psc為7199
arr為4999
time=(4999+1)*(7199+1)/72 000 000 = 0.5s = 500ms
(三)CubeMX設定
這裡需要注意的是你所需要使用的定時器是掛載在APB1還是APB2。相應的要調節他們時脈頻率
選擇
選擇內部時鐘
基礎配置,這裡配置的是1秒計數
l Prescaler (PSC- 16 bits value),預分頻器(PSC- 16位值)
l Counter Mode,計數器模式:
up 向上
down 向下
Center Aligned mode 中心對齊模式
l Counter Period (AutoReload Register - 16 bits value),重灌載值
l auto-reload preload,自動重灌載開啟
開啟更新中斷
中斷優先順序數字越低越高
(四)程式設計記錄
中斷開啟
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
溢位事件回撥函式
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ if(htim->Instance == TIM1){ HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);//單獨輸出電平取反 } }
開啟中斷
HAL_TIM_Base_Start_IT(&htim1);
二、 定時器之PWM
PWM即脈衝寬度調製,是一種模擬控制方式,通常用於LED的亮度調節。其實就是快速的高低電平變化讓人感覺不出來。
(一)瞭解一下HZ的概念
1HZ表示1秒變化一個週期
在家用交流點中:
50HZ表示電流每秒鐘來回變化50次,方向改變100次。
50HZ是50個週期,所以有50個正玄波形
這個圖表示的是1HZ變化,1個週期,1個正玄波
50HZ表示每個週期的時間=1S/50=0.02S=20ms
微控制器檢測交流電可以200ms內沒有檢測到高電平,則表示無輸入。
在計算機cpu等使用1khz=1000hz
在電磁波和機械波等,1Khz=1024hz
在PWM中
hz是頻率的單位
1hz 表示PWM的週期是一秒
1Khz表示一秒鐘有一千個週期,也就是週期是1ms
1KKhz、1Mhz表示一秒鐘有100萬個週期,也就是週期是1us
y秒=1/xHZ
1/1000=0.001S=1ms
1/1000000=0.000001S=1us
如果實現週期是100us
100us=0.0001S=1/0.0001= 10,000HZ
(二)PWM配置
ARR為自動裝載值
CCRx 為捕獲比較暫存器值
預分頻係數決定了PWM的時鐘速度
ARR的大小決定了PWM的週期
CRRx決定了輸出有效訊號的時間
有效訊號:
高電平
低電平
PWM模式:
模式1,不管是向上還是向下計數,當計數值小於重灌載值是輸出有效電平。
模式2,不管是向上還是向下計數,當計數值小於重灌載值是輸出無效電平。
PWM週期計算
Fpwm = 100M / ((arr+1)*(psc+1))(單位:Hz)
Fpwm = 100M / (arr+1)/(psc+1)(單位:Hz)
arr 是計數值
psc 是預分頻值
如:
3. 主頻=100M
4. arr=100
5. psc=1000
100,000,000/100/1000=1000Hz
(三) CubeMX設定
設定定時器使用內部時鐘
設定定時器的PWM通道1開啟
STM32F103C8T6對應的PWM通道為PA8
設定基礎引數
Prescaler,分配係數為36
Counter Period,重灌載值為100
所以:
PWM的頻率為:72 000 000/35/100=20 000 HZ(20KHZ),週期為 1/20000= 0.00005秒
PWM脈寬調製的最大值與重灌載值一致,其範圍為[0,100]
通道可以設定的值:
Mode,PWM的模式,可以選擇模式1或模式2
CH Polarity,有效電平,可選高或底
(四)程式設計
初始化
//開啟PWM輸出 HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); //設定預設的佔空比值 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,10);
while迴圈改變值
HAL_Delay(30);//延時30ms //變數修改 if(i<100) i++; else i=0; //設定佔空比值 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,i);
三、 定時器之輸入捕獲
通過檢查定時器通道上的邊沿訊號,在邊沿訊號跳變(上升沿或者下降沿)的時候,將當前定時器的計數值儲存到對應的捕獲/比較暫存器裡面,完成一次捕獲。
通常用於檢測高電平持續時間、低電平持續時間、兩次下降沿的持續時間、兩次上升沿的持續時間
濾波器:
裡可以設定以什麼頻率採集多少次有效電平才說明邊沿觸發成功,如設定的是上升沿觸發,當上升沿發生時,濾波器或以fDTS的頻率採集ICF設定的次數,每次檢測是否是高電平,這樣可以防止誤觸發所帶來的計算干擾。
邊沿檢測器:
設定捕獲的觸發邊沿,可以設定上升沿或下降沿
通道選擇
通過暫存器可以設定其它通道輸入的值到該通道上
如通道1和通道2都可以對映到IC1,但通常是通道1是IC1,通道2是IC2,每個獨立一對一對映,互不干擾。
分頻器:
每2個事件觸發一次捕獲,如上升沿捕獲時,連續獲取到兩個上升沿後才會觸發計數
每4個事件觸發一次捕獲
每8個事件觸發一次捕獲
(一) CubeMX設定
開啟TIM4的通道1作為輸入捕獲通道,對應是PB6引腳
Internal Clock表示內部時鐘
input capture direct mode 表示輸入捕獲
根據硬體連線,這裡設定為上拉
開啟中斷
基礎配置
時鐘:72 000 000 /72 = 1 000 000 HZ= 1MHZ,所以計數一次為1us
最大計數值為65536,約為65ms
prolarity selection 為觸發計數邊沿,下降沿
(二)程式設計
測量低電平的持續時間,先下降沿後上升沿,記錄計數值,最終輸出us單位。
通用函式
//變數儲存 typedef struct { uint8_t flg; //0為未開始,1已經開始,2為結束 uint16_t num;//計數值 uint16_t num_period;//溢位次數 }COUNT_TEMP; COUNT_TEMP count_temp={0}; //捕獲中斷髮送時的回撥函式 void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { //判斷定時器2 if(TIM2 == htim->Instance){ if ( count_temp.flg == 0 ) { // 清零定時器計數 __HAL_TIM_SET_COUNTER(htim,0); //設定上升沿觸發 __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING); count_temp .flg = 1; //設定已經開始 count_temp .num_period = 0; //溢位計數清零 count_temp .num = 0; //計數清零 } else { // 獲取定時器計數值 count_temp .num = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2); //設定下降沿觸發 __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); count_temp .flg = 2; } } } //定時器溢位回撥函式 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(TIM2 == htim->Instance){ //每次溢位時間為65536us if(count_temp.flg==1)//還未成功捕獲 { if(count_temp.num_period==0XFFFF)//電平太長了 { count_temp.flg=2; //標記成功捕獲了一次 count_temp .num=0XFFFF; }else count_temp .num_period ++; } } }
初始化
//開啟定時器溢位中斷 HAL_TIM_Base_Start_IT(&htim2); //開啟輸入捕獲中斷,設定下降沿觸發中斷 __HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING); HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2); //啟動輸入捕獲
while迴圈
//等待測量完畢 if(count_temp.flg == 2 ) { //計數計數值,0xFFFF為最大計數 uint32_t ulTime = (uint32_t)count_temp .num_period * 0xFFFF + count_temp .num; //輸出測量的值 printf ( "低電平時間:%d us\n",ulTime); count_temp .flg = 0; }
原文地址:https://www.cnblogs.com/dongxiaodong/p/14351398.html
找作者:https://space.bilibili.com/162091292