168 lines
9.5 KiB
C++
Executable File
168 lines
9.5 KiB
C++
Executable File
#pragma once
|
||
#include "mbed.h"
|
||
|
||
/*
|
||
GyverEncoder - библиотека для отработки энкодера. Возможности:
|
||
- Отработка поворота энкодера
|
||
- Отработка "нажатого поворота"
|
||
- Отработка "быстрого поворота"
|
||
- Несколько алгоритмов опроса энкодера
|
||
- Выбор подтяжки подключения энкодера
|
||
- Работа с двумя типами экнодеров
|
||
- Работа с внешним энкодером (через расширитель пинов и т.п.)
|
||
- Отработка нажатия/удержания кнопки с антидребезгом
|
||
|
||
Документацию читай здесь: https://alexgyver.ru/encoder/
|
||
Для максимально быстрого (в 2 раза быстрее) опроса энкодера рекомендуется использовать ядро GyverCore https://alexgyver.ru/gyvercore/
|
||
|
||
Версии:
|
||
- 3.6 от 16.09.2019 - Возвращены дефайны настроек
|
||
- 4.0 от 13.11.2019
|
||
- Оптимизирован код
|
||
- Исправлены баги
|
||
- Добавлены другие алгоритмы опроса
|
||
- Добавлена возможность полностью убрать кнопку (экономия памяти)
|
||
- Добавлена возможность подключения внешнего энкодера
|
||
- Добавлена настройка подтяжки пинов
|
||
- 4.1
|
||
- Исправлено изменение подтяжек
|
||
|
||
- 4.2
|
||
- Добавлена поддержка TYPE1 для алгоритма PRECISE_ALGORITHM
|
||
- Добавлена отработка двойного клика: isSingle / isDouble
|
||
*/
|
||
// ========= КОНСТАНТЫ ==========
|
||
#define ENC_NO_BUTTON -1 // константа для работы без пина
|
||
#define TYPE1 0 // полушаговый энкодер
|
||
#define TYPE2 1 // полношаговый
|
||
#define NORM 0 // направление вращения обычное
|
||
#define REVERSE 1 // обратное
|
||
#define MANUAL 0 // нужно вызывать функцию tick() вручную
|
||
#define AUTO 1 // tick() входит во все остальные функции и опрашивается сама!
|
||
#define HIGH_PULL 0 // внутренняя подтяжка к питанию (pinMode INPUT_PULLUP)
|
||
#define LOW_PULL 1 // внешняя подтяжка к GND (pinMode INPUT)
|
||
|
||
// =========== НАСТРОЙКИ ===========
|
||
// закомментируй строку, чтобы полностью убрать отработку кнопки из кода
|
||
#define ENC_WITH_BUTTON
|
||
|
||
// тип подключения энкодера по умолчанию (LOW_PULL или HIGH_PULL)
|
||
//#define DEFAULT_ENC_PULL LOW_PULL
|
||
#define DEFAULT_ENC_PULL HIGH_PULL
|
||
|
||
// тип подключения кнопки энкодера по умолчанию (LOW_PULL или HIGH_PULL)
|
||
//#define DEFAULT_BTN_PULL LOW_PULL
|
||
#define DEFAULT_BTN_PULL HIGH_PULL
|
||
|
||
// алгоритмы опроса энкодера (раскомментировать нужный)
|
||
//#define FAST_ALGORITHM // тик 10 мкс, быстрый, не справляется с люфтами
|
||
//#define BINARY_ALGORITHM // тик 14 мкс, лучше справляется с люфтами
|
||
#define PRECISE_ALGORITHM // тик 16 мкс, медленнее, но работает даже с убитым энкодером (по мотивам https://github.com/mathertel/RotaryEncoder)
|
||
|
||
// настройка антидребезга энкодера, кнопки, таймаута удержания и таймаута двойного клика
|
||
#define ENC_DEBOUNCE_TURN 1ms
|
||
#define ENC_DEBOUNCE_BUTTON 10ms
|
||
#define ENC_HOLD_TIMEOUT 700ms
|
||
#define ENC_DOUBLE_TIMEOUT 300ms
|
||
|
||
// The sample time in ms.
|
||
const int SAMPLE_TIME = 1;
|
||
|
||
// The number of samples that must agree before a key state change is recognised.
|
||
// 50 = 50ms for 1ms sample time.
|
||
const int DEBOUNCE_COUNT = 50;
|
||
|
||
// The number of samples that must agree before a key held state is recognised.
|
||
// 1000 = 1s for 1ms sample time.
|
||
const int HOLD_COUNT = 1000;
|
||
|
||
// The number of samples that must agree before a key repeat state is recognised.
|
||
// 200 = 200ms for 1ms sample time.
|
||
const int REPEAT_COUNT = 200;
|
||
|
||
#pragma pack(push, 1)
|
||
typedef struct
|
||
{
|
||
bool hold_flag : 1;
|
||
bool butt_flag : 1;
|
||
bool turn_flag : 1;
|
||
bool isTurn_f : 1;
|
||
bool isPress_f : 1;
|
||
bool isRelease_f : 1;
|
||
bool isHolded_f : 1;
|
||
bool isFastR_f : 1;
|
||
bool isFastL_f : 1;
|
||
bool isReleaseHold_f : 1;
|
||
bool enc_tick_mode : 1;
|
||
bool enc_type : 1;
|
||
bool use_button : 1;
|
||
bool extCLK : 1;
|
||
bool extDT : 1;
|
||
bool extSW : 1;
|
||
bool invBtn : 1;
|
||
bool isSingle_f : 1;
|
||
bool isDouble_f : 1;
|
||
bool countFlag : 1;
|
||
bool doubleFlag : 1;
|
||
bool doubleAllow : 1;
|
||
} GyverEncoderFlags;
|
||
#pragma pack(pop)
|
||
|
||
// Варианты инициализации:
|
||
// Encoder enc; // не привязан к пину
|
||
// Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
||
// Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
||
// Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
||
// Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
||
|
||
class Encoder {
|
||
public:
|
||
Encoder(); // для непривязанного к пинам энкодера
|
||
Encoder(PinName clk, PinName dt, PinName sw, bool type = false); // CLK, DT, SW, тип (TYPE1 / TYPE2) TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||
|
||
void tick(); // опрос энкодера, нужно вызывать постоянно или в прерывании
|
||
void tick(bool clk, bool dt, bool sw = 0); // опрос "внешнего" энкодера
|
||
void setType(bool type); // TYPE1 / TYPE2 - тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
||
void setPinMode(bool mode); // тип подключения энкодера, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||
void setBtnPinMode(bool mode); // тип подключения кнопки, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
||
void setTickMode(bool tickMode); // MANUAL / AUTO - ручной или автоматический опрос энкодера функцией tick(). (по умолчанию ручной)
|
||
void setDirection(bool direction); // NORM / REVERSE - направление вращения энкодера
|
||
void setFastTimeout(Kernel::Clock::duration timeout); // установка таймаута быстрого поворота
|
||
|
||
bool isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
|
||
bool isRight(); // возвращает true при повороте направо, сама сбрасывается в false
|
||
bool isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
|
||
bool isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
|
||
bool isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
|
||
bool isFastR(); // возвращает true при быстром повороте
|
||
bool isFastL(); // возвращает true при быстром повороте
|
||
|
||
bool isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
|
||
bool isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
|
||
bool isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
|
||
bool isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
|
||
bool isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
|
||
bool isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
|
||
bool isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
|
||
void start();
|
||
void stop();
|
||
|
||
private:
|
||
Thread* encThread;
|
||
GyverEncoderFlags flags;
|
||
Kernel::Clock::duration _fast_timeout = 50ms; // таймаут быстрого поворота
|
||
uint8_t prevState = 0;
|
||
uint8_t encState = 0; // 0 не крутился, 1 лево, 2 право, 3 лево нажат, 4 право нажат
|
||
Kernel::Clock::time_point debounce_timer;
|
||
Kernel::Clock::time_point fast_timer;
|
||
DigitalIn* _CLK;
|
||
DigitalIn* _DT;
|
||
DigitalIn* _SW;
|
||
|
||
Kernel::Clock::duration debounceDelta;
|
||
Kernel::Clock::time_point thisMls;
|
||
|
||
bool turnFlag = false, extTick = false, SW_state = false;
|
||
void encoderThread();
|
||
};
|