STM32 Study Notes_9 Interrupção do Timer: Modo de Interface do Codificador

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.

imagem-20230515201313919

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.

imagem-20230515201912210

imagem-20230515202159695

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.

imagem-20230515202625535

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.

imagem-20230515202857336

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);
    }
}

Acho que você gosta

Origin blog.csdn.net/jtwqwq/article/details/130699623
Recomendado
Clasificación