interface do codificador TIM
Antes de tratarmos do codificador rotativo, ele era interrompido uma vez ao ser girado, o que consumia recursos.
Podemos usar a função de codificador do TIM para obter o valor do rotator em intervalos para fazer cnt++ ou –, para julgar a posição de rotação e a velocidade de cálculo, o que economiza recursos em comparação com as interrupções. É equivalente a conectar um relógio externo com direção.
O codificador pode receber o sinal do codificador de quadratura para controlar o auto-incremento e auto-decremento de cnt.
Ao julgar a borda de subida/descida de uma das fases, a outra fase é alta ou baixa para determinar a direção da rotação.
A avaliação da interface do codificador é positiva e negativa, controle cnt++ ou –. arr é definido como 65535, de modo que, quando cnt=0, ele se tornará 65535 quando for decrementado e será -1 quando for convertido em um número com sinal.
O último é comumente usado e tem alta precisão.
O conteúdo aqui é o julgamento correspondente à fase AB. Por exemplo, na figura, FP1 sobe para FP2 nível alto, se 1 é fase A e 2 é fase B, ou seja, quando A está subindo, B está em nível alto, o que corresponde a inversão, então faz a contagem regressiva.
Se um sinal transitar, o outro estado do sinal é o mesmo da última transição, indicando uma falha. O valor da contagem oscila para frente e para trás para filtrar o ruído.
Código: Codificador tacável baseado em temporizador
A maioria ainda são códigos baseados em IC. Nova função: TIM_EncoderInterfaceConfig, configura a interface do codificador.
#include "stm32f10x.h"
void Encoder_Init(){
//rcc, gpio, time base, ic(只配置滤波器和极性), TIM_Cmd 启动
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
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;
//比如我们想定1s中断一次,CK_CNT_OV = CK_CNT / (ARR + 1) = CK_PSC / (PSC + 1) / (ARR + 1),也就是72M / (PSC + 1) / (ARR + 1) = 1
//所以两者赋值可以是10000-1和7200-1,只要两者都在65535以内就行,赋值不唯一
TIM_TimeBaseInitStructure.TIM_Period=65536-1;
TIM_TimeBaseInitStructure.TIM_Prescaler=1-1;//预分频器值,不分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器值,高级计数器才用
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
//PA6 7对应定时器3,oc channel1 channel2.
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;//PA6对应定时器3 ch1
//TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;//下面一行配置的极性会覆盖上面的配置,所以这里不用写
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//PA7对应定时器3 ch2
//TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICFilter=0xF;//滤波消除毛刺,越大效果越好,看需求
TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);
TIM_Cmd(TIM3, ENABLE);
}
uint16_t Encoder_Get(){
return TIM_GetCounter(TIM3);
}
Devido ao giro de uma grade, cada AB tem uma borda descendente e uma borda ascendente, então ±4.
Se você deseja medir a velocidade, pode limpá-la manualmente após obtê-la na função get e adicionar um atraso para obtê-la no principal, como uma vez a cada 1000 ms.
while(1){
OLED_ShowNum(4,1,Encoder_Get(),5);
Delay_ms(1000);
}
No entanto, escrever o atraso na função principal afetará a operação de outras partes do programa, portanto, é melhor escrever uma função de interrupção.
void TIM2_IRQHandler(void){
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET){
cnt=Encoder_Get();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}