Устранена мёртвая зона энкодера при реверсе
Фаза фиксации передаётся в Encoder_Init явно и не зависит от положения контактов при включении. Для режимов с двумя и четырьмя переходами детент завершается только на заданных границах; повреждённый остаток сбрасывается при возвращении к ним. Сохранён счётчик недопустимых переходов. Проверены старт во всех фазах, дребезг, реверсы и восстановление после пропуска переходов в host-тестах основного проекта; измерения установленного энкодера не выполнялись.
This commit is contained in:
@@ -23,16 +23,17 @@ typedef struct
|
|||||||
uint16_t pin_a;
|
uint16_t pin_a;
|
||||||
uint16_t pin_b;
|
uint16_t pin_b;
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
|
uint8_t detent_state;
|
||||||
uint8_t steps_per_detent;
|
uint8_t steps_per_detent;
|
||||||
int8_t partial_steps;
|
int8_t partial_steps;
|
||||||
uint32_t invalid_transitions;
|
uint32_t invalid_transitions;
|
||||||
} Encoder_HandleTypeDef;
|
} Encoder_HandleTypeDef;
|
||||||
|
|
||||||
/** Привязать настроенные GPIO A/B; steps_per_detent — от 1 до 4. */
|
/** Привязать GPIO A/B; detent_state задаёт фазу фиксации, не фазу включения. */
|
||||||
HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
||||||
GPIO_TypeDef *port_a, uint16_t pin_a,
|
GPIO_TypeDef *port_a, uint16_t pin_a,
|
||||||
GPIO_TypeDef *port_b, uint16_t pin_b,
|
GPIO_TypeDef *port_b, uint16_t pin_b,
|
||||||
unsigned steps_per_detent);
|
unsigned steps_per_detent, unsigned detent_state);
|
||||||
/** Самостоятельно опросить GPIO, обработать фазы и вернуть -1, 0 или +1 детент. */
|
/** Самостоятельно опросить GPIO, обработать фазы и вернуть -1, 0 или +1 детент. */
|
||||||
int Encoder_Update(Encoder_HandleTypeDef *encoder);
|
int Encoder_Update(Encoder_HandleTypeDef *encoder);
|
||||||
|
|
||||||
|
|||||||
+21
-3
@@ -22,16 +22,17 @@ static uint8_t read_phases(const Encoder_HandleTypeDef *encoder)
|
|||||||
* @brief Подготовить независимый экземпляр энкодера к опросу.
|
* @brief Подготовить независимый экземпляр энкодера к опросу.
|
||||||
* @details Входы предварительно настраивает CubeMX или вызывающий код.
|
* @details Входы предварительно настраивает CubeMX или вызывающий код.
|
||||||
* Начальный снимок предотвращает событие при включении питания.
|
* Начальный снимок предотвращает событие при включении питания.
|
||||||
* Число переходов задаётся механикой конкретного энкодера.
|
* Число переходов и фаза фиксации заданы конфигурацией энкодера.
|
||||||
|
* Промежуточное положение при включении не становится фазой фиксации.
|
||||||
* @return HAL_OK при успехе, HAL_ERROR при неверной конфигурации.
|
* @return HAL_OK при успехе, HAL_ERROR при неверной конфигурации.
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
||||||
GPIO_TypeDef *port_a, uint16_t pin_a,
|
GPIO_TypeDef *port_a, uint16_t pin_a,
|
||||||
GPIO_TypeDef *port_b, uint16_t pin_b,
|
GPIO_TypeDef *port_b, uint16_t pin_b,
|
||||||
unsigned steps_per_detent)
|
unsigned steps_per_detent, unsigned detent_state)
|
||||||
{
|
{
|
||||||
if (!encoder || !port_a || !port_b || !pin_a || !pin_b ||
|
if (!encoder || !port_a || !port_b || !pin_a || !pin_b ||
|
||||||
!steps_per_detent || steps_per_detent > 4U)
|
!steps_per_detent || steps_per_detent > 4U || detent_state > 3U)
|
||||||
{
|
{
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
@@ -40,6 +41,7 @@ HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
|||||||
encoder->pin_a = pin_a;
|
encoder->pin_a = pin_a;
|
||||||
encoder->pin_b = pin_b;
|
encoder->pin_b = pin_b;
|
||||||
encoder->state = read_phases(encoder);
|
encoder->state = read_phases(encoder);
|
||||||
|
encoder->detent_state = (uint8_t)detent_state;
|
||||||
encoder->steps_per_detent = (uint8_t)steps_per_detent;
|
encoder->steps_per_detent = (uint8_t)steps_per_detent;
|
||||||
encoder->partial_steps = 0;
|
encoder->partial_steps = 0;
|
||||||
encoder->invalid_transitions = 0U;
|
encoder->invalid_transitions = 0U;
|
||||||
@@ -50,6 +52,9 @@ HAL_StatusTypeDef Encoder_Init(Encoder_HandleTypeDef *encoder,
|
|||||||
* @brief Превратить последовательность фаз в законченный шаг вращения.
|
* @brief Превратить последовательность фаз в законченный шаг вращения.
|
||||||
* @details Обратные переходы компенсируют дребезг. Одновременная смена обеих
|
* @details Обратные переходы компенсируют дребезг. Одновременная смена обеих
|
||||||
* фаз обрывает незавершённый детент и учитывается как пропуск опроса.
|
* фаз обрывает незавершённый детент и учитывается как пропуск опроса.
|
||||||
|
* Для 4/2 переходов шаг завершается только в опорной/противоположной
|
||||||
|
* фазе покоя. Возврат к ней сбрасывает остаток повреждённого детента:
|
||||||
|
* пропуск не сдвигает последующие шаги и не создаёт люфт при реверсе.
|
||||||
* Функция сама читает оба GPIO; вызывающий код задаёт частоту опроса.
|
* Функция сама читает оба GPIO; вызывающий код задаёт частоту опроса.
|
||||||
*/
|
*/
|
||||||
int Encoder_Update(Encoder_HandleTypeDef *encoder)
|
int Encoder_Update(Encoder_HandleTypeDef *encoder)
|
||||||
@@ -71,6 +76,19 @@ int Encoder_Update(Encoder_HandleTypeDef *encoder)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
encoder->partial_steps += direction[previous * 4U + state];
|
encoder->partial_steps += direction[previous * 4U + state];
|
||||||
|
if (encoder->steps_per_detent == 4U || encoder->steps_per_detent == 2U)
|
||||||
|
{
|
||||||
|
int step;
|
||||||
|
if (state != encoder->detent_state &&
|
||||||
|
!(encoder->steps_per_detent == 2U && state == (encoder->detent_state ^ 3U)))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
step = encoder->partial_steps >= (int)encoder->steps_per_detent ? 1 :
|
||||||
|
encoder->partial_steps <= -(int)encoder->steps_per_detent ? -1 : 0;
|
||||||
|
encoder->partial_steps = 0;
|
||||||
|
return step;
|
||||||
|
}
|
||||||
if (encoder->partial_steps >= (int)encoder->steps_per_detent)
|
if (encoder->partial_steps >= (int)encoder->steps_per_detent)
|
||||||
{
|
{
|
||||||
encoder->partial_steps -= (int8_t)encoder->steps_per_detent;
|
encoder->partial_steps -= (int8_t)encoder->steps_per_detent;
|
||||||
|
|||||||
Reference in New Issue
Block a user