Работа с энкодером в stm32

Не так давно решил пощупать работу с энкодером.
Для этих целей приобрел себе такой модуль.

В общем это самый обычный инкрементный энкодер KY-040.
Принцип работы сего чуда прост. Имеем два выхода. А и В или же CLK и DT.
При повороте энкодера на них появляются прямоугольные импульсы.
Сдвиг говорит нам о направлении вращения.

К примеру, если в момент заднего фронта на канале А, имеем на канале В единичное значение, то происходит вращение вперед. Если же в момент среза на канале А имеем на канале В нулевое значение, это свидетельствует о вращении в обратную сторону.
Подсчет количества импульсов может сказать нам о положении вала.
Как то вот так все и работает.
Кроме этого в данном энкодере есть также кнопка выведенная на ножку SW.

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

Рассмотрим как инициализировать таймер для работы с энкодером в stm32f4discovery.
Я буду использовать таймер 3.

void init_gpio(void)
{
    GPIO_InitTypeDef gpio;
    GPIO_StructInit(&gpio);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

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

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM3);
}

Ножки контроллера настроены, теперь настраиваем таймер.

void init_timer(void)
{
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  TIM_TimeBaseInitTypeDef timer_base;
  TIM_TimeBaseStructInit(&timer_base);
  timer_base.TIM_Period = 0xffff;
  timer_base.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &timer_base);

  TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,
      TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
  
  TIM3->CNT=255; //начальное значение
  TIM_Cmd(TIM3, ENABLE);
}

Тут мы задали период счетчика, направление счета и сконфигурировали таймер для работы с энкодером.
Теперь в main вызываем эти функции и смотрим значение TIM3->CNT.

init_gpio();
init_timer();

while(1)
{
    u16 cnt = TIM3->CNT;
    Delay(100);
}

Вот и все. Вот так просто.

 

Похожий код:

Фото аватара
Алексей Петров

Программист, разработчик с 5 летним опытом работы. Учусь на разработчика игр на Unity и разработчика VR&AR реальности (виртуальной реальности). Основные языки программирования: C#, C++.

Оцените автора
Бла, бла код
Добавить комментарий

  1. sva

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

    Ответить