頻率測量
頻率測量有兩種方法
- 測頻法:在閘門時間T內,對上升沿或下降沿計次,得到N,則評率fx=N/T
- 測周法:兩個上升沿內,以標準頻率fc計次得到N,則頻率fx= fc/N
- 中界頻率:測頻法和測周法誤差相等的點fm=√(fc/T),fx大于fm選用測頻法更準確。
定時器輸入捕獲測頻原理
在說原理前需要先講一下定時器的主從模式
主模式則是設置定時器輸出時上升沿/下降沿觸發自動執行的操作
從模式則是設置定時器輸入時上升沿/下降沿觸發自動執行的操作
下面我們用到的從模式是復位模式,進入中斷定時器的計數器會自動復位清零
這是定時器運行框圖,輸入捕獲只有看紅色框出來的部分就可以了。可能有點抽象,接下來我來翻譯一下。
首先是第一框中的TI1代表的是定時器x的通道1GPIO引腳輸入的波頻,TI2、3、4同理
然后看到是第二個框中第一條通道的TI1FP1和TI1FP2,分別代表的是,TI1這個波頻輸入哪一個通道處理,TI1FP1則使用定時器通道1的資源對TI1這個波頻進行捕獲上升沿/下降沿,TI1FP2則使用的是定時器通道2的資源,TI2FP1則代表TI2這個波頻使用定時器通道1的資源。
然后就到了處理波頻的步驟了,在我們第一個上升沿到來時,定時器的CNT寄存器開始計時,然后下一個上升沿到來,CNT里的值傳入CCR輸入/比較寄存器,接下來從模式將CNT寄存器自動清零。我們將CCR里的值取出就可以知道一個周期計時值,通過該值大小知道該波頻的頻率高低。
整個流程如下圖
定時器輸入捕獲測量占空比(PWMI模式)
上文提到,定時器通道1的引腳輸入的波頻可以分為TI1FP1和TI2FP2到兩個通道的計時器處理,那么我們將一段波頻分別給兩個定時器通道處理,一個捕獲上升沿,一個捕獲下降沿,在第二次捕獲上升沿的中斷進入時,用捕獲上升沿的CCR1獲取的值減去捕獲下降沿的CCR2的值就可以得到高電平的時間,計算即可得到占空比。
如下圖所示
具體步驟:
第一次捕獲到上升沿:CNT開始計時
第一次捕獲到下降沿:CCR2獲取CNT的值,得到高電平時間
第二次捕獲到上升沿:CCR1獲取CNT的值,進入從模式清除CNT的值,得到周期
那么就可以計算出占空比了。
定時器編碼器模式
stm32的定時器擁有編碼器模式,使我們可以使用編碼器,計算電機轉速
AB相編碼器
這種編碼器可以理解為編碼器會輸出兩個相差90°相位差的波頻,而通過A相在前還是B相在前,判斷電機正轉反轉。
該模式的操作原理比較簡單
兩波頻進入編碼器接口后,判斷相位差是哪個在前,如果為A相在前就將計數器加1,負責計數器減1。
使用定時器編碼模式的軟件代碼
#include "stm32f10x.h"
#include "hal_TIM.h"/****************************************************************************
*@*名稱 : hal_TIM_Encoder_Config
*@*功能 : 初始化定時器2的編碼器模式
*@*形參 : 無
*@*返回值 : 無
****************************************************************************/
static void hal_TIM_Encoder_Config(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIMx, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入GPIO_InitStructure.GPIO_Pin = TIM_ENCODER_A_PIN | TIM_ENCODER_B_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻因子TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1; //ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1; //PSC 預分頻器 //使用系統時鐘作為定時器的編碼器模式的時鐘,實現 1 至 65536 分頻TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIMx, &TIM_TimeBaseInitStructure);TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICStructInit(&TIM_ICInitStructure); //因為結構體沒有定義完整,但擔心有不知名錯誤,先初始化結構體TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICFilter = 0xF; //濾波次數7次TIM_ICInit(TIMx, &TIM_ICInitStructure);TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;TIM_ICInitStructure.TIM_ICFilter = 0xF;TIM_ICInit(TIMx, &TIM_ICInitStructure);TIM_EncoderInterfaceConfig(TIMx, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);TIM_Cmd(TIMx, ENABLE);
}/****************************************************************************
*@*名稱 : hal_TIM_Encoder_Init
*@*功能 : 初始化定時器2的編碼器模式
*@*形參 : 無
*@*返回值 : 無
****************************************************************************/
void hal_TIM_Encoder_Init(void)
{hal_TIM_Encoder_Config();
}/****************************************************************************
*@*名稱 : hal_TIM_Encoder_Get
*@*功能 : 獲取定時器編碼器模式計數的CNT(TIM_EncoderMode_TI12通道12都計數,一個周期記4次)
*@*形參 : 無
*@*返回值 : CNT計數值
****************************************************************************/
int16_t hal_TIM_Encoder_Get(void)
{int16_t Temp;Temp = TIM_GetCounter(TIMx);return Temp;
}