STM32之通用定时器编码器模式
1、編碼器原理
如果兩個信號相位差為90度,則這兩個信號稱為正交。由于兩個信號相差90度,因此可以根據(jù)兩個信號哪個先哪個后來判斷方向、根據(jù)每個信號脈沖數(shù)量的多少及整個編碼輪的周長就可以算出當前行走的距離、如果再加上定時器的話還可以計算出速度。
?
2、為什么要用編碼器
從上圖可以看出,由于TI,T2一前一后有個90度的相位差,所以當出現(xiàn)這個相位差時就表示輪子旋轉了一個角度。但有人會問了:既然都是脈沖,為什么不用普通IO中斷?實際上如果是輪子一直正常旋轉當然沒有問題。仔細觀察上圖,如果出現(xiàn)了毛刺呢?這就是需要我們在軟件中編寫算法進行改正。于是,我們就會想到如果有個硬件能夠處理這種情況那不是挺好嗎?
?
3、stm32編碼器
還是剛才那張圖,但這時候我們看到STM32的硬件編碼器還是很智能的,當T1,T2脈沖是連續(xù)產生的時候計數(shù)器加一或減一一次,而當某個接口產生了毛刺或抖動,則計數(shù)器計數(shù)不變,也就是說該接口能夠容許抖動。在STM32中,編碼器使用的是定時器接口,通過數(shù)據(jù)手冊可知,定時器1,2,3,4,5和8有編碼器的功能,而其他沒有。編碼器輸入信號TI1,TI2經(jīng)過輸入濾波,邊沿檢測產生TI1FP1,TI2FP2接到編碼器模塊,通過配置編碼器的工作模式,即可以對編碼器進行正向/反向計數(shù)。如果用的是定時器3,則對應的引腳是在PC6和PC7上。根據(jù)stmn32手冊上編碼器模式的說明,有6中組合計數(shù)方式,見下表。?
?
由此可知,通過選擇可以確定使用定時器的哪種方式來得到我們所要的結果。STM32編碼器的使用也非常簡單,其基本步驟和開發(fā)STM32其他部件的操作一致,都是打開時鐘,配置接口,配置模式,如果要用中斷則打開中斷。具體可以參考以下代碼(這里使用的是TIM8,引腳采用GPIOC 6和GPIOC7)
正轉向上計數(shù),反轉向下計數(shù),方向在CR1的DIR位里
1.編碼器有個轉速上限,超過這個上限是不能正常工作的,這個是硬件的限制,原則上線數(shù)越多轉速就越低,這點在選型時要注意,編碼器的輸出一般是開漏的,所以單片機的io一定要上拉輸入狀態(tài).?
2.定時器初始化好以后,任何時候CNT寄存器的值就是編碼器的位置信息,正轉他會加反轉他會減這部分是不需要軟件干預的,初始化時給的TIM_Period 值應該是碼盤整圈的刻度值,在減溢出會自動修正為這個數(shù).加超過此數(shù)值就回0.?
3.如果要擴展成多圈計數(shù)需要溢出中斷像樓主說的,程序上圈計數(shù)加減方向位就行了.?
4.每個定時器的輸入腳可以通過軟件設定濾波?
5.應用中如果沒有絕對位置信號或者初始化完成后還沒有收到絕對位置信號前的計數(shù)只能是相對計數(shù).收到絕對位置信號后重新修改一次CNT的值就行了.碼盤一般都有零位置信號,結合到定時器捕獲輸入就行.上電以后要往返運動一下找到這個位置.?
6.即便有濾波計數(shù)值偶爾也會有出錯誤的情況,一圈多計一個或少計一個數(shù)都是很正常的特別是轉速比較高的時候尤其明顯,有個絕對位置信號做修正是很有必要的.絕對位置信號不需要一定在零位置點,收到這個信號就將CNT修正為一個固定的數(shù)值即可.?
7.開啟定時器的輸入中斷可以達到每個步計數(shù)都作處理的效果,但是高速運轉的時候你可能處理不過來.
?
#include "stm32f10x.h"/* RCC時鐘配置 */ void RCC_config() {?ErrorStatus HSEStartUpStatus;/* RCC寄存器設置為默認配置 */RCC_DeInit();/* 打開外部高速時鐘 */RCC_HSEConfig(RCC_HSE_ON);/* 等待外部高速時鐘穩(wěn)定 */HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus == SUCCESS)?{?/* 設置HCLK = SYSCLK */RCC_HCLKConfig(RCC_SYSCLK_Div1);/* 設置PCLK2 = HCLK */RCC_PCLK2Config(RCC_HCLK_Div1);/* 設置PCLK1 = HCLK / 2 */RCC_PCLK1Config(RCC_HCLK_Div2); //?? ??? ?/* 設置FLASH代碼延時 */ //?? ??? ?FLASH_SetLatency(FLASH_Latency_2); //?? ??? ?/* 使能預取址緩存 */ //?? ??? ?FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);/* 設置PLL時鐘源為HSE倍頻9 72MHz */RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);/* 使能PLL */RCC_PLLCmd(ENABLE);/* 等待PLL穩(wěn)定 */while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);/* 設置PLL為系統(tǒng)時鐘源 */RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);/* 等待系統(tǒng)時鐘源切換到PLL */while(RCC_GetSYSCLKSource() != 0x08);} }/* GPIO配置 */ void GPIO_config() {GPIO_InitTypeDef GPIO_InitStructure;/* 使能GPIOA時鐘 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);/* 將GPIOA時鐘設置為默認參數(shù) */GPIO_DeInit(GPIOA);?? ?/* 浮空輸入 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;/* 第3引腳 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;/* 初始化GPIOA */GPIO_Init(GPIOA, &GPIO_InitStructure); }/* 定時器配置 */ void TIMER_config() {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_ICInitTypeDef TIM_ICInitStructure;/* 允許TIM2的時鐘 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/* 將定時器2寄存器設為初始值 */TIM_DeInit(TIM2);/* 填入缺省值 */TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);/* 預分頻值 */TIM_TimeBaseStructure.TIM_Prescaler = 0;/* 自動重載值 */TIM_TimeBaseStructure.TIM_Period = 65536 - 1;/* 時鐘分割 */TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;/* 向上計數(shù) */TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;/* 初始化定時器2 */TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);/* 設置編碼器模式 */TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling ,TIM_ICPolarity_Falling);/* 填入缺省值 */TIM_ICStructInit(&TIM_ICInitStructure);/* 輸入比較濾波器 */TIM_ICInitStructure.TIM_ICFilter = 6;/* 初始化定時器2 */TIM_ICInit(TIM2, &TIM_ICInitStructure);/* 計數(shù)器初始化 */TIM_SetCounter(TIM2, 32768);/* 開啟定時器2 */TIM_Cmd(TIM2, ENABLE); }/* 毫秒延時 */ void delay_ms(uint16_t time) { ? ?uint16_t i = 0;while(time--){i = 12000;while(i--);} }int main() {int16_t speed;/* 時鐘配置 */RCC_config();/* GPIO配置 */GPIO_config();/* 定時器2配置 */TIMER_config();while(1){speed = TIM2->CNT - 32768;TIM_SetCounter(TIM2, 32768);delay_ms(1000);} }?
總結
以上是生活随笔為你收集整理的STM32之通用定时器编码器模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: makefile之自动推倒(2)
- 下一篇: 给你多少钱,你才会愿意为国家生孩子?