Подключаем энкодер с помощью таймера

Описание процесса работы с энкодером с помощью таймера в режиме захвата для микроконтроллеров STM32

Cover Image

На этот раз рассмотрим подключение к микроконтроллеру STM32F205 (на остальных аналогично) энкодер.

Есть несколько вариантов считывания информации с энкодера. Но так как микроконтроллер у нас имеет таймеры работающие в режиме захвата и способные обрабатывать сигналы с энкодера, будем пользоваться именно ими.

Подключение выполним к выводам 6 и 7 порта A (это входы/выходы таймера TIM3) вот по схеме на рисунке выше.

В принципе тут всё понятно, А и В подключаются к ногам 6 и 7, а Общий провод - к земле. В моём случае есть ещё кнопка, но она нам не нужна.

Первое что нам нужно сделать, это инициализировать выводы микроконтроллера, которые участвуют в нашем мануале (если конечно можно так сказать). Инициализировать будем с помощью библиотек SPL.

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    //--------- Включаем клоки ---------------------------------
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

    // ------- Энкодер  -------
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM3); 

    GPIO_InitStruct.GPIO_OType  = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd   = GPIO_PuPd_UP;
    GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_100MHz;
    GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Pin    = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

Далее приступаем к инициализации таймера. Тут всё максимально просто.

void TIM_Configuration(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3, ENABLE );

    // ----------------- Таймер для Энкодера -----------------

    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    TIM_TimeBaseStructure.TIM_Period = 1000; // это то значение до которого будет считать таймер
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    /* Считать будем все переходы лог. уровня с обоих каналов */
    TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge, TIM_ICPolarity_BothEdge);

    // -----------------     
    TIM_Cmd(TIM3, ENABLE); // Энкодер
}

Сразу оговорюсь, данный способ имеет свои недостатки, то есть, как только таймер досчитает до максимума, то начнет считать с начала (с нуля), в обратную сторону аналогично. Если такое поведение критично можно обработать прерывание по обновлению счетного регистра таймера, даю намёк - TIM_IT_Update.

Считанные данные хранятся в регистре CNT таймера TIM3. получить их можно так

TIM3->CNT

или с помощью SPL функции

uint32_t TIM_GetCounter(TIM_TypeDef* TIMx);

В принципе и всё. Как видите, всё довольно просто, но если что-то не получается, попробуйте более внимательно прочитать даташит.