文章目錄
一、編碼器原理
二、為什么要用編碼器
三、STM32編碼器配置相關
四、STM32實戰代碼
五、一些注意
參考
一、編碼器原理
如果兩個信號相位差為90度,則這兩個信號稱為正交。由於兩個信號相差90度,因此可以根據兩個信號哪個先哪個后來判斷方向、根據每個信號脈沖數量的多少及整個編碼輪的周長就可以算出當前行走的距離、如果再加上定時器的話還可以計算出速度。
二、為什么要用編碼器
從上圖可以看出,由於TI,T2一前一后有個90度的相位差,所以當出現這個相位差時就表示輪子旋轉了一個角度。但有人會問了:既然都是脈沖,為什么不用普通IO中斷?實際上如果是輪子一直正常旋轉當然沒有問題。仔細觀察上圖,如果出現了毛刺呢?這就是需要我們在軟件中編寫算法進行改正。於是,我們就會想到如果有個硬件能夠處理這種情況那不是挺好嗎?
對應的硬件的編碼器就來了~
我們看到STM32的硬件編碼器還是很智能的,當T1,T2脈沖是連續產生的時候計數器加一或減一一次,而當某個接口產生了毛刺或抖動,則計數器計數不變,也就是說該接口能夠容許抖動。
在STM32中,編碼器使用的是定時器接口,通過數據手冊可知,定時器1,2,3,4,5和8有編碼器的功能,而其他沒有。同時只有CH1和CH2是進行編碼器模式的~
三、STM32編碼器配置相關
編碼器輸入信號TI1,TI2經過輸入濾波,邊沿檢測產生TI1FP1,TI2FP2接到編碼器模塊,通過配置編碼器的工作模式,即可以對編碼器進行正向/反向計數。
比如如果用的是定時器2,則對應的引腳是在PA0和PA1上。
通常為了提高精度我們會選擇在上升沿和下降沿都進行計數!
還有一個非常重要的圖這里也記錄下
其中讓人費解的應該是在第二列的相對信號的電平,這里就來詳細談一下吧。
其實也不難理解哈,我們上面也說了通常為了提高精度會在A、B兩相的上升沿和下降沿都進行計數,那么對應在一個周期就可以計數四次,計數次數的增加也就意味着精度的提高!
編碼器模式下,如果此時處於正轉,那么這四次計數應該都是加的。同理,如果是反轉,那么這四次計數都是減的。那么問題來了,如何判斷正反轉呢?
不就是在相對電平的基礎上嘛!!!
仔細對照圖中,在正轉或者反轉的情況下,A相對B的電平高低以及上表中的計數方向便可了然於心!!!
選擇編碼器接口模式的方法是:如果計數器只在TI2的邊沿計數,則置TIMx_SMCR寄存器中的
SMS=001;如果只在TI1邊沿計數,則置SMS=010;如果計數器同時在TI1和TI2邊沿計數,則
置SMS=011。
通過設置TIMx_CCER寄存器中的CC1P和CC2P位,可以選擇TI1和TI2極性;如果需要,還可以
對輸入濾波器編程。
兩個輸入TI1和TI2被用來作為增量編碼器的接口。假定計數器已經啟動(TIMx_CR1
寄存器中的CEN=’1’),計數器由每次在TI1FP1或TI2FP2上的有效跳變驅動。
配置范例:

CC1S=’01’ (TIMx_CCMR1寄存器, IC1FP1映射到TI1) CC2S=’01’ (TIMx_CCMR2寄存器, IC2FP2映射到TI2) CC1P=’0’ (TIMx_CCER寄存器, IC1FP1不反相, IC1FP1=TI1) CC2P=’0’ (TIMx_CCER寄存器, IC2FP2不反相, IC2FP2=TI2) SMS=’011’ (TIMx_SMCR寄存器,所有的輸入均在上升沿和下降沿有效). CEN=’1’ (TIMx_CR1寄存器,計數器使能)
四、STM32實戰代碼
————————————————

1 /*TIM2初始化為編碼器接口*/ 2 void Encoder_Init_TIM2(void) 3 { 4 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 5 TIM_ICInitTypeDef TIM_ICInitStructure; 6 GPIO_InitTypeDef GPIO_InitStructure; 7 8 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定時器4的時鍾 9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口時鍾 10 11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //端口配置 12 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入 13 GPIO_Init(GPIOA, &GPIO_InitStructure); //根據設定參數初始化GPIOA 14 15 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 16 TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 預分頻器 17 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //設定計數器自動重裝值 18 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//選擇時鍾分頻:不分頻 19 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上計數 20 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 21 TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用編碼器模式3 22 TIM_ICStructInit(&TIM_ICInitStructure); 23 TIM_ICInitStructure.TIM_ICFilter = 10; 24 TIM_ICInit(TIM2, &TIM_ICInitStructure); 25 TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新標志位 26 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); 27 //Reset counter 28 TIM_SetCounter(TIM2,0); 29 TIM_Cmd(TIM2, ENABLE); 30 } 31 32 /*TIM4初始化為編碼器接口*/ 33 void Encoder_Init_TIM4(void) 34 { 35 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 36 TIM_ICInitTypeDef TIM_ICInitStructure; 37 GPIO_InitTypeDef GPIO_InitStructure; 38 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定時器4的時鍾 39 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口時鍾 40 41 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置 42 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入 43 GPIO_Init(GPIOB, &GPIO_InitStructure); //根據設定參數初始化GPIOB 44 45 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 46 TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 預分頻器 47 TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //設定計數器自動重裝值 48 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//選擇時鍾分頻:不分頻 49 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;////TIM向上計數 50 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); 51 TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用編碼器模式3 52 TIM_ICStructInit(&TIM_ICInitStructure); 53 TIM_ICInitStructure.TIM_ICFilter = 10; 54 TIM_ICInit(TIM4, &TIM_ICInitStructure); 55 TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新標志位 56 TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); 57 //Reset counter 58 TIM_SetCounter(TIM4,0); 59 TIM_Cmd(TIM4, ENABLE); 60 } 61 62 /*單位時間編碼器計數 輸入定時器 輸出速度值*/ 63 int Read_Encoder(u8 TIMX) 64 { 65 int Encoder_TIM; 66 switch(TIMX) 67 { 68 case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break; 69 case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break; 70 case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break; 71 default: Encoder_TIM=0; 72 } 73 return Encoder_TIM; 74 } 75 76 void TIM4_IRQHandler(void) 77 { 78 if(TIM4->SR&0X0001)//溢出中斷 79 { 80 } 81 TIM4->SR&=~(1<<0);//清除中斷標志位 82 } 83 84 void TIM2_IRQHandler(void) 85 { 86 if(TIM2->SR&0X0001)//溢出中斷 87 { 88 } 89 TIM2->SR&=~(1<<0);//清除中斷標志位 90 }