Первая итерация

This commit is contained in:
2026-06-27 00:39:04 +03:00
parent 2009035bb4
commit c4ec2b64cd
12 changed files with 951 additions and 180 deletions
+98
View File
@@ -0,0 +1,98 @@
# Драйвер инкрементального энкодера 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)`
Возвращает относительное изменение положения энкодера (количество шагов) с момента последнего вызова этой функции и **автоматически обнуляет** внутренний накопительный счетчик.