Files
2026-06-27 00:39:04 +03:00

99 lines
5.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Драйвер инкрементального энкодера DS_Encoder
Универсальный драйвер для подсчета шагов и определения направления вращения инкрементального энкодера (например, популярного EC11). Поддерживает два независимых режима работы: **аппаратный** (через Encoder Mode таймера STM32) и **программный** (через ручной опрос пинов GPIO).
## 📌 Особенности реализации
* **Двойная архитектура**: выбор между аппаратным декодированием таймером и программным сканированием пинов на лету.
* **Аппаратное подавление дребезга**: при использовании таймера задействуются встроенные цифровые фильтры STM32.
* **Квантование шага**: в аппаратном режиме учтена специфика энкодеров EC11 — счетчик автоматически делится на 4, возвращая ровно 1 шаг за один физический щелчок ручки.
---
## 🛠 Вариант 1: Аппаратный режим (Рекомендуемый)
Данный режим использует периферию таймера микроконтроллера. Процессор не тратит ресурсы на опрос пинов.
### Настройка в STM32CubeMX:
1. Выберите таймер (например, `TIM1` или `TIM2`).
2. В поле **Combined Channels** установите значение **Encoder Mode**.
3. В параметрах таймера (`Parameter Settings`):
* **Encoder Mode**: `Encoder Mode TI1 and TI2` (подсчет по обоим каналам для максимальной точности).
* **Input Filter**: установите значение от `8` до `15` для аппаратного подавления дребезга контактов.
4. Настройте соответствующие пины `TIMx_CH1` и `TIMx_CH2` в режим `GPIO_AF`.
### Пример кода в `main.c`:
```c
#include "Encoder.h"
extern TIM_HandleTypeDef htim1;
DS_Encoder volume_encoder;
int main(void) {
// ... Инициализация HAL, GPIO, TIM ...
/* Инициализируем энкодер в режиме таймера */
DS_EncoderInitTim(&volume_encoder, &htim1);
while (1) {
/* Получаем изменение положения с момента предыдущего опроса */
int8_t diff = DS_EncoderGetState(&volume_encoder);
if (diff != 0) {
// Ручку повернули! diff может быть равен +1, -1, +2 и т.д.
// Применяем изменение, например: volume += diff;
}
HAL_Delay(50); // Опрос можно делать с любой редкой периодичностью
}
}
```
---
## 🕹 Вариант 2: Программный режим (Polling)
Используется, если на плате нет свободных каналов таймера с поддержкой Encoder Mode. Пин 1 и Пин 2 настраиваются как обычные `GPIO_Input` с подтяжкой `Pull-up`.
### Пример кода в `main.c`:
```c
#include "Encoder.h"
DS_Encoder manual_encoder;
int main(void) {
// ... Инициализация ...
/* Инициализация структуры программными пинами */
DS_EncoderInit(&manual_encoder, GPIOB, GPIO_PIN_4, GPIOB, GPIO_PIN_5);
while (1) {
/* ВАЖНО: Функция обновления состояния должна вызываться как можно чаще
(в основном цикле без больших задержек или в быстром таймере) */
DS_EncoderUpdate(&manual_encoder);
/* Проверяем, накопились ли шаги вращения */
int8_t steps = DS_EncoderGetState(&manual_encoder);
if (steps != 0) {
// Обработка программного поворота ручки
}
}
}
```
---
## 📋 Справочник API функций
### `void DS_EncoderInitTim(DS_Encoder *Encoder, TIM_HandleTypeDef *hTim)`
Инициализирует и запускает таймер в режиме аппаратного декодера энкодера.
* **`hTim`**: Указатель на структуру таймера HAL (например, `&htim1`).
### `void DS_EncoderInit(DS_Encoder *Encoder, GPIO_TypeDef *PortEncSignal1, uint16_t PinEncSignal1, GPIO_TypeDef *PortEncSignal2, uint16_t PinEncSignal2)`
Конфигурирует структуру для программного отслеживания уровней на указанных GPIO портах и пинах.
### `void DS_EncoderUpdate(DS_Encoder *Encoder)`
Конечный автомат программного парсинга квадратурного сигнала. Опрашивает физическое состояние пинов. Требует высокой частоты вызова.
### `int8_t DS_EncoderGetState(DS_Encoder *Encoder)`
Возвращает относительное изменение положения энкодера (количество шагов) с момента последнего вызова этой функции и **автоматически обнуляет** внутренний накопительный счетчик.