上一個博文介紹了編碼器實現測試,這也是編碼器最普遍的應用,我們需要操作的東西並不多,通常來說記錄脈衝數。
STM32操作增量式編碼器(一)----使用外部中斷實現測速
1.增量式編碼器實現定位思路
對於增量式編碼器如何進行定位,我也是一直存在疑惑,並不是說整體定位算法難,這僅僅需要利用一個變量去記錄當前脈衝數即可,正轉遞增,反轉遞減。但是真實情況真的如此簡單嗎?
首先我們需要明確兩個存在的問題:
1.如何去確定正反轉
2.如何準確確定正反轉
可能你覺得這是同一個問題,但是真的如此嗎?
對於第一個問題,1.如何去確定正反轉,我們先來看看編碼器正反轉輸出波形圖。
圖1-1 增量式編碼器輸出波形(對於Z相波形,屬於零點信號,我們暫時不用理會)
從上述波形,我們可以根據AB相波形的相位差就可以判斷出編碼器正反轉方向,軟件實現大概思路就是通過定時器捕獲或者外部中斷的方式就可實現,這一點實現並不難。
對於第二個問題,2.如何準確確定正反轉,首先看看編碼器換向的輸出波信圖。
圖2-2 增量式編碼器換向輸出波形圖
這裏就會遇到理論與現實中間隔着東西,噪聲,現實!=理論,這是現實最迷人的地方。
言歸正傳,從波形圖可以看到,編碼器換向過程,輸出波形就會出現抖動,它是未知的,抖動都可以認爲是未知的,這個抖動正是編碼器定位的遇到的最大問題,減少噪聲的影響,我們應該想到各式各樣的濾波算法(博主小白,只能用各式各樣去修飾濾波算法了),這個濾波算法的性能將決定定位的精度,這確實也是一個深入研究的點。
2.使用STM32接口輕鬆實現編碼器定位
爲什麼說STM32作爲一個32位的MCU在如今的微處理器如此耀眼,當然是有原因的,STM32提供了在嵌入式領域的常用接口而且十分好用。博文使用STM32F4的編碼器接口實現編碼器定位。
2.1編碼器接口概述
無厘頭帖數據手冊,像極了高中時寫作文的----魯迅曾今說過。。。。。
STM32F4的編碼器接口介紹在STM32Fxx中文參考手冊,英語水平較高的小夥伴也可以看英文手冊。
我們通過下面的波信圖分析或許更加直觀一點:
圖2-1 編碼器接口模式下的計數器工作實例
怎麼一回事呢,圖中的TI1、TI2就是定時器的輸入通道,例如TIM3的 CH1 -->GPIOA6、CH2 -->GPIOA7,接的就是編碼器輸出信號的AB相,從圖中可以看到在這個官方例程配置下,計數器在TI1、TI2的上升沿下降沿都計數,相當於編碼器走一步,計數器計數 * 4,最值得關注的不是這一段,是正向轉動和反向轉動以及抖動階段,我們可以知道,編碼器接口計數自動幫我們區分正反轉,更重要的是,它幫我們處理抖動狀態,wow,感動,所以說STM32好用,好用到我們只需要讀CNT就可以實現定位了,僅僅需要按部就班的配置就完事。除了這個我們還發現STM32提供一個轉向的標誌位,不需要我們通過CNT遞增遞減去判斷。
這個標誌位是TIMx_CR1寄存器,有具體應用場合的小夥伴可以瞭解。
2.2 編碼器接口配置
這個配置是對於寄存器配置而言的,對於操作庫函數而言,這些配置幾乎就是非常直觀了,按部就班配置即可。
我會在代碼下載中放兩種代碼,分別是F1和F4的,區別就是F1操作寄存器配置,F4操作庫函數配置。(以下是F4配置代碼)
//author:ora
//email:[email protected]
#include "ROTARYENCODER.h"
#include "usart.h"
#include "lcd.h"
#define ENCODER_TIM_PERIOD (u16)(65000)
#define COUNTER_RESET (u16)30000
void rotaryEncoder_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//開啓時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//PA6、PA7輸入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//啓動GPIO複用
GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM3);
/* Timer configuration in Encoder mode */
// TIM3->PSC = 0x0;//預分頻器
// TIM3->ARR = ENCODER_TIM_PERIOD-1;//設定計數器自動重裝值
// TIM3->CR1 &=~(3<<8);// 選擇時鐘分頻:不分頻
// TIM3->CR1 &=~(3<<5);// 選擇計數模式:邊沿對齊模式
//配置定時器
TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//配置編碼器模式
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge, TIM_ICPolarity_BothEdge);
//設置輸入捕獲濾波器
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(TIM3, &TIM_ICInitStructure);
//設置初始值、使能計時器
TIM3->CNT = COUNTER_RESET;
TIM3->CR1 |= 0x01; //CEN=1,使能定時器
}
3.無厘頭代碼下載
https://github.com/oraSC/STM32-course/tree/master/%E7%BC%96%E7%A0%81%E5%99%A8