99 lines
5.7 KiB
Markdown
99 lines
5.7 KiB
Markdown
# Драйвер инкрементального энкодера 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)`
|
||
Возвращает относительное изменение положения энкодера (количество шагов) с момента последнего вызова этой функции и **автоматически обнуляет** внутренний накопительный счетчик.
|