Энкодер на базе HEDR и STM32

Энкодер на базе HEDR и STM32

Всем привет!

В данной статье я хочу Вам рассказать про датчик HEDR(от компании avago technologies) - это двухканальный инкрементальный оптический датчик, предназначен для измерения пройденного пути, линейной скорости, угловой скорости и направлении вращения вала.С помощью данного датчика будет реализован энкодер на базе микроконтроллера STM32, который будет производить вычисление пройденного пути.

В данной статье будет рассмотрено:

  • Принцип работы датчика HEDR-5420-ES214;
  • Схема подключения к микроконтроллеру STM32;
  • Программная реализация (расчет пройденного пути и вывод информации на дисплей).

Технические характеристики датчика HEDR-5420-ES214

  • Напряжение питания [ 4.5 - 5.5В ];
  • Тип выхода [ квадратурный ];
  • Диаметр вала [ 5 мм ];
  • Разрешение [ 200 отсчетов на оборот ];
  • Рабочая температура [ от -10°C до +85°C ].

Принцип работы датчика HEDR-5420-ES214

Устройство состоит из трех основных компонентов:

  • Источник света (светодиод, формирующий поток света);
  • Оптическая система (линза, обеспечивает фокусировку и отражение света);
  • Фотодетектор.
Энкодер на базе HEDR и STM32

Линза фокусирует излучаемый свет на кодовое колесо (диск с чередующимися отражающими и неотражающими участками), при вращении диска, отраженный свет проходит обратно через оптическую систему и попадает на фотодиоды, таким образом на их поверхности формируется чередующийся рисунок света и тени, соответствующий узору кодового диска.

Эти изменения интенсивности света преобразуются в внутренние сигналы А и В, которые проходят через компараторы в составе обработки сигналов, на выходе формируются два цифровых прямоугольных сигнала - канал А и В, находящиеся в квадратурной фазе на 90°, что позволяет микроконтроллеру определять направление вращения вала, к примеру:

  • если канал А опережает канал B - вращение происходит в одну сторону;
  • если канал B опережает канал А - вращение происходит в противоположную сторону.

Для своей задачи применяется следующая последовательность, если канал А опережает канал B - движение энкодера считается положительным, если на оборот, то движение будет отрицательным.

                     Осциллограмма данных полученных с датчика HEDR-5420-ES214
                     Осциллограмма данных полученных с датчика HEDR-5420-ES214

Схема подключения к микроконтроллеру STM32

       Схема подключения HEDR и дисплея к микроконтроллеру STM32F030CCT6
       Схема подключения HEDR и дисплея к микроконтроллеру STM32F030CCT6
                                   Макет STM32F030CCTx и HEDR
                                   Макет STM32F030CCTx и HEDR

В данной схеме используются преобразователь напряжения DA1 (+12V +5V) и стабилизатор напряжения DA2, дисплей подключается к выводам МК 21_SCL_I2C2 и 22_SDA_I2C2, датчик HEDR подключается к выводам МК 29_CH.A и 30_CH.B, данные сигналы сначала проходят через делители, R17-R18-[CH.A] и R15-R16-[CH.B], так как датчик работает от +5V, сигналы соответственно тоже у него +5V, я всегда стараюсь дополнительно защитить МК, после делителя амплитуда сигналов снизится до +3.3V, копипастить информацию по описанию узлов преобразователя, стабилизатора, узла обвязки напряжения питания и резонатора для МК не особо хочется, поэтому кому интересно можно почитать статью

Настройка микроконтроллера STM32F030CCTx в CubeIDE

Энкодер на базе HEDR и STM32

Настройка RCC и SYS (в RCC выбираю Crystal/Ceramic Resonator, так как у меня внешний кварц на 8 МГц)

Энкодер на базе HEDR и STM32

Настройка дисплея

Взаимодействие дисплея с МК будет через I2C2

Энкодер на базе HEDR и STM32

Настройка выводов узла подключения датчика HEDR

  • TIM1_CH1 (к данному выводу будет подключаться сигнал CH.A);
  • TIM1_CH2 (к данному выводу будет подключаться сигнал CH.B).
Энкодер на базе HEDR и STM32
Энкодер на базе HEDR и STM32

Таймер используется в режиме Encoder mode - это специальный аппаратный режим, который позволяет микроконтроллеру автоматически подсчитывать импульсы от инкрементального датчика и определять направление вращения, данная конфигурация освобождает МК от необходимости программно обрабатывать прерывания по каждому импульсу.

Encoder Mode TI1 and TI2 данный параметр указывает, что используется оба канала датчика (A и B), это дает разрешение X4 - т.е. счетчик будет увеличиваться на 4 шага за один полный оборот.

Описание режимов

TI1 - подсчет ведется по фронту одного канала А, направление определяется по уровню В, разрешение 1.8 градусов;

TI2 - аналогично логике TI1, но базируется на канале В;

TI1 and TI2 - подсчет ведется на каждом фронте обоих каналов (А+, А-, В+, В-), направление определяется автоматически, т.е. количеством импульсов на оборот 200, я получаю 800 шагов на оборот, разрешение будет 0.45 градусов.

Input Filter - включает цифровую фильтрацию входного сигнала, помогает убрать дребезг и шум, значения от 0 до 15, чем выше значение, тем надежнее фильтрация, но будет повышаться задержка.

Polarity (Rising Edge) - счетчик реагирует на восходящие фронты сигнала.

Настройка Clock

Энкодер на базе HEDR и STM32

Программная реализация ведомого устройства

Ссылка на скачивание исходного кода [ #исскуствомк_исходный_код — Исходный код для Encoder_HEDR_5420_STM32F030CCTx].

Модуль process_Encoder

Данный модуль реализует считывание сигналов с инкрементального датчика HEDR и вычисляет:

  • Количество импульсов на оборот;
  • Пройденную дистанцию;
  • Отображение данных на дисплее.
#define ENCODER_MODE_X4 4

Данный параметр отражает режим подсчета импульсов, привожу формулу:

Энкодер на базе HEDR и STM32

Этот режим обеспечивает максимальную точность - 0.45 на один шаг.

#define WHEEL_DIAMETR_M 0.230f // 230 мм #define WHEEL_RADIUS_M (WHEEL_DIAMETR_M / 2.0f)

Здесь я задаю геометрические размеры колеса, на валу которого установлен датчик%

Диаметр колеса 230 мм (0.230м);

Радиус вычисляется так:

Энкодер на базе HEDR и STM32
#define STEPS_PER_REV (ENCODER_PPR * ENCODER_MODE_X4)

Максимальное количество шагов за один оборот

#define CIRCUMFERENCE_M (2.0f *M_PI * WHEEL_RADIUS_M)

Длина окружности колеса - это путь, который проходит колесо за один оборот

Энкодер на базе HEDR и STM32

т.е. при моем радиусе 0.115, получится за один полный оборот 0.72 м.

Функция display_init() - инициализация дисплея

  • Инициализируется драйвер дисплея;
  • Выполняется заливка экрана черным цветом;
  • На дисплее на 2 секунды отображается стартовый экран с надписью ''ChipCraft";
  • После задержки экран очищается для дальнейшей работы.

библиотеку для работы с дисплеем я взял с [https://github.com/afiskon/stm32-ssd1306/tree/master]

Функция display_update()

Отвечает за визуализацию информации на дисплее:

  • Экран предварительно очищается с помощью ssd1306_Fill(Black);
  • В верхней части по центру отображается надпись «Encoder»;
  • Ниже последовательно выводятся:количество импульсов;дистанция;
  • Буфер графики передается на дисплей вызовом ssd1306_UpdateScreen()

Функция encoder_Handler()

Логика работы:

  • считывание текущего значения таймера;
  • определение разницы (delta) между текущим и предыдущим значениями;
  • накопление общего счетчика enocoder_position;
  • вызов функций для вычисления дистанции и обновление дисплея.

Функция get_distance_m() - вычисление пройденной дистанции

Переводит количество импульсов датчика в физическую длину пути в (метрах).

Модуль process_Encoder.c

#include "./Project/process_Encoder.h" #include "./Project/shared.h" #include "./Project/ssd1306.h" #include "./Project/ssd1306_fonts.h" #include "main.h" #include <stdlib.h>//abs #include <string.h>//memset #include <stdio.h> #include <stdint.h> #include <math.h> #define ENCODER_PPR 200 // импульсов на оборот #define ENCODER_MODE_X4 4 #define WHEEL_DIAMETR_M 0.230f // 230 мм #define WHEEL_RADIUS_M (WHEEL_DIAMETR_M / 2.0f) #define STEPS_PER_REV (ENCODER_PPR * ENCODER_MODE_X4) #define CIRCUMFERENCE_M (2.0f *M_PI * WHEEL_RADIUS_M) uint16_t current_count= 0; int16_t delta = 0; float distance = 0.0f; int32_t encoder_position = 0; uint8_t ssd1306_buffer[SSD1306_BUFFER_SIZE]; void display_init(void) { ssd1306_Init(); ssd1306_Fill(Black); ssd1306_SetCursor(20, 25); ssd1306_WriteString("ChipCraft", Font_11x18, White); ssd1306_UpdateScreen(); HAL_Delay(2000); ssd1306_Fill(Black); ssd1306_UpdateScreen(); } void encoder_Handler(void) { static uint16_t last_count = 0; current_count = __HAL_TIM_GET_COUNTER(&htim1); delta = (int16_t)(current_count - last_count); encoder_position += delta; last_count = current_count; get_distance_m(); display_update(encoder_position, distance); } void display_update(int32_t pulses, float distance) { char buf[32]; ssd1306_Fill(Black); ssd1306_SetCursor(25, 2); ssd1306_WriteString("Encoder" ,Font_11x18, White); sprintf(buf, "Pulses: %ld", pulses); ssd1306_SetCursor(2, 22); ssd1306_WriteString(buf, Font_7x10, White); sprintf(buf, "Dist: %.2f m", distance); ssd1306_SetCursor(2, 36); ssd1306_WriteString(buf, Font_7x10, White); ssd1306_UpdateScreen(); } float get_distance_m(void){ distance = ((float) encoder_position / STEPS_PER_REV) * CIRCUMFERENCE_M; return distance; }

Модуль proj_main() - главный метод

  • Выполняется инициализация дисплея;
  • Запуск таймера;
  • Запуск функции encoder_Handler().
#include "./Project/shared.h" #include "./Project/proj_main.h" #include "./Project/process_Encoder.h" #include "./Project/process_Encoder.h" void proj_main() { volatile const char *ch = ";V-F-BIN;ver: "VER_PROG(VER_a,VER_b,VER_c);(void)ch;//0x8008b00 display_init(); HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); while (1){ //хэндлеры encoder_Handler(); }//while (1) }

Если статья показалась Вам интересной, буду рад выпустить для Вас еще множество статей исследований по всевозможным видам устройств, так что, если не хотите их пропустить — буду благодарен за подписку на мой ТГ-канал.

Начать дискуссию