1?編碼器接口簡介
Encoder Interface 編碼器接口
編碼器接口可接收增量(正交)編碼器的信號,根據編碼器旋轉產生的正交信號脈沖,自動控制CNT自增或自減,從而指示編碼器的位置、旋轉方向和旋轉速度
接收正交信號,自動執行CNT自增或者自減,編碼器接口相當于帶有方向控制的外部時鐘,同時控制著CNT的計數時鐘和計數方向。每隔一段時間去取一次CNT的值,再把CNT清零,每次取出來的值就表示編碼器的速度。(測頻法)
每個高級定時器和通用定時器都擁有1個編碼器接口
兩個輸入引腳借用了輸入捕獲的通道1和通道2(CH1和CH2)
1.1?正交編碼器
正交編碼器一般可以測量位置或者帶有方向的速度值
旋轉編碼器:用來測量位置、速度或旋轉方向的裝置,當其旋轉軸旋轉時,其輸出端可以輸出與旋轉速度和方向對應的方波信號,讀取方波信號的頻率和相位信息即可得知旋轉軸的速度和方向
類型:機械觸點式/霍爾傳感器式/光柵式
?
方波頻率代表速度。正轉時A相提前B相90°;反轉時A相滯后B相90°
首先把A\相和B相的所有邊沿作為計數器的計數時鐘,出現邊沿信號時就計數器自增或者自減;計數的方向由另一相的狀態來確定。當出現某個邊沿時,判斷另一相高低電平,如果另一相的狀態出現在上面這個表中,那就是正轉,計數自增;否則就是反轉,計數自減。這樣就可以實現編碼器接口的功能了。
編碼器接口有兩個輸入端,分別接到編碼器的A相和B相,所以編碼器的輸入引腳就是定時器的CH1和CH2引腳。編碼器的輸出部分相當于從模式的控制器了,控制CNT的計數時鐘和計數方向。計數器的自增和自減受編碼器控制。
1.2?編碼器接口基本結構
很清晰
1.3?工作模式
這里TI1FP1和TI2FP2接的就是AB相。計數和前面一樣。
正轉向上計數,反轉向下計數。
1.4?實例圖
均不反向,使用TI1和TI2都計數
很清晰。
TI1反向,TI2不反向。極性的變化對計數的影響。
這里的極性選擇就是高低電平的極性選擇了。如果選擇上升沿的參數,就是信號直通過來,高低電平極性不反轉;如果選擇下降沿的參數,就是信號通過非門,高低電平反轉。
很清晰。
手冊
2? 編碼器接口測速
2.1?接線圖
引腳定義
計劃用TIM3的通道1和通道2
2.2?模塊封裝
按這個配置
庫函數
// 定時器編碼器接口配置
void TIM_EncoderInterfaceConfig(TIM_TypeDef* TIMx, uint16_t TIM_EncoderMode,uint16_t TIM_IC1Polarity, uint16_t TIM_IC2Polarity);
版本一:Encoder.c
#include "stm32f10x.h" // Device header// 編碼器接口初始化函數
void EnCoder_Init(void)
{// 1開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 2配置GPIOGPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入模式GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);// 3配置時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1; // PSC預分頻器的值,不分頻TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1; // ARR自動重裝器的值 TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上計數,沒有用TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 不分頻TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 重復計數器的值TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);// 4配置輸入捕獲單元(只有極性和濾波器兩個參數有用)TIM_ICInitTypeDef TIM_ICInitStruct;TIM_ICStructInit(&TIM_ICInitStruct); // 結構體初始化TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; // 通道1TIM_ICInitStruct.TIM_ICFilter = 0xF; // 濾波器
// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 和后面重復
// TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 無作用
// TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 無作用TIM_ICInit(TIM3, &TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;TIM_ICInitStruct.TIM_ICFilter = 0xF;// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 和后面重復TIM_ICInit(TIM3, &TIM_ICInitStruct);// 5配置編碼器接口模式// TIM_ICPolarity_Rising這個通道不反向,TIM_ICPolarity_Falling這個通道反向// 后兩個參數相反就是方向相反TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);// 6啟動定時器TIM_Cmd(TIM3, ENABLE);
}// 獲取CNT的值
int16_t Encoder_Get(void)
{return TIM_GetCounter(TIM3);
}
版本二:Encoder.c
#include "stm32f10x.h" // Device header// 編碼器接口初始化函數
void EnCoder_Init(void)
{// 1開啟時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 2配置GPIOGPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉輸入模式GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);// 3配置時基單元TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_Prescaler = 1 - 1; // PSC預分頻器的值,不分頻TIM_TimeBaseInitStruct.TIM_Period = 65536 - 1; // ARR自動重裝器的值 TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上計數,沒有用TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 不分頻TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; // 重復計數器的值TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);// 4配置輸入捕獲單元(只有極性和濾波器兩個參數有用)TIM_ICInitTypeDef TIM_ICInitStruct;TIM_ICStructInit(&TIM_ICInitStruct); // 結構體初始化TIM_ICInitStruct.TIM_Channel = TIM_Channel_1; // 通道1TIM_ICInitStruct.TIM_ICFilter = 0xF; // 濾波器
// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 和后面重復
// TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 無作用
// TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 無作用TIM_ICInit(TIM3, &TIM_ICInitStruct);TIM_ICInitStruct.TIM_Channel = TIM_Channel_2;TIM_ICInitStruct.TIM_ICFilter = 0xF;// TIM_ICInitStruct.TIM_ICPolarity = TIM_ICPolarity_Rising; // 和后面重復TIM_ICInit(TIM3, &TIM_ICInitStruct);// 5配置編碼器接口模式// TIM_ICPolarity_Rising這個通道不反向,TIM_ICPolarity_Falling這個通道反向// 后兩個參數相反就是方向相反TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);// 6啟動定時器TIM_Cmd(TIM3, ENABLE);
}// 獲取CNT的值
int16_t Encoder_Get(void)
{
// return TIM_GetCounter(TIM3);// 讀取cnt,把cnt清零的邏輯int16_t temp = TIM_GetCounter(TIM3);TIM_SetCounter(TIM3, 0);return temp;
}
2.3?主函數
版本一:主函數
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "EnCoder.h"int main()
{OLED_Init(); // 初始化OLEDEnCoder_Init();
// Timer_Init(); // 初始化定時器OLED_ShowString(1, 1, "CNT:"); // 顯示字符串while (1){OLED_ShowNum(1, 5, Encoder_Get(), 5); // 顯示CNT計數器}
}
版本二:主函數
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "EnCoder.h"int16_t speed;int main()
{OLED_Init(); // 初始化OLEDEnCoder_Init();Timer_Init(); // 初始化定時器OLED_ShowString(1, 1, "speed:"); // 顯示字符串while (1){OLED_ShowSignedNum(1, 7, speed, 5); // 顯示CNT計數器}
}// 中斷函數
void TIM2_IRQHandler(void)
{// 檢測中斷標志位,確保是設置的中斷源觸發的這個函數if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){// 中斷處理speed = Encoder_Get();// 清除中斷標志TIM_ClearITPendingBit(TIM2, TIM_IT_Update);}
}