前言:
本系列教程將外設原理,HAL庫與STM32CubeMX結合在一起講解,使您可以更快速的學會各個模塊的使用
所用工具:
1、芯片: STM32F407ZET6/STM32F103ZET6
2、STM32CubeMx軟件
3、IDE: MDK-Keil軟件
4、STM32F1xx/STM32F4xxHAL庫
5
知識概括:
通過本篇博客您將學到:
SMT32定時器輸入捕獲
測量PWM頻率和占空比
輸入捕獲
輸入捕獲概念
輸入捕獲模式可以用來測量脈沖寬度或者測量頻率。STM32的定時器,除了TIM6、TIM7,其他的定時器都有輸入捕獲的功能。
具體請參看《【STM32】HAL庫 STM32CubeMX教程六----定時器中斷》
輸入捕獲的工作原理
①先設置輸入捕獲為上升沿檢測,
②記錄發生上升沿時TIMx_CNT(計數器)的值
③配置捕獲信號為下降沿捕獲,當下降沿到來的時候發生捕獲
④記錄此時的TIMx_CN(計數器)T的值
⑤前后兩次TIMx_CNT(計數器)的值之差就是高電平的脈寬。同時根據TIM的計數頻率,我們就能知道高電平脈寬的准確時間。
簡單說:
當你設置的捕獲開始的時候,cpu會將計數寄存器的值復制到捕獲比較寄存器中並開始計數,當再次捕捉到電平變化時,這是計數寄存器中的值減去剛才復制的值就是這段電平的持續時間,你可以設置上升沿捕獲、下降沿捕獲、或者上升沿下降沿都捕獲,
輸入捕獲的工作流程(對應CubeMx的四個選項)
設置輸入捕獲濾波器
STM32在很多功能中都提供了濾波器,濾波器的功能簡單來說就是多次檢測視為一次有效,達到濾波效果,
數字濾波器由一個事件計數器組成,假設我們是檢測高電平,濾波N次,那么記錄到N個事件后計數器會產生一個輸出的跳變。也就是說連續N次采樣檢測,如果都是高電平,則說明這是一個有效的電平信號,這樣便可以過濾掉那些因為某些而干擾產生的一些信號
輸入捕獲濾波器IC1F[3:0],這個用於設置采樣頻率和數字濾波器長度。其中:fCK_INT是定時器的輸入頻率,fDTS是根據TIMx_CR1的CKD[1:0]的設置來確定的。
設置輸入捕獲極性
設置具體為那種捕獲事件
可以設置上升沿捕獲、下降沿捕獲、或者上升沿下降沿都捕獲
設置輸入捕獲映射關系
STM32為了更好的優化使用,TIMx_CH1通道1捕捉到的信號可以傳輸到IC1,TIMx_CH1捕捉到的信號也可以連接到IC2,TIMx_CH2捕捉到的信號也可以連接到IC2,也可以連接到IC2
設置輸入捕獲分頻器
設置每N個事件觸發一次捕獲,可以設置為1/2/4/8次檢測到電平變化才觸發捕獲
溢出時間計算:
t1時刻檢測到高電平,發生中斷,在中斷里將計數值置0,開始記溢出次數N,
其中每計數0xFFFF次溢出一次,直到t2時刻跳變回低電平,
獲取最后一次溢出時到t2時刻的計數值TIM5CH1_CAPTURE_VAL
則 高電平時間 = 溢出次數*65535+TIM5CH1_CAPTURE_VAL us ;根據定時器初始化時的頻率即可計算出溢出總次數所占用的時間,即為高電平時間。
如果計數器值為 32 bit 那么最大為0xFFFFFFFF
高電平時間:
輸入捕獲的工作框圖
工程創建
設置RCC
設置高速外部時鍾HSE 選擇外部時鍾源
2設置時鍾
我的是 外部晶振為8MHz
- 1選擇外部時鍾HSE 8MHz
- 2PLL鎖相環倍頻72倍
- 3系統時鍾來源選擇為PLL
- 4設置APB1分頻器為 /2
- 5 這時候定時器的時鍾頻率為72Mhz
32的時鍾樹框圖 如果不懂的話請看《【STM32】系統時鍾RCC詳解(超詳細,超全面)》
3定時器配置
這里我們選擇TIM5的通道1
- 預分頻系數為71 計數時鍾頻率就是 72MHz/(71+1) = 1MHz 此時1us計數一次
- 自動加載值設置為32bit最大值 0xFFFFFFFF
- 上升沿捕獲
- 不分頻
- 濾波值為8
同時在NVIC一欄使能TIM5的中斷
對應引腳設置下拉電阻,保證沒有信號輸入的時候電平穩定
4項目文件設置
- 1 設置項目名稱
- 2 設置存儲路徑
- 3 選擇所用IDE
5創建工程文件
然后點擊GENERATE CODE 創建工程
配置下載工具
新建的工程所有配置都是默認的 我們需要自行選擇下載模式,勾選上下載后復位運行
例程實現:
定義變量:
-
/* USER CODE BEGIN 0 */
-
uint32_t capture_Buf[3] = {0}; //存放計數值
-
uint8_t capture_Cnt = 0; //狀態標志位
-
uint32_t high_time; //高電平時間
-
/* USER CODE END 0 */
在 while(1)中的用戶代碼區 3,寫入TIM2 CH1通道的輸入捕獲控制和數據處理
-
while (1)
-
{
-
/* USER CODE END WHILE */
-
-
/* USER CODE BEGIN 3 */
-
switch (capture_Cnt){
-
case 0:
-
capture_Cnt++;
-
__HAL_TIM_SET_CAPTUREPOLARITY(&htim5, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
-
HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1); //啟動輸入捕獲 或者: __HAL_TIM_ENABLE(&htim5);
-
break;
-
case 3:
-
high_time = capture_Buf[ 1]- capture_Buf[0]; //高電平時間
-
HAL_UART_Transmit(&huart1, ( uint8_t *)high_time, 1, 0xffff); //發送高電平時間
-
-
-
HAL_Delay( 1000); //延時1S
-
capture_Cnt = 0; //清空標志位
-
break;
-
-
}
-
}
-
/* USER CODE END 3 */
在main函數下方添加中斷回調函數:
-
/* USER CODE BEGIN 4 */
-
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
-
{
-
-
if(TIM5 == htim->Instance)
-
{
-
switch(capture_Cnt){
-
case 1:
-
capture_Buf[ 0] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//獲取當前的捕獲值.
-
__HAL_TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //設置為下降沿捕獲
-
capture_Cnt++;
-
break;
-
case 2:
-
capture_Buf[ 1] = HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);//獲取當前的捕獲值.
-
HAL_TIM_IC_Stop_IT(&htim5,TIM_CHANNEL_1); //停止捕獲 或者: __HAL_TIM_DISABLE(&htim5);
-
capture_Cnt++;
-
}
-
-
}
-
-
}
-
/* USER CODE END 4 */
具體流程:
1.設置TIM5 CH1為輸入捕獲功能;
2.設置上升沿捕獲;
3.使能TIM2 CH1捕獲功能;
4.捕獲到上升沿后,定時器當前計數值存入capture_buf[0],改為捕獲下降沿;
5.捕獲到下降沿后,定時器當前計數值存入存入capture_buf[1],關閉TIM2 CH1捕獲功能; capture_Cnt=3;
6. 高電平時間: capture_buf[1] - capture_buf[0] 發送到上位機 重新啟動輸入捕獲
__HAL_TIM_SET_COUNTER(&TIM5_Handler,0); //設置計數寄存器的值變為0
HAL_TIM_PWM_Start() 函數用於使能定時器某一通道的PWM輸出。
HAL_TIM_IC_Start_IT() 函數用於使能定時器某一通道的輸入捕獲功能,並使能相應的中斷
HAL_TIM_IC_Stop_IT() 函數和開啟功能相反,是關閉定時器某一通道的輸入捕獲功能和相應中斷
__HAL_TIM_SET_CAPTUREPOLARITY不是函數,而是底層操作的一個宏定義
在stm32f4xx_hal_tim.h文件中可以找到。其作用是修改定時器某一通道的輸入捕獲極性
其中有兩個函數,第一個為清除清除原來的捕獲極性,第二個為設置通道捕捉極性
等價於:
-
TIM_RESET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1); //一定要先清除原來的捕獲極性!!
-
TIM_SET_CAPTUREPOLARITY(&TIM5_Handler,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING); //定時器5通道1設置為下降沿捕獲(重設捕獲極性)
在修改定時器某一通道的輸入捕獲極性時,一定要先清除該通道之前捕獲極性
__HAL_TIM_GET_COMPARE也是一個宏定義。
在stm32f4xx_hal_tim.h文件中可以找到。其作用是獲取定時器某一通道的捕獲/比較寄存器值
等價於 : HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
兩者都是直接讀取對應CCRx寄存器的值