add disp
This commit is contained in:
parent
0e1f3c1579
commit
d62ecbc979
23
README.md
23
README.md
@ -0,0 +1,23 @@
|
|||||||
|
<h1 align="center">PumpController</h1>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/Pendosv">
|
||||||
|
<img src="https://img.shields.io/github/followers/Pendosv?label=Follow&style=social">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/Pendosv/PumpController">
|
||||||
|
<img src="https://img.shields.io/github/stars/Pendosv/PumpController?style=social">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
Contact with me
|
||||||
|
</p>
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://T.me/Pend0s">
|
||||||
|
<img src="https://raw.githubusercontent.com/Pendosv/Pendosv/master/img/telegram.png" width="40" height="40">
|
||||||
|
</a>
|
||||||
|
<a href="mailto:djvlad967891@gmail.com">
|
||||||
|
<img src="https://raw.githubusercontent.com/Pendosv/Pendosv/master/img/mail.png" width="40" height="40">
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
@ -1,29 +1,46 @@
|
|||||||
#define pressure_Aport 0
|
#define pressure_Aport 0
|
||||||
#define relay_Dport 5
|
#define relay_Dport 5
|
||||||
|
|
||||||
#define CLK 2
|
#define S1 2
|
||||||
#define DT 3
|
#define S2 3
|
||||||
#define SW 4
|
#define KEY 4
|
||||||
|
|
||||||
|
#define CLK 6
|
||||||
|
#define DIO 7
|
||||||
|
|
||||||
#define const_pressure_min 0
|
#define const_pressure_min 0
|
||||||
#define const_pressure_max 1000
|
#define const_pressure_max 1000
|
||||||
|
|
||||||
#include <GyverEncoder.h>
|
#include <EncButton.h>
|
||||||
#include <EEPROM.h>
|
#include <EEPROM.h>
|
||||||
|
#include <GyverTM1637.h>
|
||||||
|
|
||||||
|
|
||||||
int pressure, pressure_min, pressure_max;
|
int pressure, pressure_min, pressure_max;
|
||||||
bool flag;
|
bool flag;
|
||||||
|
unsigned long last_time1, last_time2;
|
||||||
|
|
||||||
Encoder enc(CLK, DT, SW);
|
|
||||||
|
|
||||||
|
EncButton<EB_TICK, S1, S2, KEY> enc;
|
||||||
|
GyverTM1637 disp(CLK, DIO);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int constraint_pressure(int pressure_) {
|
||||||
|
return constrain(pressure_, 0, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
enc.setType(TYPE2);
|
|
||||||
pinMode(relay_Dport, OUTPUT);
|
pinMode(relay_Dport, OUTPUT);
|
||||||
|
|
||||||
EEPROM.get(0, pressure_min);
|
EEPROM.get(0, pressure_min);
|
||||||
EEPROM.get(2, pressure_max);
|
EEPROM.get(2, pressure_max);
|
||||||
|
|
||||||
|
disp.clear();
|
||||||
|
disp.brightness(7);
|
||||||
|
disp.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@ -32,20 +49,24 @@ void loop() {
|
|||||||
enc.tick();
|
enc.tick();
|
||||||
if (enc.isTurn()) {
|
if (enc.isTurn()) {
|
||||||
if (enc.isRight()) {
|
if (enc.isRight()) {
|
||||||
pressure_min = constrain(pressure_min+10, const_pressure_min, const_pressure_max);
|
pressure_min = constraint_pressure(pressure_min+10);
|
||||||
|
disp.displayInt(pressure_min);
|
||||||
}
|
}
|
||||||
if (enc.isLeft()) {
|
if (enc.isLeft()) {
|
||||||
pressure_min = constrain(pressure_min-10, const_pressure_min, const_pressure_max);
|
pressure_min = constraint_pressure(pressure_min-10);
|
||||||
|
disp.displayInt(pressure_min);
|
||||||
}
|
}
|
||||||
if (enc.isRightH()) {
|
if (enc.isRightH()) {
|
||||||
pressure_min = constrain(pressure_max+10, const_pressure_min, const_pressure_max);
|
pressure_max = constraint_pressure(pressure_max+10);
|
||||||
|
disp.displayInt(pressure_max);
|
||||||
}
|
}
|
||||||
if (enc.isLeftH()) {
|
if (enc.isLeftH()) {
|
||||||
pressure_min = constrain(pressure_max-10, const_pressure_min, const_pressure_max);
|
pressure_max = constraint_pressure(pressure_max-10);
|
||||||
|
disp.displayInt(pressure_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enc.isClick()) {
|
if (enc.isHolded()) {
|
||||||
EEPROM.put(0, pressure_min);
|
EEPROM.put(0, pressure_min);
|
||||||
EEPROM.put(2, pressure_max);
|
EEPROM.put(2, pressure_max);
|
||||||
}
|
}
|
||||||
@ -53,6 +74,12 @@ void loop() {
|
|||||||
|
|
||||||
pressure = analogRead(pressure_Aport);
|
pressure = analogRead(pressure_Aport);
|
||||||
|
|
||||||
|
if (millis() - last_time1 > 850) {
|
||||||
|
last_time1 = millis();
|
||||||
|
disp.displayInt(pressure);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pressure < pressure_min) {
|
if (pressure < pressure_min) {
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
digitalWrite(relay_Dport, HIGH);
|
digitalWrite(relay_Dport, HIGH);
|
||||||
|
|||||||
194
libraries/EncButton/README.md
Normal file
194
libraries/EncButton/README.md
Normal file
@ -0,0 +1,194 @@
|
|||||||
|

|
||||||
|

|
||||||
|
# EncButton
|
||||||
|
Ультра лёгкая и быстрая библиотека для энкодера, энкодера с кнопкой или просто кнопки
|
||||||
|
- Максимально быстрое чтение пинов для AVR (ATmega328/ATmega168, ATtiny85/ATtiny13)
|
||||||
|
- Оптимизированный вес
|
||||||
|
- Быстрые и лёгкие алгоритмы кнопки и энкодера
|
||||||
|
- Энкодер: поворот, нажатый поворот, быстрый поворот, счётчик
|
||||||
|
- Кнопка: антидребезг, клик, несколько кликов, счётчик кликов, удержание, режим step
|
||||||
|
- Подключение - **только с подтяжкой к питанию** (внешней или внутренней)!
|
||||||
|
- Опциональный режим callback (+22б SRAM на каждый экземпляр)
|
||||||
|
- Виртуальный режим (кнопка, энк, энк с кнопкой)
|
||||||
|
|
||||||
|
### Совместимость
|
||||||
|
Совместима со всеми Arduino платформами (используются Arduino-функции)
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
- [Установка](#install)
|
||||||
|
- [Инициализация](#init)
|
||||||
|
- [Использование](#usage)
|
||||||
|
- [Пример](#example)
|
||||||
|
- [Версии](#versions)
|
||||||
|
- [Баги и обратная связь](#feedback)
|
||||||
|
|
||||||
|
<a id="install"></a>
|
||||||
|
## Установка
|
||||||
|
- Библиотеку можно найти по названию **EncButton** и установить через менеджер библиотек в:
|
||||||
|
- Arduino IDE
|
||||||
|
- Arduino IDE v2
|
||||||
|
- PlatformIO
|
||||||
|
- [Скачать библиотеку](https://github.com/GyverLibs/EncButton/archive/refs/heads/main.zip) .zip архивом для ручной установки:
|
||||||
|
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
|
||||||
|
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
|
||||||
|
- Распаковать и положить в *Документы/Arduino/libraries/*
|
||||||
|
- (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
|
||||||
|
- Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
|
||||||
|
|
||||||
|
<a id="init"></a>
|
||||||
|
## Инициализация
|
||||||
|
```cpp
|
||||||
|
EncButton<MODE, A, B, KEY> enc; // энкодер с кнопкой и пинами A, B, KEY
|
||||||
|
EncButton<MODE, A, B> enc; // просто энкодер с пинами A, B
|
||||||
|
EncButton<MODE, KEY> btn; // просто кнопка с пином KEY
|
||||||
|
// MODE: EB_TICK или EB_CALLBACK - режим работы ручной или с обработчиками
|
||||||
|
|
||||||
|
// по умолчанию пины настроены в INPUT_PULLUP
|
||||||
|
// Если используется внешняя подтяжка - лучше перевести в INPUT
|
||||||
|
EncButton<EB_TICK, 2, 3, 4> enc(INPUT);
|
||||||
|
|
||||||
|
// Виртуальный режим:
|
||||||
|
EncButton<MODE, VIRT_BTN> enc; // виртуальная кнопка
|
||||||
|
EncButton<MODE, VIRT_ENCBTN> enc; // виртуальный энк с кнопкой
|
||||||
|
EncButton<MODE, VIRT_ENC> enc; // виртуальный энк
|
||||||
|
// в tick нужно передавать виртуальное значение, см. ниже!
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="usage"></a>
|
||||||
|
## Использование
|
||||||
|
```cpp
|
||||||
|
void pullUp(); // подтянуть пины внутренней подтяжкой
|
||||||
|
void holdEncButton(bool state); // виртуально зажать кнопку энкодера
|
||||||
|
void setHoldTimeout(int tout); // установить время удержания кнопки, мс (до 30 000)
|
||||||
|
|
||||||
|
// тикер, вызывать как можно чаще или в прерывании
|
||||||
|
// вернёт отличное от нуля значение, если произошло какое то событие
|
||||||
|
uint8_t tick();
|
||||||
|
|
||||||
|
// tick может принимать виртуальный сигнал при режиме VIRT_:
|
||||||
|
// (сигнал кнопки)
|
||||||
|
// (сигнал энкодера А, сигнал энкодера B)
|
||||||
|
// (сигнал энкодера А, сигнал энкодера B, сигнал кнопки)
|
||||||
|
|
||||||
|
uint8_t getState(); // получить статус
|
||||||
|
void resetState(); // сбросить статус
|
||||||
|
|
||||||
|
// обработка энкодера
|
||||||
|
bool isTurn(); // факт поворота
|
||||||
|
bool isRight(); // вправо
|
||||||
|
bool isLeft(); // влево
|
||||||
|
bool isRightH(); // вправо нажатый
|
||||||
|
bool isLeftH(); // влево нажатый
|
||||||
|
bool isFast(); // быстрый
|
||||||
|
int counter; // доступ к счётчику энкодера
|
||||||
|
|
||||||
|
// обработка кнопки
|
||||||
|
bool isPress(); // нажатие
|
||||||
|
bool isRelease(); // отпускание
|
||||||
|
bool isClick(); // клик
|
||||||
|
bool isHolded(); // было удержание (однократное срабатывание)
|
||||||
|
bool isHold(); // удерживается (постоянное срабатывание)
|
||||||
|
bool isStep(); // режим шага
|
||||||
|
bool state(); // текущий статус кнопки
|
||||||
|
bool hasClicks(uint8_t numClicks); // проверка на наличие указанного количества кликов
|
||||||
|
uint8_t hasClicks(); // вернёт количество кликов, если они есть
|
||||||
|
uint8_t clicks; // доступ к счётчику кликов
|
||||||
|
|
||||||
|
// для режима с обработчиком
|
||||||
|
void attach(eb_callback type, void (*handler)()); // подключить обработчик
|
||||||
|
void detach(eb_callback type); // отключить обработчик
|
||||||
|
void attachClicks(uint8_t amount, void (*handler)()); // подключить обработчик на количество кликов (может быть только один!)
|
||||||
|
void detachClicks(); // отключить обработчик на количество кликов
|
||||||
|
|
||||||
|
// eb_callback может быть:
|
||||||
|
TURN_HANDLER
|
||||||
|
RIGHT_HANDLER
|
||||||
|
LEFT_HANDLER
|
||||||
|
RIGHT_H_HANDLER
|
||||||
|
LEFT_H_HANDLER
|
||||||
|
CLICK_HANDLER
|
||||||
|
HOLDED_HANDLER
|
||||||
|
STEP_HANDLER
|
||||||
|
HOLD_HANDLER
|
||||||
|
CLICKS_HANDLER
|
||||||
|
PRESS_HANDLER
|
||||||
|
RELEASE_HANDLER
|
||||||
|
// СМОТРИ ПРИМЕР
|
||||||
|
|
||||||
|
// дефайны настроек (дефайнить ПЕРЕД ПОДКЛЮЧЕНИЕМ БИБЛИОТЕКИ)
|
||||||
|
// показаны значения по умолчанию
|
||||||
|
//#define EB_FAST 30 // таймаут быстрого поворота, мс
|
||||||
|
//#define EB_DEB 80 // дебаунс кнопки, мс
|
||||||
|
//#define EB_HOLD 1000 // таймаут удержания кнопки, мс
|
||||||
|
//#define EB_STEP 500 // период срабатывания степ, мс
|
||||||
|
//#define EB_CLICK 400 // таймаут накликивания, мс
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="example"></a>
|
||||||
|
## Пример
|
||||||
|
Остальные примеры смотри в **examples**!
|
||||||
|
```cpp
|
||||||
|
// Пример с прямой работой библиотеки
|
||||||
|
|
||||||
|
#include <EncButton.h>
|
||||||
|
EncButton<EB_TICK, 2, 3, 4> enc; // энкодер с кнопкой <A, B, KEY>
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
enc.counter = 100; // изменение счётчика
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
enc.tick();
|
||||||
|
|
||||||
|
if (enc.isTurn()) { // любой поворот
|
||||||
|
Serial.print("turn ");
|
||||||
|
Serial.println(enc.counter); // вывод счётчика
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isLeft()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast left");
|
||||||
|
else Serial.println("left");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isRight()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast right");
|
||||||
|
else Serial.println("right");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isLeftH()) Serial.println("leftH");
|
||||||
|
if (enc.isRightH()) Serial.println("rightH");
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isHolded()) Serial.println("holded");
|
||||||
|
if (enc.isStep()) Serial.println("step");
|
||||||
|
|
||||||
|
if (enc.isPress()) Serial.println("press");
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isRelease()) Serial.println("release");
|
||||||
|
|
||||||
|
if (enc.hasClicks(1)) Serial.println("1 click");
|
||||||
|
if (enc.hasClicks(2)) Serial.println("2 click");
|
||||||
|
if (enc.hasClicks(3)) Serial.println("3 click");
|
||||||
|
if (enc.hasClicks(5)) Serial.println("5 click");
|
||||||
|
|
||||||
|
if (enc.hasClicks()) Serial.println(enc.clicks);
|
||||||
|
//if (enc.isHold()) Serial.println("hold");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="versions"></a>
|
||||||
|
## Версии
|
||||||
|
- v1.1 - пуллап отдельныи методом
|
||||||
|
- v1.2 - можно передать конструктору параметр INPUT_PULLUP / INPUT(умолч)
|
||||||
|
- v1.3 - виртуальное зажатие кнопки энкодера вынесено в отдельную функцию + мелкие улучшения
|
||||||
|
- v1.4 - обработка нажатия и отпускания кнопки
|
||||||
|
- v1.5 - добавлен виртуальный режим
|
||||||
|
- v1.6 - оптимизация работы в прерывании
|
||||||
|
- v1.6.1 - подтяжка по умолчанию INPUT_PULLUP
|
||||||
|
- v1.7 - большая оптимизация памяти, переделан FastIO
|
||||||
|
- v1.8 - индивидуальная настройка таймаута удержания кнопки (была общая на всех)
|
||||||
|
|
||||||
|
<a id="feedback"></a>
|
||||||
|
## Баги и обратная связь
|
||||||
|
При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
|
||||||
|
Библиотека открыта для доработки и ваших **Pull Request**'ов!
|
||||||
74
libraries/EncButton/examples/callbackMode/callbackMode.ino
Normal file
74
libraries/EncButton/examples/callbackMode/callbackMode.ino
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Пример с обработчиками
|
||||||
|
|
||||||
|
// Опциональные дефайн-настройки (показаны по умолчанию)
|
||||||
|
//#define EB_FAST 30 // таймаут быстрого поворота, мс
|
||||||
|
//#define EB_DEB 80 // дебаунс кнопки, мс
|
||||||
|
//#define EB_HOLD 1000 // таймаут удержания кнопки, мс
|
||||||
|
//#define EB_STEP 500 // период срабатывания степ, мс
|
||||||
|
//#define EB_CLICK 400 // таймаут накликивания, мс
|
||||||
|
|
||||||
|
// подключение - только PULL-UP, внешний или внутренний!
|
||||||
|
// для изменения направления энкодера поменяй A и B при инициализации
|
||||||
|
|
||||||
|
#include <EncButton.h>
|
||||||
|
EncButton<EB_CALLBACK, 2, 3, 4> enc; // энкодер с кнопкой <A, B, KEY>
|
||||||
|
//EncButton<EB_CALLBACK, 2, 3> enc; // просто энкодер <A, B>
|
||||||
|
//EncButton<EB_CALLBACK, 4> enc; // просто кнопка <KEY>
|
||||||
|
|
||||||
|
// по умолчанию пины настроены в INPUT_PULLUP
|
||||||
|
// Если используется внешняя подтяжка - лучше перевести в INPUT
|
||||||
|
//EncButton<EB_CALLBACK, 2, 3, 4> enc(INPUT);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
enc.counter = 100; // изменение счётчика
|
||||||
|
//enc.setHoldTimeout(500); // установка таймаута удержания кнопки
|
||||||
|
|
||||||
|
enc.attach(TURN_HANDLER, myTurn);
|
||||||
|
enc.attach(RIGHT_HANDLER, myRight);
|
||||||
|
enc.attach(CLICK_HANDLER, myClick);
|
||||||
|
enc.attach(HOLDED_HANDLER, myHolded);
|
||||||
|
enc.attach(STEP_HANDLER, myStep);
|
||||||
|
enc.attach(CLICKS_HANDLER, myClicks);
|
||||||
|
enc.attachClicks(5, fiveClicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void myTurn() {
|
||||||
|
Serial.print("turn ");
|
||||||
|
Serial.println(enc.counter); // вывод счётчика
|
||||||
|
|
||||||
|
// также можно опросить здесь (isRight, isLeft, isRightH, isLeftH)
|
||||||
|
if (enc.isLeft()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast left");
|
||||||
|
else Serial.println("left");
|
||||||
|
}
|
||||||
|
if (enc.isLeftH()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast left hold");
|
||||||
|
else Serial.println("left");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void myRight() {
|
||||||
|
if (enc.isFast()) Serial.println("fast right");
|
||||||
|
else Serial.println("right");
|
||||||
|
}
|
||||||
|
|
||||||
|
void myClick() {
|
||||||
|
Serial.println("click");
|
||||||
|
}
|
||||||
|
void myHolded() {
|
||||||
|
Serial.println("holded");
|
||||||
|
}
|
||||||
|
void myStep() {
|
||||||
|
Serial.println("step");
|
||||||
|
}
|
||||||
|
void myClicks() {
|
||||||
|
Serial.println(enc.clicks);
|
||||||
|
}
|
||||||
|
void fiveClicks() {
|
||||||
|
Serial.println("kek");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
enc.tick(); // обработка всё равно здесь
|
||||||
|
}
|
||||||
49
libraries/EncButton/examples/isr/isr.ino
Normal file
49
libraries/EncButton/examples/isr/isr.ino
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Пример с прямой работой библиотеки на прерываниях
|
||||||
|
|
||||||
|
// Опциональные дефайн-настройки (показаны по умолчанию)
|
||||||
|
//#define EB_FAST 30 // таймаут быстрого поворота, мс
|
||||||
|
//#define EB_DEB 80 // дебаунс кнопки, мс
|
||||||
|
//#define EB_HOLD 1000 // таймаут удержания кнопки, мс
|
||||||
|
//#define EB_STEP 500 // период срабатывания степ, мс
|
||||||
|
//#define EB_CLICK 400 // таймаут накликивания, мс
|
||||||
|
|
||||||
|
// подключение - только PULL-UP, внешний или внутренний!
|
||||||
|
// для изменения направления энкодера поменяй A и B при инициализации
|
||||||
|
|
||||||
|
#include <EncButton.h>
|
||||||
|
EncButton<EB_TICK, 2, 3, 4> enc; // энкодер с кнопкой <A, B, KEY>
|
||||||
|
//EncButton<EB_TICK, 2, 3> enc; // просто энкодер <A, B>
|
||||||
|
//EncButton<EB_TICK, 4> enc; // просто кнопка <KEY>
|
||||||
|
|
||||||
|
// по умолчанию пины настроены в INPUT_PULLUP
|
||||||
|
// Если используется внешняя подтяжка - лучше перевести в INPUT
|
||||||
|
//EncButton<EB_TICK, 2, 3, 4> enc(INPUT);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// желательно подключить оба пина энкодера на внешние прерывания по CHANGE
|
||||||
|
// можно использовать PCINT https://github.com/NicoHood/PinChangeInterrupt
|
||||||
|
attachInterrupt(0, isr, CHANGE); // D2
|
||||||
|
attachInterrupt(1, isr, CHANGE); // D3
|
||||||
|
// подключил оба прерывания на одну функцию
|
||||||
|
}
|
||||||
|
|
||||||
|
// в прерывании вызываем тик
|
||||||
|
void isr() {
|
||||||
|
enc.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// тут тоже вызываем тик, нужен для
|
||||||
|
// корректной работы дебаунсов и прочих таймеров!!!
|
||||||
|
enc.tick();
|
||||||
|
|
||||||
|
if (enc.isTurn()) { // любой поворот
|
||||||
|
Serial.print("turn ");
|
||||||
|
Serial.println(enc.counter); // вывод счётчика
|
||||||
|
}
|
||||||
|
|
||||||
|
// имитация загруженной программы, обработка происходит в прерывании
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
// пример с прерываниями pinChangeInterrupt (прерывания на любом пине)
|
// пример с прерываниями pinChangeInterrupt (прерывания на любом пине)
|
||||||
// только для ATmega328 (UNO, Nano, Pro Mini)
|
// только для ATmega328 (UNO, Nano, Pro Mini)
|
||||||
|
|
||||||
#define SW 0
|
#define CLK 4
|
||||||
#define DT 2
|
#define DT 5
|
||||||
#define CLK 3
|
#define SW 6
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
#include <EncButton.h>
|
||||||
Encoder enc1(CLK, DT, SW);
|
EncButton<EB_TICK, CLK, DT, SW> enc;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
@ -17,13 +17,23 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
enc1.tick(); // оставляем тут для работы "временных" функций и антидребезга
|
// оставляем тут для работы "временных" функций и антидребезга
|
||||||
|
enc.tick();
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
if (enc.isTurn()) { // любой поворот
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
Serial.print("turn ");
|
||||||
|
Serial.println(enc.counter); // вывод счётчика
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isLeft()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast left");
|
||||||
|
else Serial.println("left");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isRight()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast right");
|
||||||
|
else Serial.println("right");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// функция для настройки PCINT для ATmega328 (UNO, Nano, Pro Mini)
|
// функция для настройки PCINT для ATmega328 (UNO, Nano, Pro Mini)
|
||||||
@ -46,16 +56,15 @@ uint8_t attachPCINT(uint8_t pin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Векторы PCINT, нужно кинуть сюда тики
|
// Векторы PCINT, нужно кинуть сюда тики
|
||||||
// не обязательно в каждый вектор, достаточно в тот, который задействован
|
|
||||||
// пины 0-7: PCINT2
|
// пины 0-7: PCINT2
|
||||||
// пины 8-13: PCINT0
|
// пины 8-13: PCINT0
|
||||||
// пины A0-A5: PCINT1
|
// пины A0-A5: PCINT1
|
||||||
ISR(PCINT0_vect) {
|
ISR(PCINT0_vect) {
|
||||||
//enc1.tick();
|
|
||||||
}
|
}
|
||||||
ISR(PCINT1_vect) {
|
ISR(PCINT1_vect) {
|
||||||
//enc1.tick();
|
|
||||||
}
|
}
|
||||||
ISR(PCINT2_vect) {
|
ISR(PCINT2_vect) {
|
||||||
enc1.tick();
|
enc.tick();
|
||||||
}
|
}
|
||||||
63
libraries/EncButton/examples/tickMode/tickMode.ino
Normal file
63
libraries/EncButton/examples/tickMode/tickMode.ino
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Пример с прямой работой библиотеки
|
||||||
|
|
||||||
|
// Опциональные дефайн-настройки (показаны по умолчанию)
|
||||||
|
//#define EB_FAST 30 // таймаут быстрого поворота, мс
|
||||||
|
//#define EB_DEB 80 // дебаунс кнопки, мс
|
||||||
|
//#define EB_HOLD 1000 // таймаут удержания кнопки, мс
|
||||||
|
//#define EB_STEP 500 // период срабатывания степ, мс
|
||||||
|
//#define EB_CLICK 400 // таймаут накликивания, мс
|
||||||
|
|
||||||
|
// подключение - только PULL-UP, внешний или внутренний!
|
||||||
|
// для изменения направления энкодера поменяй A и B при инициализации
|
||||||
|
|
||||||
|
#include <EncButton.h>
|
||||||
|
EncButton<EB_TICK, 2, 3, 4> enc; // энкодер с кнопкой <A, B, KEY>
|
||||||
|
//EncButton<EB_TICK, 2, 3> enc; // просто энкодер <A, B>
|
||||||
|
//EncButton<EB_TICK, 4> enc; // просто кнопка <KEY>
|
||||||
|
|
||||||
|
// по умолчанию пины настроены в INPUT_PULLUP
|
||||||
|
// Если используется внешняя подтяжка - лучше перевести в INPUT
|
||||||
|
//EncButton<EB_TICK, 2, 3, 4> enc(INPUT);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
enc.counter = 100; // изменение счётчика
|
||||||
|
//enc.setHoldTimeout(500); // установка таймаута удержания кнопки
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
enc.tick();
|
||||||
|
|
||||||
|
if (enc.isTurn()) { // любой поворот
|
||||||
|
Serial.print("turn ");
|
||||||
|
Serial.println(enc.counter); // вывод счётчика
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isLeft()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast left");
|
||||||
|
else Serial.println("left");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isRight()) {
|
||||||
|
if (enc.isFast()) Serial.println("fast right");
|
||||||
|
else Serial.println("right");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enc.isLeftH()) Serial.println("leftH");
|
||||||
|
if (enc.isRightH()) Serial.println("rightH");
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isHolded()) Serial.println("holded");
|
||||||
|
if (enc.isStep()) Serial.println("step");
|
||||||
|
|
||||||
|
if (enc.isPress()) Serial.println("press");
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isRelease()) Serial.println("release");
|
||||||
|
|
||||||
|
if (enc.hasClicks(1)) Serial.println("1 click");
|
||||||
|
if (enc.hasClicks(2)) Serial.println("2 click");
|
||||||
|
if (enc.hasClicks(3)) Serial.println("3 click");
|
||||||
|
if (enc.hasClicks(5)) Serial.println("5 click");
|
||||||
|
|
||||||
|
if (enc.hasClicks()) Serial.println(enc.clicks);
|
||||||
|
//if (enc.isHold()) Serial.println("hold");
|
||||||
|
}
|
||||||
35
libraries/EncButton/examples/virtual/virtual.ino
Normal file
35
libraries/EncButton/examples/virtual/virtual.ino
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include <EncButton.h>
|
||||||
|
|
||||||
|
EncButton<EB_TICK, VIRT_BTN> enc; // виртуальная кнопка
|
||||||
|
//EncButton<EB_TICK, VIRT_ENCBTN> enc; // виртуальный энк с кнопкой
|
||||||
|
//EncButton<EB_TICK, VIRT_ENC> enc; // виртуальный энк
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
pinMode(4, INPUT_PULLUP); // подтянем пин
|
||||||
|
//enc.setHoldTimeout(500); // установка таймаута удержания кнопки
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// tick может принимать виртуальный сигнал:
|
||||||
|
// (сигнал кнопки)
|
||||||
|
// (сигнал энкодера А, сигнал энкодера B)
|
||||||
|
// (сигнал энкодера А, сигнал энкодера B, сигнал кнопки)
|
||||||
|
enc.tick(!digitalRead(4));
|
||||||
|
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isHolded()) Serial.println("holded");
|
||||||
|
if (enc.isStep()) Serial.println("step");
|
||||||
|
|
||||||
|
if (enc.isPress()) Serial.println("press");
|
||||||
|
if (enc.isClick()) Serial.println("click");
|
||||||
|
if (enc.isRelease()) Serial.println("release");
|
||||||
|
|
||||||
|
if (enc.hasClicks(1)) Serial.println("1 click");
|
||||||
|
if (enc.hasClicks(2)) Serial.println("2 click");
|
||||||
|
if (enc.hasClicks(3)) Serial.println("3 click");
|
||||||
|
if (enc.hasClicks(5)) Serial.println("5 click");
|
||||||
|
|
||||||
|
if (enc.hasClicks()) Serial.println(enc.clicks);
|
||||||
|
//if (enc.isHold()) Serial.println("hold");
|
||||||
|
}
|
||||||
66
libraries/EncButton/keywords.txt
Normal file
66
libraries/EncButton/keywords.txt
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For EncButton
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
EncButton KEYWORD1
|
||||||
|
|
||||||
|
EB_FAST KEYWORD1
|
||||||
|
EB_DEB KEYWORD1
|
||||||
|
EB_HOLD KEYWORD1
|
||||||
|
EB_STEP KEYWORD1
|
||||||
|
EB_CLICK KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
tick KEYWORD2
|
||||||
|
getState KEYWORD2
|
||||||
|
resetState KEYWORD2
|
||||||
|
isPress KEYWORD2
|
||||||
|
isRelease KEYWORD2
|
||||||
|
isFast KEYWORD2
|
||||||
|
isTurn KEYWORD2
|
||||||
|
isRight KEYWORD2
|
||||||
|
isLeft KEYWORD2
|
||||||
|
isRightH KEYWORD2
|
||||||
|
isLeftH KEYWORD2
|
||||||
|
isClick KEYWORD2
|
||||||
|
isHolded KEYWORD2
|
||||||
|
isHeld KEYWORD2
|
||||||
|
isHold KEYWORD2
|
||||||
|
isStep KEYWORD2
|
||||||
|
counter KEYWORD2
|
||||||
|
state KEYWORD2
|
||||||
|
hasClicks KEYWORD2
|
||||||
|
clicks KEYWORD2
|
||||||
|
attach KEYWORD2
|
||||||
|
detach KEYWORD2
|
||||||
|
attachClicks KEYWORD2
|
||||||
|
detachClicks KEYWORD2
|
||||||
|
pullUp KEYWORD2
|
||||||
|
holdEncButton KEYWORD2
|
||||||
|
setHoldTimeout KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
EB_TICK LITERAL1
|
||||||
|
EB_CALLBACK LITERAL1
|
||||||
|
VIRT_BTN LITERAL1
|
||||||
|
VIRT_ENC LITERAL1
|
||||||
|
VIRT_ENCBTN LITERAL1
|
||||||
|
TURN_HANDLER LITERAL1
|
||||||
|
RIGHT_HANDLER LITERAL1
|
||||||
|
LEFT_HANDLER LITERAL1
|
||||||
|
RIGHT_H_HANDLER LITERAL1
|
||||||
|
LEFT_H_HANDLER LITERAL1
|
||||||
|
CLICK_HANDLER LITERAL1
|
||||||
|
HOLDED_HANDLER LITERAL1
|
||||||
|
STEP_HANDLER LITERAL1
|
||||||
|
HOLD_HANDLER LITERAL1
|
||||||
|
CLICKS_HANDLER LITERAL1
|
||||||
|
PRESS_HANDLER LITERAL1
|
||||||
|
RELEASE_HANDLER LITERAL1
|
||||||
9
libraries/EncButton/library.properties
Normal file
9
libraries/EncButton/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=EncButton
|
||||||
|
version=1.8
|
||||||
|
author=AlexGyver <alex@alexgyver.ru>
|
||||||
|
maintainer=AlexGyver <alex@alexgyver.ru>
|
||||||
|
sentence=Light and fast library for button and encoder control
|
||||||
|
paragraph=Light and fast library for button and encoder control
|
||||||
|
category=Sensors
|
||||||
|
url=https://github.com/GyverLibs/EncButton
|
||||||
|
architectures=*
|
||||||
383
libraries/EncButton/src/EncButton.h
Normal file
383
libraries/EncButton/src/EncButton.h
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
/*
|
||||||
|
Ультра лёгкая и быстрая библиотека для энкодера, энкодера с кнопкой или просто кнопки
|
||||||
|
Документация:
|
||||||
|
GitHub: https://github.com/GyverLibs/EncButton
|
||||||
|
Возможности:
|
||||||
|
- Максимально быстрое чтение пинов для AVR (ATmega328/ATmega168, ATtiny85/ATtiny13)
|
||||||
|
- Оптимизированный вес
|
||||||
|
- Быстрые и лёгкие алгоритмы кнопки и энкодера
|
||||||
|
- Энкодер: поворот, нажатый поворот, быстрый поворот, счётчик
|
||||||
|
- Кнопка: антидребезг, клик, несколько кликов, счётчик кликов, удержание, режим step
|
||||||
|
- Подключение - только HIGH PULL!
|
||||||
|
- Опциональный режим callback (+22б SRAM на каждый экземпляр)
|
||||||
|
|
||||||
|
AlexGyver, alex@alexgyver.ru
|
||||||
|
https://alexgyver.ru/
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Версии:
|
||||||
|
v1.1 - пуллап отдельныи методом
|
||||||
|
v1.2 - можно передать конструктору параметр INPUT_PULLUP / INPUT(умолч)
|
||||||
|
v1.3 - виртуальное зажатие кнопки энкодера вынесено в отдельную функцию + мелкие улучшения
|
||||||
|
v1.4 - обработка нажатия и отпускания кнопки
|
||||||
|
v1.5 - добавлен виртуальный режим
|
||||||
|
v1.6 - оптимизация работы в прерывании
|
||||||
|
v1.6.1 - PULLUP по умолчанию
|
||||||
|
v1.7 - большая оптимизация памяти, переделан FastIO
|
||||||
|
v1.8 - индивидуальная настройка таймаута удержания кнопки (была общая на всех)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EncButton_h
|
||||||
|
#define EncButton_h
|
||||||
|
|
||||||
|
// =========== НАСТРОЙКИ (можно передефайнить из скетча) ============
|
||||||
|
#define _EB_FAST 30 // таймаут быстрого поворота
|
||||||
|
#define _EB_DEB 80 // дебаунс кнопки
|
||||||
|
#define _EB_HOLD 1000 // таймаут удержания кнопки
|
||||||
|
#define _EB_STEP 500 // период срабатывания степ
|
||||||
|
#define _EB_CLICK 400 // таймаут накликивания
|
||||||
|
|
||||||
|
// =========== НЕ ТРОГАЙ ============
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "FastIO_v2.h"
|
||||||
|
// флаг макро
|
||||||
|
#define _setFlag(x) (flags |= 1 << x)
|
||||||
|
#define _clrFlag(x) (flags &= ~(1 << x))
|
||||||
|
#define _readFlag(x) ((flags >> x) & 1)
|
||||||
|
|
||||||
|
#ifndef EB_FAST
|
||||||
|
#define EB_FAST _EB_FAST
|
||||||
|
#endif
|
||||||
|
#ifndef EB_DEB
|
||||||
|
#define EB_DEB _EB_DEB
|
||||||
|
#endif
|
||||||
|
#ifndef EB_HOLD
|
||||||
|
#define EB_HOLD _EB_HOLD
|
||||||
|
#endif
|
||||||
|
#ifndef EB_STEP
|
||||||
|
#define EB_STEP _EB_STEP
|
||||||
|
#endif
|
||||||
|
#ifndef EB_CLICK
|
||||||
|
#define EB_CLICK _EB_CLICK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum eb_callback {
|
||||||
|
TURN_HANDLER,
|
||||||
|
RIGHT_HANDLER,
|
||||||
|
LEFT_HANDLER,
|
||||||
|
RIGHT_H_HANDLER,
|
||||||
|
LEFT_H_HANDLER,
|
||||||
|
CLICK_HANDLER,
|
||||||
|
HOLDED_HANDLER,
|
||||||
|
STEP_HANDLER,
|
||||||
|
HOLD_HANDLER,
|
||||||
|
CLICKS_HANDLER,
|
||||||
|
PRESS_HANDLER,
|
||||||
|
RELEASE_HANDLER,
|
||||||
|
};
|
||||||
|
|
||||||
|
// константы
|
||||||
|
#define EB_TICK 0
|
||||||
|
#define EB_CALLBACK 1
|
||||||
|
|
||||||
|
#define EB_NO_PIN 255
|
||||||
|
|
||||||
|
#define VIRT_ENC 254
|
||||||
|
#define VIRT_ENCBTN 253
|
||||||
|
#define VIRT_BTN 252
|
||||||
|
|
||||||
|
// класс
|
||||||
|
template < uint8_t _EB_MODE, uint8_t _S1 = EB_NO_PIN, uint8_t _S2 = EB_NO_PIN, uint8_t _KEY = EB_NO_PIN >
|
||||||
|
class EncButton {
|
||||||
|
public:
|
||||||
|
// можно указать режим работы пина
|
||||||
|
EncButton(const uint8_t mode = INPUT_PULLUP) {
|
||||||
|
if (_S1 < 252 && mode == INPUT_PULLUP) pullUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// подтянуть пины внутренней подтяжкой
|
||||||
|
void pullUp() {
|
||||||
|
if (_S1 < 252) { // реальное устройство
|
||||||
|
if (_S2 == EB_NO_PIN) { // обычная кнопка
|
||||||
|
pinMode(_S1, INPUT_PULLUP);
|
||||||
|
} else if (_KEY == EB_NO_PIN) { // энк без кнопки
|
||||||
|
pinMode(_S1, INPUT_PULLUP);
|
||||||
|
pinMode(_S2, INPUT_PULLUP);
|
||||||
|
} else { // энк с кнопкой
|
||||||
|
pinMode(_S1, INPUT_PULLUP);
|
||||||
|
pinMode(_S2, INPUT_PULLUP);
|
||||||
|
pinMode(_KEY, INPUT_PULLUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// установить таймаут удержания кнопки для isHold(), мс (до 30 000)
|
||||||
|
void setHoldTimeout(int tout) {
|
||||||
|
_holdT = tout >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// виртуально зажать кнопку энкодера
|
||||||
|
void holdEncButton(bool state) {
|
||||||
|
if (state) _setFlag(7);
|
||||||
|
else _clrFlag(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// тикер, вызывать как можно чаще или в прерывании
|
||||||
|
// вернёт отличное от нуля значение, если произошло какое то событие
|
||||||
|
uint8_t tick(uint8_t s1 = 0, uint8_t s2 = 0, uint8_t key = 0) {
|
||||||
|
if (!_isrFlag) {
|
||||||
|
_isrFlag = 1;
|
||||||
|
|
||||||
|
// обработка энка (компилятор вырежет блок если не используется)
|
||||||
|
// если объявлены два пина или выбран вирт. энкодер или энкодер с кнопкой
|
||||||
|
if ((_S1 < 252 && _S2 < 252) || _S1 == VIRT_ENC || _S1 == VIRT_ENCBTN) {
|
||||||
|
uint8_t state;
|
||||||
|
if (_S1 >= 252) state = s1 | (s2 << 1); // получаем код
|
||||||
|
else state = F_fastRead(_S1) | (F_fastRead(_S2) << 1); // получаем код
|
||||||
|
poolEnc(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// обработка кнопки (компилятор вырежет блок если не используется)
|
||||||
|
// если S2 не указан (кнопка) или указан KEY или выбран вирт. энкодер с кнопкой или кнопка
|
||||||
|
if ((_S1 < 252 && _S2 == EB_NO_PIN) || _KEY != EB_NO_PIN || _S1 == VIRT_BTN || _S1 == VIRT_ENCBTN) {
|
||||||
|
if (_S1 < 252 && _S2 == EB_NO_PIN) _btnState = !F_fastRead(_S1); // обычная кнопка
|
||||||
|
if (_KEY != EB_NO_PIN) _btnState = !F_fastRead(_KEY); // энк с кнопкой
|
||||||
|
if (_S1 == VIRT_BTN) _btnState = s1; // вирт кнопка
|
||||||
|
if (_S1 == VIRT_ENCBTN) _btnState = key; // вирт энк с кнопкой
|
||||||
|
poolBtn();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_EB_MODE) {
|
||||||
|
if (*_callback[0] && isTurn()) _callback[0]();
|
||||||
|
switch (EBState) {
|
||||||
|
case 1: if (*_callback[1]) _callback[1](); break; // isRight
|
||||||
|
case 2: if (*_callback[2]) _callback[2](); break; // isLeft
|
||||||
|
case 3: if (*_callback[3]) _callback[3](); break; // isRightH
|
||||||
|
case 4: if (*_callback[4]) _callback[4](); break; // isLeftH
|
||||||
|
case 5: if (*_callback[5]) _callback[5](); break; // isClick
|
||||||
|
case 6: if (*_callback[6]) _callback[6](); break; // isHolded
|
||||||
|
case 7: if (*_callback[7]) _callback[7](); break; // isStep
|
||||||
|
case 8: if (*_callback[11]) _callback[11](); break; // isPress
|
||||||
|
case 9: if (*_callback[12]) _callback[12](); break; // isRelease
|
||||||
|
}
|
||||||
|
EBState = 0;
|
||||||
|
if (*_callback[8] && _readFlag(4)) _callback[8](); // isHold
|
||||||
|
if (_readFlag(6)) {
|
||||||
|
if (*_callback[9]) _callback[9](); // clicks
|
||||||
|
if (*_callback[10] && clicks == _amount) _callback[10]();
|
||||||
|
_clrFlag(6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isrFlag = 0;
|
||||||
|
return EBState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// подключить обработчик
|
||||||
|
void attach(eb_callback type, void (*handler)()) {
|
||||||
|
_callback[type] = *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// отключить обработчик
|
||||||
|
void detach(eb_callback type) {
|
||||||
|
_callback[type] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// подключить обработчик на количество кликов (может быть только один!)
|
||||||
|
void attachClicks(uint8_t amount, void (*handler)()) {
|
||||||
|
_amount = amount;
|
||||||
|
_callback[10] = *handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// отключить обработчик на количество кликов
|
||||||
|
void detachClicks() {
|
||||||
|
_callback[10] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// получить статус
|
||||||
|
uint8_t getState() { return EBState; }
|
||||||
|
|
||||||
|
// сбросить статус
|
||||||
|
void resetState() { EBState = 0; }
|
||||||
|
|
||||||
|
// поворот вправо
|
||||||
|
bool isRight() { return _EB_MODE ? (_dir == 1 ? 1 : 0) : checkState(1); }
|
||||||
|
|
||||||
|
// поворот влево
|
||||||
|
bool isLeft() { return _EB_MODE ? (_dir == 2 ? 1 : 0) : checkState(2); }
|
||||||
|
|
||||||
|
// поворот вправо нажатый
|
||||||
|
bool isRightH() { return _EB_MODE ? (_dir == 3 ? 1 : 0) : checkState(3); }
|
||||||
|
|
||||||
|
// поворот влево нажатый
|
||||||
|
bool isLeftH() { return _EB_MODE ? (_dir == 4 ? 1 : 0) : checkState(4); }
|
||||||
|
|
||||||
|
// быстрый поворот
|
||||||
|
bool isFast() { return _readFlag(1); }
|
||||||
|
|
||||||
|
// энкодер повёрнут
|
||||||
|
bool isTurn() {
|
||||||
|
if (_readFlag(0)) {
|
||||||
|
_clrFlag(0);
|
||||||
|
return true;
|
||||||
|
} return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// кнопка нажата
|
||||||
|
bool isPress() { return checkState(8); }
|
||||||
|
|
||||||
|
// кнопка отпущена
|
||||||
|
bool isRelease() { return checkState(9); }
|
||||||
|
|
||||||
|
// клик по кнопке
|
||||||
|
bool isClick() { return checkState(5); }
|
||||||
|
|
||||||
|
// кнопка удержана
|
||||||
|
bool isHolded() { return checkState(6); }
|
||||||
|
|
||||||
|
// кнопка удержана (грамотный аналог holded =)
|
||||||
|
bool isHeld() { return checkState(6); }
|
||||||
|
|
||||||
|
// кнопка удерживается
|
||||||
|
bool isHold() { return _readFlag(4); }
|
||||||
|
|
||||||
|
// режим импульсного удержания
|
||||||
|
bool isStep() { return checkState(7); }
|
||||||
|
|
||||||
|
// статус кнопки
|
||||||
|
bool state() { return !F_fastRead(_S1); }
|
||||||
|
|
||||||
|
// имеются клики
|
||||||
|
bool hasClicks(uint8_t numClicks) {
|
||||||
|
if (clicks == numClicks && _readFlag(6)) {
|
||||||
|
_clrFlag(6);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// имеются клики
|
||||||
|
uint8_t hasClicks() {
|
||||||
|
if (_readFlag(6)) {
|
||||||
|
_clrFlag(6);
|
||||||
|
return clicks;
|
||||||
|
} return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// счётчик энкодера
|
||||||
|
int counter = 0;
|
||||||
|
|
||||||
|
// счётчик кликов
|
||||||
|
uint8_t clicks = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void poolEnc(uint8_t state) {
|
||||||
|
if (_encRST && state == 0b11) { // ресет и энк защёлкнул позицию
|
||||||
|
if (_S2 == EB_NO_PIN || _KEY != EB_NO_PIN) { // энкодер с кнопкой
|
||||||
|
if (!_readFlag(4)) { // если кнопка не "удерживается"
|
||||||
|
if (_lastState == 0b10) EBState = (_btnState || _readFlag(7)) ? 3 : 1, counter++;
|
||||||
|
else if (_lastState == 0b01) EBState = (_btnState || _readFlag(7)) ? 4 : 2, counter--;
|
||||||
|
}
|
||||||
|
} else { // просто энкодер
|
||||||
|
if (_lastState == 0b10) EBState = 1, counter++;
|
||||||
|
else if (_lastState == 0b01) EBState = 2, counter--;
|
||||||
|
}
|
||||||
|
if (EBState > 0) {
|
||||||
|
if (_EB_MODE) _dir = EBState;
|
||||||
|
if (millis() - _debTimer < EB_FAST) _setFlag(1); // быстрый поворот
|
||||||
|
else _clrFlag(1); // обычный поворот
|
||||||
|
if (EBState < 5) _setFlag(0); // флаг поворота для юзера
|
||||||
|
}
|
||||||
|
|
||||||
|
_encRST = 0;
|
||||||
|
_debTimer = millis();
|
||||||
|
}
|
||||||
|
if (state == 0b00) _encRST = 1;
|
||||||
|
_lastState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void poolBtn() {
|
||||||
|
uint32_t thisMls = millis();
|
||||||
|
uint32_t debounce = thisMls - _debTimer;
|
||||||
|
if (_btnState) { // кнопка нажата
|
||||||
|
if (!_readFlag(3)) { // и не была нажата ранее
|
||||||
|
if (debounce > EB_DEB) { // и прошел дебаунс
|
||||||
|
_setFlag(3); // флаг кнопка была нажата
|
||||||
|
_debTimer = thisMls; // сброс таймаутов
|
||||||
|
EBState = 8; // кнопка нажата
|
||||||
|
}
|
||||||
|
if (debounce > EB_CLICK) { // кнопка нажата после EB_CLICK
|
||||||
|
clicks = 0; // сбросить счётчик и флаг кликов
|
||||||
|
flags &= ~0b01100000;
|
||||||
|
}
|
||||||
|
} else { // кнопка уже была нажата
|
||||||
|
if (!_readFlag(4)) { // и удержание ещё не зафиксировано
|
||||||
|
if (debounce < (_holdT << 7)) { // прошло меньше удержания
|
||||||
|
if (EBState != 0 && EBState != 8) _setFlag(2); // но энкодер повёрнут! Запомнили
|
||||||
|
} else { // прошло больше времени удержания
|
||||||
|
if (!_readFlag(2)) { // и энкодер не повёрнут
|
||||||
|
EBState = 6; // значит это удержание (сигнал)
|
||||||
|
_setFlag(4); // запомнили что удерживается
|
||||||
|
_debTimer = thisMls; // сброс таймаута
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // удержание зафиксировано
|
||||||
|
if (debounce > EB_STEP) { // таймер степа
|
||||||
|
EBState = 7; // сигналим
|
||||||
|
_debTimer = thisMls; // сброс таймаута
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // кнопка не нажата
|
||||||
|
if (_readFlag(3)) { // но была нажата
|
||||||
|
if (debounce > EB_DEB && !_readFlag(4) && !_readFlag(2)) { // энкодер не трогали и не удерживали - это клик
|
||||||
|
EBState = 5;
|
||||||
|
clicks++;
|
||||||
|
} else EBState = 9; // кнопка отпущена
|
||||||
|
flags &= ~0b00011100; // clear 2 3 4
|
||||||
|
_debTimer = thisMls; // сброс таймаута
|
||||||
|
} else if (clicks > 0 && debounce > EB_CLICK && !_readFlag(5)) flags |= 0b01100000; // флаг на клики
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkState(uint8_t val) {
|
||||||
|
if (EBState == val) {
|
||||||
|
EBState = 0;
|
||||||
|
return 1;
|
||||||
|
} return 0;
|
||||||
|
}
|
||||||
|
uint32_t _debTimer = 0;
|
||||||
|
uint8_t _lastState = 0, EBState = 0;
|
||||||
|
bool _btnState = 0, _encRST = 0, _isrFlag = 0;
|
||||||
|
uint8_t flags = 0;
|
||||||
|
uint8_t _holdT = EB_HOLD >> 7;
|
||||||
|
|
||||||
|
uint8_t _dir = 0;
|
||||||
|
void (*_callback[_EB_MODE ? 13 : 0])() = {};
|
||||||
|
uint8_t _amount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// flags
|
||||||
|
// 0 - enc turn
|
||||||
|
// 1 - enc fast
|
||||||
|
// 2 - enc был поворот
|
||||||
|
// 3 - флаг кнопки
|
||||||
|
// 4 - hold
|
||||||
|
// 5 - clicks flag
|
||||||
|
// 6 - clicks get
|
||||||
|
// 7 - enc button hold
|
||||||
|
|
||||||
|
// EBState
|
||||||
|
// 0 - idle
|
||||||
|
// 1 - right
|
||||||
|
// 2 - left
|
||||||
|
// 3 - rightH
|
||||||
|
// 4 - leftH
|
||||||
|
// 5 - click
|
||||||
|
// 6 - holded
|
||||||
|
// 7 - step
|
||||||
|
// 8 - press
|
||||||
|
// 9 - release
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
93
libraries/EncButton/src/FastIO_v2.cpp
Normal file
93
libraries/EncButton/src/FastIO_v2.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "FastIO_v2.h"
|
||||||
|
|
||||||
|
bool F_fastRead(const uint8_t pin) {
|
||||||
|
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
|
||||||
|
if (pin < 8) return bitRead(PIND, pin);
|
||||||
|
else if (pin < 14) return bitRead(PINB, pin - 8);
|
||||||
|
else if (pin < 20) return bitRead(PINC, pin - 14);
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__)
|
||||||
|
return bitRead(PINB, pin);
|
||||||
|
|
||||||
|
#elif defined(AVR)
|
||||||
|
uint8_t *_pin_reg = portInputRegister(digitalPinToPort(pin));
|
||||||
|
uint8_t _bit_mask = digitalPinToBitMask(pin);
|
||||||
|
return bool(*_pin_reg & _bit_mask);
|
||||||
|
|
||||||
|
#else
|
||||||
|
return digitalRead(pin);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void F_fastWrite(const uint8_t pin, bool val) {
|
||||||
|
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
|
||||||
|
if (pin < 8) bitWrite(PORTD, pin, val);
|
||||||
|
else if (pin < 14) bitWrite(PORTB, (pin - 8), val);
|
||||||
|
else if (pin < 20) bitWrite(PORTC, (pin - 14), val);
|
||||||
|
|
||||||
|
#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__)
|
||||||
|
bitWrite(PORTB, pin, val);
|
||||||
|
|
||||||
|
#elif defined(AVR)
|
||||||
|
uint8_t *_port_reg = portInputRegister(digitalPinToPort(pin));
|
||||||
|
uint8_t _bit_mask = digitalPinToBitMask(pin);
|
||||||
|
_port_reg = portOutputRegister(digitalPinToPort(pin));
|
||||||
|
_bit_mask = digitalPinToBitMask(pin);
|
||||||
|
if (val) *_port_reg |= _bit_mask; // HIGH
|
||||||
|
else *_port_reg &= ~_bit_mask; // LOW
|
||||||
|
|
||||||
|
#else
|
||||||
|
digitalWrite(pin, val);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t F_fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
|
||||||
|
#if defined(AVR)
|
||||||
|
volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
|
||||||
|
volatile uint8_t *_dat_port = portInputRegister(digitalPinToPort(dataPin));
|
||||||
|
uint8_t _clk_mask = digitalPinToBitMask(clockPin);
|
||||||
|
uint8_t _dat_mask = digitalPinToBitMask(dataPin);
|
||||||
|
uint8_t data = 0;
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
*_clk_port |= _clk_mask;
|
||||||
|
if (bitOrder == MSBFIRST) {
|
||||||
|
data <<= 1;
|
||||||
|
if (bool(*_dat_port & _dat_mask)) data |= 1;
|
||||||
|
} else {
|
||||||
|
data >>= 1;
|
||||||
|
if (bool(*_dat_port & _dat_mask)) data |= 1 << 7;
|
||||||
|
}
|
||||||
|
*_clk_port &= ~_clk_mask;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
#else
|
||||||
|
return shiftIn(dataPin, clockPin, bitOrder);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void F_fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data) {
|
||||||
|
#if defined(AVR)
|
||||||
|
volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
|
||||||
|
volatile uint8_t *_dat_port = portOutputRegister(digitalPinToPort(dataPin));
|
||||||
|
uint8_t _clk_mask = digitalPinToBitMask(clockPin);
|
||||||
|
uint8_t _dat_mask = digitalPinToBitMask(dataPin);
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
if (bitOrder == MSBFIRST) {
|
||||||
|
if (data & (1 << 7)) *_dat_port |= _dat_mask;
|
||||||
|
else *_dat_port &= ~_dat_mask;
|
||||||
|
data <<= 1;
|
||||||
|
} else {
|
||||||
|
if (data & 1) *_dat_port |= _dat_mask;
|
||||||
|
else *_dat_port &= ~_dat_mask;
|
||||||
|
data >>= 1;
|
||||||
|
}
|
||||||
|
*_clk_port |= _clk_mask;
|
||||||
|
*_clk_port &= ~_clk_mask;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
shiftOut(dataPin, clockPin, bitOrder, data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
13
libraries/EncButton/src/FastIO_v2.h
Normal file
13
libraries/EncButton/src/FastIO_v2.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Быстрый IO для AVR (для остальных будет digitalxxxxx)
|
||||||
|
// v1.0
|
||||||
|
|
||||||
|
#ifndef _FastIO_v2_h
|
||||||
|
#define _FastIO_v2_h
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
bool F_fastRead(const uint8_t pin); // быстрое чтение пина
|
||||||
|
void F_fastWrite(const uint8_t pin, bool val); // быстрая запись
|
||||||
|
uint8_t F_fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); // быстрый shiftIn
|
||||||
|
void F_fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data); // быстрый shiftOut
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,149 +0,0 @@
|
|||||||

|
|
||||||

|
|
||||||
# GyverEncoder
|
|
||||||
Библиотека для расширенной работы с энкодером
|
|
||||||
**ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ [EncButton](https://github.com/GyverLibs/EncButton)**
|
|
||||||
- Отработка поворота энкодера
|
|
||||||
- Отработка "нажатого поворота"
|
|
||||||
- Отработка "быстрого поворота"
|
|
||||||
- Несколько алгоритмов опроса энкодера
|
|
||||||
- Выбор подтяжки подключения энкодера
|
|
||||||
- Работа с двумя типами экнодеров
|
|
||||||
- Работа с внешним энкодером (через расширитель пинов и т.п.)
|
|
||||||
- Отработка нажатия/удержания кнопки с антидребезгом
|
|
||||||
|
|
||||||
### Совместимость
|
|
||||||
Совместима со всеми Arduino платформами (используются Arduino-функции)
|
|
||||||
|
|
||||||
### Документация
|
|
||||||
К библиотеке есть [расширенная документация](https://alexgyver.ru/encoder/)
|
|
||||||
|
|
||||||
## Содержание
|
|
||||||
- [Установка](#install)
|
|
||||||
- [Инициализация](#init)
|
|
||||||
- [Использование](#usage)
|
|
||||||
- [Пример](#example)
|
|
||||||
- [Версии](#versions)
|
|
||||||
- [Баги и обратная связь](#feedback)
|
|
||||||
|
|
||||||
<a id="install"></a>
|
|
||||||
## Установка
|
|
||||||
- Библиотеку можно найти по названию **GyverEncoder** и установить через менеджер библиотек в:
|
|
||||||
- Arduino IDE
|
|
||||||
- Arduino IDE v2
|
|
||||||
- PlatformIO
|
|
||||||
- [Скачать библиотеку](https://github.com/GyverLibs/GyverEncoder/archive/refs/heads/main.zip) .zip архивом для ручной установки:
|
|
||||||
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
|
|
||||||
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
|
|
||||||
- Распаковать и положить в *Документы/Arduino/libraries/*
|
|
||||||
- (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
|
|
||||||
- Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
|
|
||||||
|
|
||||||
<a id="init"></a>
|
|
||||||
## Инициализация
|
|
||||||
```cpp
|
|
||||||
Encoder enc; // не привязан к пину
|
|
||||||
Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
|
||||||
Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
|
||||||
Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
|
||||||
Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
|
||||||
```
|
|
||||||
|
|
||||||
<a id="usage"></a>
|
|
||||||
## Использование
|
|
||||||
```cpp
|
|
||||||
void tick(); // опрос энкодера, нужно вызывать постоянно или в прерывании
|
|
||||||
void setType(boolean type); // TYPE1 / TYPE2 - тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
|
||||||
void setTickMode(boolean tickMode); // MANUAL / AUTO - ручной или автоматический опрос энкодера функцией tick(). (по умолчанию ручной)
|
|
||||||
void setDirection(boolean direction); // NORM / REVERSE - направление вращения энкодера
|
|
||||||
void setFastTimeout(int timeout); // установка таймаута быстрого поворота
|
|
||||||
void setPinMode(bool mode); // тип подключения энкодера, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
|
||||||
void setBtnPinMode(bool mode); // тип подключения кнопки, подтяжка HIGH_PULL (внутренняя) или LOW_PULL (внешняя на GND)
|
|
||||||
|
|
||||||
boolean isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
|
|
||||||
boolean isRight(); // возвращает true при повороте направо, сама сбрасывается в false
|
|
||||||
boolean isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
|
|
||||||
boolean isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
|
|
||||||
boolean isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
|
|
||||||
boolean isFastR(); // возвращает true при быстром повороте
|
|
||||||
boolean isFastL(); // возвращает true при быстром повороте
|
|
||||||
|
|
||||||
boolean isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
|
|
||||||
boolean isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
|
|
||||||
boolean isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
|
|
||||||
boolean isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
|
|
||||||
boolean isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
|
|
||||||
boolean isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
|
|
||||||
boolean isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
|
|
||||||
void resetStates(); // сбрасывает все is-флаги
|
|
||||||
```
|
|
||||||
|
|
||||||
<a id="example"></a>
|
|
||||||
## Пример
|
|
||||||
Остальные примеры смотри в **examples**!
|
|
||||||
```cpp
|
|
||||||
#define CLK 2
|
|
||||||
#define DT 3
|
|
||||||
#define SW 4
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
// ваш код
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
|
|
||||||
//if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
|
||||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
|
||||||
|
|
||||||
if (enc1.isClick()) Serial.println("Click"); // одиночный клик
|
|
||||||
if (enc1.isSingle()) Serial.println("Single"); // одиночный клик (с таймаутом для двойного)
|
|
||||||
if (enc1.isDouble()) Serial.println("Double"); // двойной клик
|
|
||||||
|
|
||||||
|
|
||||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
|
||||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<a id="versions"></a>
|
|
||||||
## Версии
|
|
||||||
- v3.6 от 16.09.2019 - Возвращены дефайны настроек
|
|
||||||
- v4.0 от 13.11.2019
|
|
||||||
- Оптимизирован код
|
|
||||||
- Исправлены баги
|
|
||||||
- Добавлены другие алгоритмы опроса
|
|
||||||
- Добавлена возможность полностью убрать кнопку (экономия памяти)
|
|
||||||
- Добавлена возможность подключения внешнего энкодера
|
|
||||||
- Добавлена настройка подтяжки пинов
|
|
||||||
- v4.1: Исправлено изменение подтяжек
|
|
||||||
- v4.2
|
|
||||||
- Добавлена поддержка TYPE1 для алгоритма PRECISE_ALGORITHM
|
|
||||||
- Добавлена отработка двойного клика: isSingle / isDouble
|
|
||||||
- v4.3: Исправлено ложное isSingle
|
|
||||||
- v4.4: Добавлен метод resetStates, сбрасывает все is-флаги и счётчики
|
|
||||||
- v4.5: Улучшен алгоритм BINARY_ALGORITHM (спасибо Ярославу Курусу)
|
|
||||||
- v4.6: BINARY_ALGORITHM пофикшен для TYPE1, добавлена isReleaseHold
|
|
||||||
- v4.7: Исправлен случайный нажатый поворот в BINARY_ALGORITHM
|
|
||||||
- v4.8: увеличена производительность для AVR Arduino
|
|
||||||
- v4.9: быстрый поворот отключен если кнопка удерживается
|
|
||||||
|
|
||||||
<a id="feedback"></a>
|
|
||||||
## Баги и обратная связь
|
|
||||||
При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
|
|
||||||
Библиотека открыта для доработки и ваших **Pull Request**'ов!
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
В последнее время китайцы стали делать одинаковые модули (ку 40)
|
|
||||||
с разными типами энкодеров - полный период и полпериода.
|
|
||||||
Если ваш энкодер ведёт себя странно (один тик считает за два поворота),
|
|
||||||
то смените тип энкодера
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CLK 4
|
|
||||||
#define DT 3
|
|
||||||
#define SW 2
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(CLK, DT, SW);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#define CLK 6
|
|
||||||
#define DT 5
|
|
||||||
#define SW 4
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(CLK, DT, SW);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setTickMode(AUTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// enc1.tick(); // не нужна, в этом режиме (AUTO) она входит в каждую функцию!
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
// ваш код
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
|
|
||||||
if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
|
||||||
if (enc1.isRelease()) Serial.println("Release"); // отпускание кнопки (+ дебаунс)
|
|
||||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
|
||||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
#define CLK 2
|
|
||||||
#define DT 3
|
|
||||||
#define SW 4
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
//Encoder enc1(CLK, DT); // для работы без кнопки
|
|
||||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
|
||||||
//Encoder enc1(CLK, DT, SW, TYPE2); // для работы c кнопкой и сразу выбираем тип
|
|
||||||
//Encoder enc1(CLK, DT, ENC_NO_BUTTON, TYPE2); // для работы без кнопки и сразу выбираем тип
|
|
||||||
|
|
||||||
// Варианты инициализации:
|
|
||||||
// Encoder enc; // не привязан к пину
|
|
||||||
// Encoder enc(пин CLK, пин DT); // энкодер без кнопки (ускоренный опрос)
|
|
||||||
// Encoder enc(пин CLK, пин DT, пин SW); // энкодер с кнопкой
|
|
||||||
// Encoder enc(пин CLK, пин DT, пин SW, тип); // энкодер с кнопкой и указанием типа
|
|
||||||
// Encoder enc(пин CLK, пин DT, ENC_NO_BUTTON, тип); // энкодер без кнопкой и с указанием типа
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
// ваш код
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
|
|
||||||
//if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
|
||||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
|
||||||
|
|
||||||
if (enc1.isClick()) Serial.println("Click"); // одиночный клик
|
|
||||||
if (enc1.isSingle()) Serial.println("Single"); // одиночный клик (с таймаутом для двойного)
|
|
||||||
if (enc1.isDouble()) Serial.println("Double"); // двойной клик
|
|
||||||
|
|
||||||
|
|
||||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
|
||||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
#define CLK 2
|
|
||||||
#define DT 3
|
|
||||||
#define SW 4
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(CLK, DT, SW);
|
|
||||||
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE1); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип\=
|
|
||||||
enc1.setFastTimeout(40); // таймаут на скорость isFastR. По умолч. 50
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
|
|
||||||
if (enc1.isRight()) value++; // если был поворот направо, увеличиваем на 1
|
|
||||||
if (enc1.isLeft()) value--; // если был поворот налево, уменьшаем на 1
|
|
||||||
|
|
||||||
if (enc1.isRightH()) value += 5; // если было удержание + поворот направо, увеличиваем на 5
|
|
||||||
if (enc1.isLeftH()) value -= 5; // если было удержание + поворот налево, уменьшаем на 5
|
|
||||||
|
|
||||||
if (enc1.isFastR()) value += 10; // если был быстрый поворот направо, увеличиваем на 10
|
|
||||||
if (enc1.isFastL()) value -= 10; // если был быстрый поворот налево, уменьшаем на 10
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
Serial.println(value); // выводим значение при повороте
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
Пример работы с энкодером с прерыванием. Максимальная чёткость работы
|
|
||||||
в любом быдлокоде!
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CLK 2
|
|
||||||
#define DT 3
|
|
||||||
#define SW 4
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(CLK, DT, SW);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
attachInterrupt(0, isrCLK, CHANGE); // прерывание на 2 пине! CLK у энка
|
|
||||||
attachInterrupt(1, isrDT, CHANGE); // прерывание на 3 пине! DT у энка
|
|
||||||
}
|
|
||||||
|
|
||||||
void isrCLK() {
|
|
||||||
enc1.tick(); // отработка в прерывании
|
|
||||||
}
|
|
||||||
void isrDT() {
|
|
||||||
enc1.tick(); // отработка в прерывании
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
enc1.tick();
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
// подключаем "внешний" энкодер, для работы с расширителями пинов например
|
|
||||||
|
|
||||||
#define SW 0
|
|
||||||
#define DT 2
|
|
||||||
#define CLK 3
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2);
|
|
||||||
pinMode(SW, INPUT_PULLUP);
|
|
||||||
pinMode(CLK, INPUT);
|
|
||||||
pinMode(DT, INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// подаём значения напрямую в tick()
|
|
||||||
// можно подавать лог. величины с любых расширителей пинов!!!
|
|
||||||
// Здесь в качестве примера digitalRead
|
|
||||||
enc1.tick(digitalRead(CLK), digitalRead(DT), !digitalRead(SW));
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
// ваш код
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
|
|
||||||
if (enc1.isPress()) Serial.println("Press"); // нажатие на кнопку (+ дебаунс)
|
|
||||||
if (enc1.isClick()) Serial.println("Click"); // отпускание кнопки (+ дебаунс)
|
|
||||||
//if (enc1.isRelease()) Serial.println("Release"); // то же самое, что isClick
|
|
||||||
|
|
||||||
if (enc1.isHolded()) Serial.println("Holded"); // если была удержана и энк не поворачивался
|
|
||||||
//if (enc1.isHold()) Serial.println("Hold"); // возвращает состояние кнопки
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Отработка по прерыванию таймера
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define CLK 7
|
|
||||||
#define DT 8
|
|
||||||
#define SW 9
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
#include "TimerOne.h"
|
|
||||||
Encoder enc1(CLK, DT, SW);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
|
||||||
|
|
||||||
Timer1.initialize(1000); // установка таймера на каждые 1000 микросекунд (= 1 мс)
|
|
||||||
Timer1.attachInterrupt(timerIsr); // запуск таймера
|
|
||||||
}
|
|
||||||
|
|
||||||
void timerIsr() { // прерывание таймера
|
|
||||||
enc1.tick(); // отработка теперь находится здесь
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
if (enc1.isRight()) Serial.println("Right"); // если был поворот
|
|
||||||
if (enc1.isLeft()) Serial.println("Left");
|
|
||||||
if (enc1.isRightH()) Serial.println("Right holded"); // если было удержание + поворот
|
|
||||||
if (enc1.isLeftH()) Serial.println("Left holded");
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
// два энкодера
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
Encoder enc1(4, 3, 2);
|
|
||||||
Encoder enc2(7, 6, 5);
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
enc2.tick();
|
|
||||||
|
|
||||||
if (enc1.isLeft()) Serial.println("enc 1 left");
|
|
||||||
if (enc1.isRight()) Serial.println("enc 1 right");
|
|
||||||
if (enc2.isLeft()) Serial.println("enc 2 left");
|
|
||||||
if (enc2.isRight()) Serial.println("enc 2 right");
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
#define CLK 7
|
|
||||||
#define DT 8
|
|
||||||
#define SW 9
|
|
||||||
|
|
||||||
#include "GyverEncoder.h"
|
|
||||||
//Encoder enc1(CLK, DT); // для работы без кнопки
|
|
||||||
Encoder enc1(CLK, DT, SW); // для работы c кнопкой
|
|
||||||
//Encoder enc1(CLK, DT, SW, TYPE2); // для работы c кнопкой и сразу выбираем тип
|
|
||||||
//Encoder enc1(CLK, DT, ENC_NO_BUTTON, TYPE2); // для работы без кнопки и сразу выбираем тип
|
|
||||||
|
|
||||||
int value = 0;
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
Serial.begin(9600);
|
|
||||||
enc1.setType(TYPE2); // тип энкодера TYPE1 одношаговый, TYPE2 двухшаговый. Если ваш энкодер работает странно, смените тип
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop() {
|
|
||||||
// обязательная функция отработки. Должна постоянно опрашиваться
|
|
||||||
enc1.tick();
|
|
||||||
|
|
||||||
if (enc1.isRight()) value++; // если был поворот направо, увеличиваем на 1
|
|
||||||
if (enc1.isLeft()) value--; // если был поворот налево, уменьшаем на 1
|
|
||||||
|
|
||||||
if (enc1.isRightH()) value += 5; // если было удержание + поворот направо, увеличиваем на 5
|
|
||||||
if (enc1.isLeftH()) value -= 5; // если было удержание + поворот налево, уменьшаем на 5
|
|
||||||
|
|
||||||
if (enc1.isTurn()) { // если был совершён поворот (индикатор поворота в любую сторону)
|
|
||||||
Serial.println(value); // выводим значение при повороте
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
#######################################
|
|
||||||
# Syntax Coloring Map For GyverEncoder
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Datatypes (KEYWORD1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
Encoder KEYWORD1
|
|
||||||
GyverEncoder KEYWORD1
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Methods and Functions (KEYWORD2)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
tick KEYWORD2
|
|
||||||
setType KEYWORD2
|
|
||||||
setDirection KEYWORD2
|
|
||||||
setFastTimeout KEYWORD2
|
|
||||||
setPinMode KEYWORD2
|
|
||||||
setBtnPinMode KEYWORD2
|
|
||||||
isTurn KEYWORD2
|
|
||||||
isRight KEYWORD2
|
|
||||||
isLeft KEYWORD2
|
|
||||||
isRightH KEYWORD2
|
|
||||||
isLeftH KEYWORD2
|
|
||||||
isFastR KEYWORD2
|
|
||||||
isFastL KEYWORD2
|
|
||||||
|
|
||||||
isPress KEYWORD2
|
|
||||||
isRelease KEYWORD2
|
|
||||||
isReleaseHold KEYWORD2
|
|
||||||
isClick KEYWORD2
|
|
||||||
isSingle KEYWORD2
|
|
||||||
isDouble KEYWORD2
|
|
||||||
isHolded KEYWORD2
|
|
||||||
isHold KEYWORD2
|
|
||||||
resetStates KEYWORD2
|
|
||||||
|
|
||||||
#######################################
|
|
||||||
# Constants (LITERAL1)
|
|
||||||
#######################################
|
|
||||||
|
|
||||||
TYPE1 LITERAL1
|
|
||||||
TYPE2 LITERAL1
|
|
||||||
MANUAL LITERAL1
|
|
||||||
AUTO LITERAL1
|
|
||||||
NORM LITERAL1
|
|
||||||
REVERSE LITERAL1
|
|
||||||
HIGH_PULL LITERAL1
|
|
||||||
LOW_PULL LITERAL1
|
|
||||||
ENC_NO_BUTTON LITERAL1
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
name=GyverEncoder
|
|
||||||
version=4.9
|
|
||||||
author=AlexGyver <alex@alexgyver.ru>
|
|
||||||
maintainer=AlexGyver <alex@alexgyver.ru>
|
|
||||||
sentence=Advanced encoder control library
|
|
||||||
paragraph=Advanced encoder control library
|
|
||||||
category=Sensors
|
|
||||||
url=https://github.com/GyverLibs/GyverEncoder
|
|
||||||
architectures=*
|
|
||||||
@ -1,352 +0,0 @@
|
|||||||
#include "GyverEncoder.h"
|
|
||||||
|
|
||||||
#if defined(PRECISE_ALGORITHM)
|
|
||||||
const int8_t KNOBDIR[] = {
|
|
||||||
0, -1, 1, 0,
|
|
||||||
1, 0, 0, -1,
|
|
||||||
-1, 0, 0, 1,
|
|
||||||
0, 1, -1, 0,
|
|
||||||
};
|
|
||||||
int8_t encPos = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ================= CONSTRUCTOR =================
|
|
||||||
Encoder::Encoder() {
|
|
||||||
flags.use_button = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Encoder::Encoder(uint8_t clk, uint8_t dt, int8_t sw, bool type) {
|
|
||||||
_CLK = clk;
|
|
||||||
_DT = dt;
|
|
||||||
if (sw != -1) {
|
|
||||||
_SW = sw;
|
|
||||||
flags.use_button = true;
|
|
||||||
} else {
|
|
||||||
flags.use_button = false;
|
|
||||||
}
|
|
||||||
flags.enc_type = type;
|
|
||||||
|
|
||||||
#if defined(__AVR__)
|
|
||||||
_pin_reg_CLK = portInputRegister(digitalPinToPort(_CLK));
|
|
||||||
_bit_mask_CLK = digitalPinToBitMask(_CLK);
|
|
||||||
_pin_reg_DT = portInputRegister(digitalPinToPort(_DT));
|
|
||||||
_bit_mask_DT = digitalPinToBitMask(_DT);
|
|
||||||
if (sw != -1) {
|
|
||||||
_pin_reg_SW = portInputRegister(digitalPinToPort(_SW));
|
|
||||||
_bit_mask_SW = digitalPinToBitMask(_SW);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pinMode(_CLK, (DEFAULT_ENC_PULL ? INPUT : INPUT_PULLUP));
|
|
||||||
pinMode(_DT, (DEFAULT_ENC_PULL ? INPUT : INPUT_PULLUP));
|
|
||||||
if (flags.use_button) pinMode(_SW, (DEFAULT_BTN_PULL ? INPUT : INPUT_PULLUP));
|
|
||||||
flags.invBtn = (DEFAULT_BTN_PULL == HIGH_PULL) ? true : false;
|
|
||||||
|
|
||||||
#if defined(FAST_ALGORITHM)
|
|
||||||
prevState = _readCLK();
|
|
||||||
#else
|
|
||||||
prevState = _readCLK() | (_readDT() << 1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= SET =================
|
|
||||||
void Encoder::setDirection(bool direction) {
|
|
||||||
if (direction) {
|
|
||||||
uint8_t buf = _CLK;
|
|
||||||
_CLK = _DT;
|
|
||||||
_DT = buf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Encoder::setPinMode(bool mode) {
|
|
||||||
pinMode(_CLK, (mode) ? INPUT : INPUT_PULLUP);
|
|
||||||
pinMode(_DT, (mode) ? INPUT : INPUT_PULLUP);
|
|
||||||
}
|
|
||||||
void Encoder::setBtnPinMode(bool mode) {
|
|
||||||
pinMode(_SW, (mode) ? INPUT : INPUT_PULLUP);
|
|
||||||
flags.invBtn = (mode) ? 0 : 1;
|
|
||||||
}
|
|
||||||
void Encoder::setType(bool type) {
|
|
||||||
flags.enc_type = type;
|
|
||||||
}
|
|
||||||
void Encoder::setTickMode(bool tickMode) {
|
|
||||||
flags.enc_tick_mode = tickMode;
|
|
||||||
}
|
|
||||||
void Encoder::setFastTimeout(uint16_t timeout) {
|
|
||||||
_fast_timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= IS =================
|
|
||||||
// повороты
|
|
||||||
boolean Encoder::isTurn() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isTurn_f) {
|
|
||||||
flags.isTurn_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isRight() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (encState == 2) {
|
|
||||||
encState = 0;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isLeft() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (encState == 1) {
|
|
||||||
encState = 0;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isRightH() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (encState == 4) {
|
|
||||||
encState = 0;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isLeftH() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (encState == 3) {
|
|
||||||
encState = 0;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isFastR() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isFastR_f) {
|
|
||||||
flags.isFastR_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isFastL() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isFastL_f) {
|
|
||||||
flags.isFastL_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// кнопка
|
|
||||||
boolean Encoder::isPress() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isPress_f) {
|
|
||||||
flags.isPress_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isRelease() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isRelease_f) {
|
|
||||||
flags.isRelease_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isReleaseHold() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isReleaseHold_f) {
|
|
||||||
flags.isReleaseHold_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isClick() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isRelease_f) {
|
|
||||||
flags.isRelease_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isHolded() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.hold_flag && flags.isHolded_f) {
|
|
||||||
flags.isHolded_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isSingle() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isSingle_f) {
|
|
||||||
flags.isSingle_f = false;
|
|
||||||
flags.isDouble_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isDouble() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
if (flags.isDouble_f) {
|
|
||||||
flags.isDouble_f = false;
|
|
||||||
flags.isSingle_f = false;
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
boolean Encoder::isHold() {
|
|
||||||
if (flags.enc_tick_mode) Encoder::tick();
|
|
||||||
return (SW_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Encoder::resetStates() {
|
|
||||||
encState = 0;
|
|
||||||
flags.isTurn_f = false;
|
|
||||||
flags.isFastR_f = false;
|
|
||||||
flags.isFastL_f = false;
|
|
||||||
flags.isPress_f = false;
|
|
||||||
flags.isRelease_f = false;
|
|
||||||
flags.isReleaseHold_f = false;
|
|
||||||
flags.isHolded_f = false;
|
|
||||||
flags.isSingle_f = false;
|
|
||||||
flags.isDouble_f = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================= TICK =================
|
|
||||||
void Encoder::tick(bool clk, bool dt, bool sw) {
|
|
||||||
extTick = true;
|
|
||||||
flags.extCLK = clk;
|
|
||||||
flags.extDT = dt;
|
|
||||||
flags.extSW = sw;
|
|
||||||
Encoder::tick();
|
|
||||||
extTick = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Encoder::tick() {
|
|
||||||
uint32_t thisMls = millis();
|
|
||||||
uint32_t debounceDelta = thisMls - debounce_timer;
|
|
||||||
|
|
||||||
#ifdef ENC_WITH_BUTTON
|
|
||||||
if (flags.use_button) {
|
|
||||||
if (!extTick) SW_state = _readSW() ^ flags.invBtn; // читаем состояние кнопки SW
|
|
||||||
else SW_state = flags.extSW;
|
|
||||||
|
|
||||||
if (SW_state && !flags.butt_flag && (debounceDelta > ENC_DEBOUNCE_BUTTON)) {
|
|
||||||
flags.butt_flag = true;
|
|
||||||
flags.turn_flag = false;
|
|
||||||
debounce_timer = thisMls;
|
|
||||||
debounceDelta = 0;
|
|
||||||
flags.isPress_f = true;
|
|
||||||
flags.isHolded_f = true;
|
|
||||||
flags.doubleAllow = true;
|
|
||||||
}
|
|
||||||
if (!SW_state && flags.butt_flag && (debounceDelta > ENC_DEBOUNCE_BUTTON)) {
|
|
||||||
if (!flags.turn_flag && !flags.hold_flag) { // если кнопка отпущена и ручка не поворачивалась
|
|
||||||
flags.turn_flag = false;
|
|
||||||
flags.isRelease_f = true;
|
|
||||||
}
|
|
||||||
if (debounceDelta > ENC_HOLD_TIMEOUT) flags.isReleaseHold_f = true;
|
|
||||||
flags.butt_flag = false;
|
|
||||||
debounce_timer = thisMls;
|
|
||||||
debounceDelta = 0;
|
|
||||||
flags.hold_flag = false;
|
|
||||||
|
|
||||||
if (flags.doubleAllow && !flags.doubleFlag) {
|
|
||||||
flags.doubleFlag = true;
|
|
||||||
flags.countFlag = false;
|
|
||||||
} else {
|
|
||||||
flags.countFlag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (flags.doubleFlag && debounceDelta > ENC_DOUBLE_TIMEOUT) {
|
|
||||||
if (!flags.turn_flag) {
|
|
||||||
if (!flags.countFlag) flags.isSingle_f = true;
|
|
||||||
else flags.isDouble_f = true;
|
|
||||||
}
|
|
||||||
flags.doubleFlag = false;
|
|
||||||
}
|
|
||||||
if (flags.butt_flag && debounceDelta > ENC_HOLD_TIMEOUT && !flags.turn_flag) {
|
|
||||||
if (SW_state) {
|
|
||||||
flags.hold_flag = true;
|
|
||||||
flags.doubleAllow = false;
|
|
||||||
} else {
|
|
||||||
flags.butt_flag = false;
|
|
||||||
flags.hold_flag = false;
|
|
||||||
debounce_timer = thisMls;
|
|
||||||
debounceDelta = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(FAST_ALGORITHM)
|
|
||||||
uint8_t curState = (extTick) ? (flags.extCLK) : (_readCLK());
|
|
||||||
|
|
||||||
if (curState != prevState
|
|
||||||
#if (ENC_DEBOUNCE_TURN > 0)
|
|
||||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
encState = 0;
|
|
||||||
turnFlag = !turnFlag;
|
|
||||||
if (turnFlag || !flags.enc_type) {
|
|
||||||
if (( (extTick) ? (flags.extDT) : _readDT() ) != prevState) {
|
|
||||||
encState = 1;
|
|
||||||
} else {
|
|
||||||
encState = 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(BINARY_ALGORITHM)
|
|
||||||
uint8_t curState = (extTick) ? (flags.extCLK | (flags.extDT << 1)) : (_readCLK() | (_readDT() << 1));
|
|
||||||
|
|
||||||
if (curState != prevState
|
|
||||||
#if (ENC_DEBOUNCE_TURN > 0)
|
|
||||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
encState = 0;
|
|
||||||
if (flags.rst_flag) {
|
|
||||||
if (curState == 0b11) {
|
|
||||||
flags.rst_flag = 0;
|
|
||||||
//encState = 3-prevState;
|
|
||||||
switch (prevState) {
|
|
||||||
case 0b10: encState = 1; break; // 2 - 1
|
|
||||||
case 0b01: encState = 2; break; // 1 - 2
|
|
||||||
}
|
|
||||||
} else if (!flags.enc_type && (curState == 0b00)) {
|
|
||||||
flags.rst_flag = 0;
|
|
||||||
//encState = prevState;
|
|
||||||
switch (prevState) {
|
|
||||||
case 0b01: encState = 1; break;
|
|
||||||
case 0b10: encState = 2; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (curState == 0b00 || (!flags.enc_type && curState == 0b11)) flags.rst_flag = 1;
|
|
||||||
|
|
||||||
#elif defined(PRECISE_ALGORITHM)
|
|
||||||
uint8_t curState = (extTick) ? (flags.extCLK | (flags.extDT << 1)) : (_readCLK() | (_readDT() << 1));
|
|
||||||
|
|
||||||
if (curState != prevState
|
|
||||||
#if (ENC_DEBOUNCE_TURN > 0)
|
|
||||||
&& (debounceDelta > ENC_DEBOUNCE_TURN)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
encState = 0;
|
|
||||||
encPos += KNOBDIR[curState | (prevState << 2)];
|
|
||||||
if (flags.enc_type) {
|
|
||||||
if (curState == 0x3 && encPos != 0) {
|
|
||||||
encState = (encPos == 4) ? 1 : 2;
|
|
||||||
encPos = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((curState == 0x3 || !curState) && encPos != 0) {
|
|
||||||
encState = (encPos == 2) ? 1 : 2;
|
|
||||||
encPos = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (encState != 0) {
|
|
||||||
flags.isTurn_f = true;
|
|
||||||
if (!SW_state && thisMls - fast_timer < _fast_timeout) {
|
|
||||||
if (encState == 1) flags.isFastL_f = true;
|
|
||||||
else if (encState == 2) flags.isFastR_f = true;
|
|
||||||
fast_timer = thisMls;
|
|
||||||
} else fast_timer = thisMls;
|
|
||||||
#ifdef ENC_WITH_BUTTON
|
|
||||||
if (flags.use_button && SW_state) encState += 2;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
prevState = curState;
|
|
||||||
flags.turn_flag = true;
|
|
||||||
debounce_timer = thisMls;
|
|
||||||
debounceDelta = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,175 +0,0 @@
|
|||||||
/*
|
|
||||||
GyverEncoder - библиотека для расширенной работы с энкодером
|
|
||||||
ВНИМАНИЕ, БИБЛИОТЕКА УСТАРЕЛА! ИСПОЛЬЗУЙ БИБЛИОТЕКУ EncButton https://github.com/GyverLibs/EncButton
|
|
||||||
Документация: https://alexgyver.ru/encoder/
|
|
||||||
GitHub: https://github.com/GyverLibs/GyverEncoder
|
|
||||||
Возможности:
|
|
||||||
- Отработка поворота энкодера
|
|
||||||
- Отработка "нажатого поворота"
|
|
||||||
- Отработка "быстрого поворота"
|
|
||||||
- Несколько алгоритмов опроса энкодера
|
|
||||||
- Выбор подтяжки подключения энкодера
|
|
||||||
- Работа с двумя типами экнодеров
|
|
||||||
- Работа с внешним энкодером (через расширитель пинов и т.п.)
|
|
||||||
- Отработка нажатия/удержания кнопки с антидребезгом
|
|
||||||
|
|
||||||
Версии:
|
|
||||||
v3.6 от 16.09.2019 - Возвращены дефайны настроек
|
|
||||||
v4.0 от 13.11.2019
|
|
||||||
- Оптимизирован код
|
|
||||||
- Исправлены баги
|
|
||||||
- Добавлены другие алгоритмы опроса
|
|
||||||
- Добавлена возможность полностью убрать кнопку (экономия памяти)
|
|
||||||
- Добавлена возможность подключения внешнего энкодера
|
|
||||||
- Добавлена настройка подтяжки пинов
|
|
||||||
|
|
||||||
v4.1: Исправлено изменение подтяжек
|
|
||||||
|
|
||||||
v4.2
|
|
||||||
- Добавлена поддержка TYPE1 для алгоритма PRECISE_ALGORITHM
|
|
||||||
- Добавлена отработка двойного клика: isSingle / isDouble
|
|
||||||
|
|
||||||
v4.3: Исправлено ложное isSingle
|
|
||||||
v4.4: Добавлен метод resetStates, сбрасывает все is-флаги и счётчики
|
|
||||||
v4.5: Улучшен алгоритм BINARY_ALGORITHM (спасибо Ярославу Курусу)
|
|
||||||
v4.6: BINARY_ALGORITHM пофикшен для TYPE1, добавлена isReleaseHold
|
|
||||||
v4.7: Исправлен случайный нажатый поворот в BINARY_ALGORITHM
|
|
||||||
v4.8: увеличена производительность для AVR Arduino
|
|
||||||
v4.9: быстрый поворот отключен если кнопка удерживается
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GyverEncoder_h
|
|
||||||
#define GyverEncoder_h
|
|
||||||
#include <Arduino.h>
|
|
||||||
|
|
||||||
// ========= КОНСТАНТЫ ==========
|
|
||||||
#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 0
|
|
||||||
#define ENC_DEBOUNCE_BUTTON 80
|
|
||||||
#define ENC_HOLD_TIMEOUT 700
|
|
||||||
#define ENC_DOUBLE_TIMEOUT 300
|
|
||||||
|
|
||||||
#if defined(__AVR__)
|
|
||||||
#define _readCLK() bool(*_pin_reg_CLK & _bit_mask_CLK)
|
|
||||||
#define _readDT() bool(*_pin_reg_DT & _bit_mask_DT)
|
|
||||||
#define _readSW() bool(*_pin_reg_SW & _bit_mask_SW)
|
|
||||||
#else
|
|
||||||
#define _readCLK() digitalRead(_CLK)
|
|
||||||
#define _readDT() digitalRead(_DT)
|
|
||||||
#define _readSW() digitalRead(_SW)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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 isReleaseHold_f: 1;
|
|
||||||
bool isHolded_f: 1;
|
|
||||||
bool isFastR_f: 1;
|
|
||||||
bool isFastL_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;
|
|
||||||
bool rst_flag : 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(uint8_t clk, uint8_t dt, int8_t sw = -1, 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(uint16_t timeout); // установка таймаута быстрого поворота
|
|
||||||
|
|
||||||
boolean isTurn(); // возвращает true при любом повороте, сама сбрасывается в false
|
|
||||||
boolean isRight(); // возвращает true при повороте направо, сама сбрасывается в false
|
|
||||||
boolean isLeft(); // возвращает true при повороте налево, сама сбрасывается в false
|
|
||||||
boolean isRightH(); // возвращает true при удержании кнопки и повороте направо, сама сбрасывается в false
|
|
||||||
boolean isLeftH(); // возвращает true при удержании кнопки и повороте налево, сама сбрасывается в false
|
|
||||||
boolean isFastR(); // возвращает true при быстром повороте
|
|
||||||
boolean isFastL(); // возвращает true при быстром повороте
|
|
||||||
|
|
||||||
boolean isPress(); // возвращает true при нажатии кнопки, сама сбрасывается в false
|
|
||||||
boolean isRelease(); // возвращает true при отпускании кнопки, сама сбрасывается в false
|
|
||||||
boolean isReleaseHold(); // возвращает true при отпускании кнопки после удержания, сама сбрасывается в false
|
|
||||||
boolean isClick(); // возвращает true при нажатии и отпускании кнопки, сама сбрасывается в false
|
|
||||||
boolean isHolded(); // возвращает true при удержании кнопки, сама сбрасывается в false
|
|
||||||
boolean isHold(); // возвращает true при удержании кнопки, НЕ СБРАСЫВАЕТСЯ
|
|
||||||
boolean isSingle(); // возвращает true при одиночном клике (после таймаута), сама сбрасывается в false
|
|
||||||
boolean isDouble(); // возвращает true при двойном клике, сама сбрасывается в false
|
|
||||||
|
|
||||||
void resetStates(); // сбрасывает все is-флаги и счётчики
|
|
||||||
|
|
||||||
private:
|
|
||||||
GyverEncoderFlags flags;
|
|
||||||
uint8_t _fast_timeout = 50; // таймаут быстрого поворота
|
|
||||||
uint8_t prevState = 0;
|
|
||||||
uint8_t encState = 0; // 0 не крутился, 1 лево, 2 право, 3 лево нажат, 4 право нажат
|
|
||||||
uint32_t debounce_timer = 0, fast_timer = 0;
|
|
||||||
uint8_t _CLK = 0, _DT = 0, _SW = 0;
|
|
||||||
bool turnFlag = false, extTick = false, SW_state = false;
|
|
||||||
#if defined(__AVR__)
|
|
||||||
volatile uint8_t *_pin_reg_CLK;
|
|
||||||
volatile uint8_t _bit_mask_CLK;
|
|
||||||
volatile uint8_t *_pin_reg_DT;
|
|
||||||
volatile uint8_t _bit_mask_DT;
|
|
||||||
volatile uint8_t *_pin_reg_SW;
|
|
||||||
volatile uint8_t _bit_mask_SW;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
21
libraries/GyverTM1637/LICENSE
Normal file
21
libraries/GyverTM1637/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2021 Alex
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
337
libraries/GyverTM1637/README.md
Normal file
337
libraries/GyverTM1637/README.md
Normal file
@ -0,0 +1,337 @@
|
|||||||
|

|
||||||
|

|
||||||
|
# GyverTM1637
|
||||||
|
GyverTM1637 - бибилотека для 7 сегментного дисплея на чипе TM1637 с кучей приколюх
|
||||||
|
- Вывод цифр массивом или прицельно
|
||||||
|
- Вывод букв из списка доступных (листай ниже) массивом или прицельно
|
||||||
|
- Отдельная функция вывода часов и минут (часы без нуля слева, минуты с нулём)
|
||||||
|
- Вывод числа от -999 до 9999 с учётом знака
|
||||||
|
- Готовая функция бегущей строки
|
||||||
|
- Функции смены яркости и состояния двоеточия автоматически обновляют дисплей
|
||||||
|
- Функция обновления значения с эффектом вертикальной прокрутки
|
||||||
|
- Функция обновления значения с эффектом скручивания (лучше один раз увидеть)
|
||||||
|
|
||||||
|
### Совместимость
|
||||||
|
Совместима со всеми Arduino платформами (используются Arduino-функции)
|
||||||
|
|
||||||
|
### Документация
|
||||||
|
К библиотеке есть [расширенная документация](https://alexgyver.ru/tm1637_display/)
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
- [Установка](#install)
|
||||||
|
- [Инициализация](#init)
|
||||||
|
- [Использование](#usage)
|
||||||
|
- [Пример](#example)
|
||||||
|
- [Версии](#versions)
|
||||||
|
- [Баги и обратная связь](#feedback)
|
||||||
|
|
||||||
|
<a id="install"></a>
|
||||||
|
## Установка
|
||||||
|
- Библиотеку можно найти по названию **GyverTM1637** и установить через менеджер библиотек в:
|
||||||
|
- Arduino IDE
|
||||||
|
- Arduino IDE v2
|
||||||
|
- PlatformIO
|
||||||
|
- [Скачать библиотеку](https://github.com/GyverLibs/GyverTM1637/archive/refs/heads/main.zip) .zip архивом для ручной установки:
|
||||||
|
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64)
|
||||||
|
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32)
|
||||||
|
- Распаковать и положить в *Документы/Arduino/libraries/*
|
||||||
|
- (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив
|
||||||
|
- Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA)
|
||||||
|
|
||||||
|
<a id="init"></a>
|
||||||
|
## Инициализация
|
||||||
|
```cpp
|
||||||
|
GyverTM1637 disp(CLK, DIO);
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="usage"></a>
|
||||||
|
## Использование
|
||||||
|
```cpp
|
||||||
|
void display(uint8_t DispData[]); // выводит цифры массивом по ячейкам. От 0 до 9 (byte values[] = {3, 5, 9, 0}; )
|
||||||
|
void display(uint8_t BitAddr, uint8_t DispData); // выводит цифру DispData в указанную ячейку дисплея BitAddr
|
||||||
|
void display(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3); // если лень создавать массив, выводит цифры в ячейки
|
||||||
|
|
||||||
|
void displayByte(uint8_t DispData[]); // выводит байт вида 0xe6 и буквы-константы вида _a , _b .... массивом
|
||||||
|
void displayByte(uint8_t BitAddr, uint8_t DispData); // выводит байт вида 0xe6 и буквы-константы вида _a , _b .... в ячейку
|
||||||
|
void displayByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3); // если лень создавать массив, выводит байты в ячейки
|
||||||
|
|
||||||
|
void displayClock(uint8_t hrs, uint8_t mins); // выводит часы и минуты
|
||||||
|
void displayClockScroll(uint8_t hrs, uint8_t mins, int delayms); // выводит часы и минуты с эффектом прокрутки
|
||||||
|
void displayClockTwist(uint8_t hrs, uint8_t mins, int delayms); // выводит часы и минуты с эффектом скрутки
|
||||||
|
|
||||||
|
void displayInt(int value); // выводит число от -999 до 9999 (да, со знаком минус)
|
||||||
|
void runningString(uint8_t DispData[], byte amount, int delayMs); // бегущая строка (array, sizeof(array), задержка в мс)
|
||||||
|
void clear(void); // очистить дисплей
|
||||||
|
void point(boolean PointFlag); // вкл / выкл точку (POINT_ON / POINT_OFF)
|
||||||
|
void brightness(uint8_t bright, uint8_t = 0x40, uint8_t = 0xc0); // яркость 0 - 7
|
||||||
|
|
||||||
|
void scroll(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение прокруткой (адрес, ЦИФРА, задержка в мс)
|
||||||
|
void scroll(uint8_t DispData[], int delayms); // обновить значение прокруткой (массив ЦИФР, задержка в мс)
|
||||||
|
void scroll(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // прокрутка посимвольно
|
||||||
|
void scrollByte(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение прокруткой (адрес, БАЙТ, задержка в мс)
|
||||||
|
void scrollByte(uint8_t DispData[], int delayms); // обновить значение прокруткой (массив БАЙТ, задержка в мс)
|
||||||
|
void scrollByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // прокрутка посимвольно
|
||||||
|
|
||||||
|
void twist(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение скручиванием (адрес, ЦИФРА, задержка в мс)
|
||||||
|
void twist(uint8_t DispData[], int delayms); // обновить значение скручиванием (массив ЦИФР, задержка в мс)
|
||||||
|
void twist(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // скрутка посимвольно
|
||||||
|
void twistByte(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение скручиванием (адрес, БАЙТ, задержка в мс)
|
||||||
|
void twistByte(uint8_t DispData[], int delayms); // обновить значение скручиванием (массив БАЙТ, задержка в мс)
|
||||||
|
void twistByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // скрутка посимвольно
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="example"></a>
|
||||||
|
## Пример
|
||||||
|
Остальные примеры смотри в **examples**!
|
||||||
|
```cpp
|
||||||
|
/*
|
||||||
|
Пример вывода на дисплей с регистром TM1637
|
||||||
|
показывает все возможности библиотеки GyverTM1637
|
||||||
|
AlexGyver Technologies http://alexgyver.ru/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CLK 2
|
||||||
|
#define DIO 3
|
||||||
|
|
||||||
|
#include "GyverTM1637.h"
|
||||||
|
GyverTM1637 disp(CLK, DIO);
|
||||||
|
|
||||||
|
uint32_t Now, clocktimer;
|
||||||
|
boolean flag;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
disp.clear();
|
||||||
|
disp.brightness(7); // яркость, 0 - 7 (минимум - максимум)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
runningText();
|
||||||
|
scrolls();
|
||||||
|
scrollClock();
|
||||||
|
twists();
|
||||||
|
twistClock();
|
||||||
|
ints();
|
||||||
|
bytes();
|
||||||
|
fadeBlink();
|
||||||
|
normClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void twists() {
|
||||||
|
// скручивание массив ЦИФР
|
||||||
|
byte digs[4] = {3, 5, 7, 1};
|
||||||
|
disp.twist(digs, 50); // скорость прокрутки 100
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// скручивание прицельно (ячейка, БАЙТ, скорость)
|
||||||
|
disp.twistByte(0, _1, 50);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// скручивание прицельно (ячейка, ЦИФРА, скорость)
|
||||||
|
disp.twist(0, 8, 70);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
disp.clear();
|
||||||
|
delay(200);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.twist(3, i, 20);
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// скручивание массива БАЙТ
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.twistByte(troll, 50);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прицельное скручивание БАЙТА (ячейка, байт, скорость)
|
||||||
|
disp.twistByte(2, _G, 50);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void twistClock() {
|
||||||
|
byte hrs = 21, mins = 55;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClockTwist(hrs, mins, 35); // выводим время
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrolls() {
|
||||||
|
// прокрутка массив ЦИФР
|
||||||
|
byte digs[4] = {3, 5, 7, 1};
|
||||||
|
disp.scroll(digs, 100); // скорость прокрутки 100
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прокрутка прицельно (ячейка, ЦИФРА, скорость)
|
||||||
|
disp.scroll(0, 8, 200);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
disp.clear();
|
||||||
|
delay(1000);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.scroll(3, i, 50);
|
||||||
|
delay(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// прокрутка массива БАЙТ
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.scrollByte(troll, 100);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прицельная прокрутка БАЙТА (ячейка, байт, скорость)
|
||||||
|
disp.scrollByte(2, _G, 50);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bytes() {
|
||||||
|
// выводим байты из массива
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.displayByte(troll);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим байты напрямую (4 в скобках)
|
||||||
|
disp.displayByte(_L, _O, _L, _empty);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим байты "прицельно"
|
||||||
|
disp.displayByte(3, _O); // 3 ячейка, буква О
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры из массива
|
||||||
|
byte hell[4] = {6, 6, 6, 6};
|
||||||
|
disp.display(hell);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры напрямую (4 в скобках)
|
||||||
|
disp.display(1, 2, 3, 4);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры "прицельно"
|
||||||
|
disp.display(0, 9); // 0 ячейка, цифра 9
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fadeBlink() {
|
||||||
|
// пишем HELL
|
||||||
|
disp.displayByte(_H, _E, _L, _L);
|
||||||
|
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 3000) { // 3 секунды
|
||||||
|
for (int i = 7; i > 0; i--) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClockScroll(hrs, mins, 70); // выводим время
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void normClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClock(hrs, mins); // выводим время функцией часов
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void ints() {
|
||||||
|
// тупо отправляем цифры
|
||||||
|
disp.displayInt(-999);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(-99);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(-9);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(0);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(6);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(66);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(666);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(6666);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runningText() {
|
||||||
|
byte welcome_banner[] = {_H, _E, _L, _L, _O, _empty, _empty,
|
||||||
|
_e, _n, _j, _o, _y, _empty, _empty,
|
||||||
|
_1, _6, _3, _7, _empty, _d, _i, _S, _P, _l, _a, _y
|
||||||
|
};
|
||||||
|
disp.runningString(welcome_banner, sizeof(welcome_banner), 200); // 200 это время в миллисекундах!
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
<a id="versions"></a>
|
||||||
|
## Версии
|
||||||
|
- v1.4 - поправлены типы данных и ошибки, добавлена совместимость с ESP
|
||||||
|
|
||||||
|
<a id="feedback"></a>
|
||||||
|
## Баги и обратная связь
|
||||||
|
При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru)
|
||||||
|
Библиотека открыта для доработки и ваших **Pull Request**'ов!
|
||||||
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
Пример вывода на дисплей с регистром TM1637
|
||||||
|
показывает все возможности библиотеки GyverTM1637
|
||||||
|
AlexGyver Technologies http://alexgyver.ru/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CLK 2
|
||||||
|
#define DIO 3
|
||||||
|
|
||||||
|
#include "GyverTM1637.h"
|
||||||
|
GyverTM1637 disp(CLK, DIO);
|
||||||
|
|
||||||
|
uint32_t Now, clocktimer;
|
||||||
|
boolean flag;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
disp.clear();
|
||||||
|
disp.brightness(7); // яркость, 0 - 7 (минимум - максимум)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
runningText();
|
||||||
|
scrolls();
|
||||||
|
scrollClock();
|
||||||
|
twists();
|
||||||
|
twistClock();
|
||||||
|
ints();
|
||||||
|
bytes();
|
||||||
|
fadeBlink();
|
||||||
|
normClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void twists() {
|
||||||
|
// скручивание массив ЦИФР
|
||||||
|
byte digs[4] = {3, 5, 7, 1};
|
||||||
|
disp.twist(digs, 50); // скорость прокрутки 100
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// скручивание прицельно (ячейка, БАЙТ, скорость)
|
||||||
|
disp.twistByte(0, _1, 50);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// скручивание прицельно (ячейка, ЦИФРА, скорость)
|
||||||
|
disp.twist(0, 8, 70);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
disp.clear();
|
||||||
|
delay(200);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.twist(3, i, 20);
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// скручивание массива БАЙТ
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.twistByte(troll, 50);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прицельное скручивание БАЙТА (ячейка, байт, скорость)
|
||||||
|
disp.twistByte(2, _G, 50);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void twistClock() {
|
||||||
|
byte hrs = 21, mins = 55;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClockTwist(hrs, mins, 35); // выводим время
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrolls() {
|
||||||
|
// прокрутка массив ЦИФР
|
||||||
|
byte digs[4] = {3, 5, 7, 1};
|
||||||
|
disp.scroll(digs, 100); // скорость прокрутки 100
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прокрутка прицельно (ячейка, ЦИФРА, скорость)
|
||||||
|
disp.scroll(0, 8, 200);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
disp.clear();
|
||||||
|
delay(1000);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.scroll(3, i, 50);
|
||||||
|
delay(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// прокрутка массива БАЙТ
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.scrollByte(troll, 100);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// прицельная прокрутка БАЙТА (ячейка, байт, скорость)
|
||||||
|
disp.scrollByte(2, _G, 50);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bytes() {
|
||||||
|
// выводим байты из массива
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.displayByte(troll);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим байты напрямую (4 в скобках)
|
||||||
|
disp.displayByte(_L, _O, _L, _empty);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим байты "прицельно"
|
||||||
|
disp.displayByte(3, _O); // 3 ячейка, буква О
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры из массива
|
||||||
|
byte hell[4] = {6, 6, 6, 6};
|
||||||
|
disp.display(hell);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры напрямую (4 в скобках)
|
||||||
|
disp.display(1, 2, 3, 4);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
// выводим цифры "прицельно"
|
||||||
|
disp.display(0, 9); // 0 ячейка, цифра 9
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fadeBlink() {
|
||||||
|
// пишем HELL
|
||||||
|
disp.displayByte(_H, _E, _L, _L);
|
||||||
|
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 3000) { // 3 секунды
|
||||||
|
for (int i = 7; i > 0; i--) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClockScroll(hrs, mins, 70); // выводим время
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void normClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 10000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClock(hrs, mins); // выводим время функцией часов
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void ints() {
|
||||||
|
// тупо отправляем цифры
|
||||||
|
disp.displayInt(-999);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(-99);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(-9);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(0);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(6);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(66);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(666);
|
||||||
|
delay(500);
|
||||||
|
disp.displayInt(6666);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runningText() {
|
||||||
|
byte welcome_banner[] = {_H, _E, _L, _L, _O, _empty, _empty,
|
||||||
|
_e, _n, _j, _o, _y, _empty, _empty,
|
||||||
|
_1, _6, _3, _7, _empty, _d, _i, _S, _P, _l, _a, _y
|
||||||
|
};
|
||||||
|
disp.runningString(welcome_banner, sizeof(welcome_banner), 200); // 200 это время в миллисекундах!
|
||||||
|
}
|
||||||
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
Пример вывода на дисплей с регистром TM1637
|
||||||
|
показывает все возможности библиотеки GyverTM1637
|
||||||
|
AlexGyver Technologies http://alexgyver.ru/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CLK 2
|
||||||
|
#define DIO 3
|
||||||
|
|
||||||
|
#include "GyverTM1637.h"
|
||||||
|
GyverTM1637 disp(CLK, DIO);
|
||||||
|
|
||||||
|
uint32_t Now, clocktimer;
|
||||||
|
boolean flag;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
disp.clear();
|
||||||
|
disp.brightness(7); // яркость, 0 - 7 (минимум - максимум)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
runningText();
|
||||||
|
normClock();
|
||||||
|
scrollClock();
|
||||||
|
twistClock();
|
||||||
|
scrolls();
|
||||||
|
twists();
|
||||||
|
ints();
|
||||||
|
fadeBlink();
|
||||||
|
}
|
||||||
|
|
||||||
|
void twists() {
|
||||||
|
disp.clear();
|
||||||
|
delay(200);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.twist(3, i, 20);
|
||||||
|
delay(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// скрутка массива БАЙТ
|
||||||
|
byte troll[4] = {_L, _O, _L, _empty};
|
||||||
|
disp.scrollByte(troll, 100);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void twistClock() {
|
||||||
|
byte hrs = 21, mins = 55;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 5000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
byte dispTime[] = {(byte)hrs / 10, (byte)hrs % 10, (byte)mins / 10, (byte)mins % 10};
|
||||||
|
disp.twist(dispTime, 35); // выводим время массивом
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrolls() {
|
||||||
|
disp.clear();
|
||||||
|
delay(1000);
|
||||||
|
for (byte i = 0; i < 10; i++) {
|
||||||
|
disp.scroll(3, i, 50);
|
||||||
|
delay(300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// прокрутка массива БАЙТ
|
||||||
|
byte troll[4] = {_t, _r, _o, _l};
|
||||||
|
disp.scrollByte(troll, 100);
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fadeBlink() {
|
||||||
|
// пишем HELL
|
||||||
|
disp.displayByte(_H, _E, _L, _L);
|
||||||
|
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 3000) { // 3 секунды
|
||||||
|
for (int i = 7; i > 0; i--) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
disp.brightness(i); // меняем яркость
|
||||||
|
delay(40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 5000) { // каждые 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
if (flag) {
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
byte dispTime[] = {(byte)hrs / 10, (byte)hrs % 10, (byte)mins / 10, (byte)mins % 10};
|
||||||
|
disp.scroll(dispTime, 70); // выводим время массивом
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void normClock() {
|
||||||
|
byte hrs = 15, mins = 0;
|
||||||
|
uint32_t tmr;
|
||||||
|
Now = millis();
|
||||||
|
while (millis () - Now < 5000) { // 10 секунд
|
||||||
|
if (millis() - tmr > 500) { // каждые полсекунды
|
||||||
|
tmr = millis();
|
||||||
|
flag = !flag;
|
||||||
|
disp.point(flag); // выкл/выкл точки
|
||||||
|
|
||||||
|
// ***** часы! ****
|
||||||
|
mins ++;
|
||||||
|
if (mins > 59) {
|
||||||
|
mins = 0;
|
||||||
|
hrs++;
|
||||||
|
if (hrs > 24) hrs = 0;
|
||||||
|
}
|
||||||
|
// ***** часы! ****
|
||||||
|
disp.displayClock(hrs, mins); // выводим время функцией часов
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp.point(0); // выкл точки
|
||||||
|
}
|
||||||
|
|
||||||
|
void ints() {
|
||||||
|
// тупо отправляем цифры
|
||||||
|
disp.displayInt(-999);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(-99);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(-9);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(0);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(6);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(66);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(666);
|
||||||
|
delay(200);
|
||||||
|
disp.displayInt(6666);
|
||||||
|
delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runningText() {
|
||||||
|
byte welcome_banner[] = {_H, _E, _L, _L, _O, _empty, _empty,
|
||||||
|
_T, _M, _1, _6, _3, _7,
|
||||||
|
};
|
||||||
|
disp.runningString(welcome_banner, sizeof(welcome_banner), 150); // 200 это время в миллисекундах!
|
||||||
|
}
|
||||||
91
libraries/GyverTM1637/keywords.txt
Normal file
91
libraries/GyverTM1637/keywords.txt
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
#######################################
|
||||||
|
# Syntax Coloring Map For GyverTM1637
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Datatypes (KEYWORD1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
GyverTM1637 KEYWORD1
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Methods and Functions (KEYWORD2)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
display KEYWORD2
|
||||||
|
displayByte KEYWORD2
|
||||||
|
displayInt KEYWORD2
|
||||||
|
|
||||||
|
displayClock KEYWORD2
|
||||||
|
displayClockTwist KEYWORD2
|
||||||
|
displayClockScroll KEYWORD2
|
||||||
|
|
||||||
|
runningString KEYWORD2
|
||||||
|
scroll KEYWORD2
|
||||||
|
scrollByte KEYWORD2
|
||||||
|
twist KEYWORD2
|
||||||
|
twistByte KEYWORD2
|
||||||
|
|
||||||
|
clear KEYWORD2
|
||||||
|
point KEYWORD2
|
||||||
|
brightness KEYWORD2
|
||||||
|
digToHEX KEYWORD2
|
||||||
|
|
||||||
|
#######################################
|
||||||
|
# Constants (LITERAL1)
|
||||||
|
#######################################
|
||||||
|
|
||||||
|
POINT_ON LITERAL1
|
||||||
|
POINT_OFF LITERAL1
|
||||||
|
|
||||||
|
_A LITERAL1
|
||||||
|
_B LITERAL1
|
||||||
|
_C LITERAL1
|
||||||
|
_D LITERAL1
|
||||||
|
_E LITERAL1
|
||||||
|
_F LITERAL1
|
||||||
|
_G LITERAL1
|
||||||
|
_H LITERAL1
|
||||||
|
_J LITERAL1
|
||||||
|
_L LITERAL1
|
||||||
|
_N LITERAL1
|
||||||
|
_O LITERAL1
|
||||||
|
_P LITERAL1
|
||||||
|
_S LITERAL1
|
||||||
|
_U LITERAL1
|
||||||
|
_Y LITERAL1
|
||||||
|
_a LITERAL1
|
||||||
|
_b LITERAL1
|
||||||
|
_c LITERAL1
|
||||||
|
_d LITERAL1
|
||||||
|
_e LITERAL1
|
||||||
|
_f LITERAL1
|
||||||
|
_h LITERAL1
|
||||||
|
_i LITERAL1
|
||||||
|
_j LITERAL1
|
||||||
|
_l LITERAL1
|
||||||
|
_n LITERAL1
|
||||||
|
_o LITERAL1
|
||||||
|
_q LITERAL1
|
||||||
|
_r LITERAL1
|
||||||
|
_t LITERAL1
|
||||||
|
_u LITERAL1
|
||||||
|
_y LITERAL1
|
||||||
|
|
||||||
|
_dash LITERAL1
|
||||||
|
_under LITERAL1
|
||||||
|
_equal LITERAL1
|
||||||
|
_empty LITERAL1
|
||||||
|
_degree LITERAL1
|
||||||
|
|
||||||
|
_0 LITERAL1
|
||||||
|
_1 LITERAL1
|
||||||
|
_2 LITERAL1
|
||||||
|
_3 LITERAL1
|
||||||
|
_4 LITERAL1
|
||||||
|
_5 LITERAL1
|
||||||
|
_6 LITERAL1
|
||||||
|
_7 LITERAL1
|
||||||
|
_8 LITERAL1
|
||||||
|
_9 LITERAL1
|
||||||
9
libraries/GyverTM1637/library.properties
Normal file
9
libraries/GyverTM1637/library.properties
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
name=GyverTM1637
|
||||||
|
version=1.4
|
||||||
|
author=AlexGyver <alex@alexgyver.ru>
|
||||||
|
maintainer=AlexGyver <alex@alexgyver.ru>
|
||||||
|
sentence=Library for advanced control of TM1637 7-segment display
|
||||||
|
paragraph=Library for advanced control of TM1637 7-segment display
|
||||||
|
category=Display
|
||||||
|
url=https://github.com/GyverLibs/GyverTM1637
|
||||||
|
architectures=*
|
||||||
535
libraries/GyverTM1637/src/GyverTM1637.cpp
Normal file
535
libraries/GyverTM1637/src/GyverTM1637.cpp
Normal file
@ -0,0 +1,535 @@
|
|||||||
|
#include "GyverTM1637.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
const uint8_t digitHEX[] = {0x3f, 0x06, 0x5b, 0x4f,
|
||||||
|
0x66, 0x6d, 0x7d, 0x07,
|
||||||
|
0x7f, 0x6f, 0x00, 0x40
|
||||||
|
};//0~9, ,-
|
||||||
|
|
||||||
|
GyverTM1637::GyverTM1637(uint8_t clk, uint8_t dio)
|
||||||
|
{
|
||||||
|
Clkpin = clk;
|
||||||
|
Datapin = dio;
|
||||||
|
pinMode(Clkpin, OUTPUT);
|
||||||
|
pinMode(Datapin, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t digToHEX(uint8_t digit) {
|
||||||
|
return digitHEX[digit];
|
||||||
|
}
|
||||||
|
|
||||||
|
int GyverTM1637::writeByte(int8_t wr_data)
|
||||||
|
{
|
||||||
|
uint8_t i, count1;
|
||||||
|
for (i = 0; i < 8; i++) //sent 8bit data
|
||||||
|
{
|
||||||
|
digitalWrite(Clkpin, LOW);
|
||||||
|
if (wr_data & 0x01)digitalWrite(Datapin, HIGH); //LSB first
|
||||||
|
else digitalWrite(Datapin, LOW);
|
||||||
|
wr_data >>= 1;
|
||||||
|
digitalWrite(Clkpin, HIGH);
|
||||||
|
|
||||||
|
}
|
||||||
|
digitalWrite(Clkpin, LOW); //wait for the ACK
|
||||||
|
digitalWrite(Datapin, HIGH);
|
||||||
|
digitalWrite(Clkpin, HIGH);
|
||||||
|
pinMode(Datapin, INPUT);
|
||||||
|
|
||||||
|
delayMicroseconds(50);
|
||||||
|
uint8_t ack = digitalRead(Datapin);
|
||||||
|
if (ack == 0)
|
||||||
|
{
|
||||||
|
pinMode(Datapin, OUTPUT);
|
||||||
|
digitalWrite(Datapin, LOW);
|
||||||
|
}
|
||||||
|
delayMicroseconds(50);
|
||||||
|
pinMode(Datapin, OUTPUT);
|
||||||
|
delayMicroseconds(50);
|
||||||
|
|
||||||
|
return ack;
|
||||||
|
}
|
||||||
|
//send start signal to GyverTM1637
|
||||||
|
void GyverTM1637::start(void)
|
||||||
|
{
|
||||||
|
digitalWrite(Clkpin, HIGH); //send start signal to GyverTM1637
|
||||||
|
digitalWrite(Datapin, HIGH);
|
||||||
|
digitalWrite(Datapin, LOW);
|
||||||
|
digitalWrite(Clkpin, LOW);
|
||||||
|
}
|
||||||
|
//End of transmission
|
||||||
|
void GyverTM1637::stop(void)
|
||||||
|
{
|
||||||
|
digitalWrite(Clkpin, LOW);
|
||||||
|
digitalWrite(Datapin, LOW);
|
||||||
|
digitalWrite(Clkpin, HIGH);
|
||||||
|
digitalWrite(Datapin, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************** ФОРМИРУЕМ ДАННЫЕ *****************************
|
||||||
|
void GyverTM1637::display(uint8_t DispData[])
|
||||||
|
{
|
||||||
|
uint8_t SegData[4];
|
||||||
|
for (byte i = 0; i < 4; i ++) {
|
||||||
|
//if (DispData[i] == 0x7f) SegData[i] = 0x00;
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
lastData[i] = digitHEX[DispData[i]];
|
||||||
|
SegData[i] = digitHEX[DispData[i]] + PointData;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
sendArray(SegData);
|
||||||
|
}
|
||||||
|
void GyverTM1637::displayByte(uint8_t DispData[])
|
||||||
|
{
|
||||||
|
uint8_t SegData[4];
|
||||||
|
for (byte i = 0; i < 4; i ++) {
|
||||||
|
//if (DispData[i] == 0x7f) SegData[i] = 0x00;
|
||||||
|
//else SegData[i] = DispData[i];
|
||||||
|
//{
|
||||||
|
lastData[i] = DispData[i];
|
||||||
|
SegData[i] = DispData[i] + PointData;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
sendArray(SegData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::display(uint8_t BitAddr, uint8_t DispData)
|
||||||
|
{
|
||||||
|
uint8_t SegData;
|
||||||
|
//if (DispData == 0x7f) SegData = 0x00;
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
lastData[BitAddr] = digitHEX[DispData];
|
||||||
|
SegData = digitHEX[DispData] + PointData;
|
||||||
|
//}
|
||||||
|
sendByte(BitAddr, SegData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::displayByte(uint8_t BitAddr, uint8_t DispData)
|
||||||
|
{
|
||||||
|
uint8_t SegData;
|
||||||
|
//if (DispData == 0x7f) SegData = 0x00;
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
lastData[BitAddr] = DispData;
|
||||||
|
SegData = DispData + PointData;
|
||||||
|
//}
|
||||||
|
sendByte(BitAddr, SegData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************** ОТПРАВКА НА ДИСПЛЕЙ *****************************
|
||||||
|
void GyverTM1637::sendByte(uint8_t BitAddr, int8_t sendData) {
|
||||||
|
start(); //start signal sent to GyverTM1637 from MCU
|
||||||
|
writeByte(ADDR_FIXED);//
|
||||||
|
stop(); //
|
||||||
|
start(); //
|
||||||
|
writeByte(BitAddr | 0xc0); //
|
||||||
|
writeByte(sendData);//
|
||||||
|
stop(); //
|
||||||
|
start(); //
|
||||||
|
writeByte(Cmd_DispCtrl);//
|
||||||
|
stop(); //
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::sendArray(uint8_t sendData[]) {
|
||||||
|
start(); //start signal sent to GyverTM1637 from MCU
|
||||||
|
writeByte(ADDR_AUTO);//
|
||||||
|
stop(); //
|
||||||
|
start(); //
|
||||||
|
writeByte(Cmd_SetAddr);//
|
||||||
|
for (byte i = 0; i < 4; i ++) {
|
||||||
|
writeByte(sendData[i]); //
|
||||||
|
}
|
||||||
|
stop(); //
|
||||||
|
start(); //
|
||||||
|
writeByte(Cmd_DispCtrl);//
|
||||||
|
stop(); //
|
||||||
|
}
|
||||||
|
// ******************************************
|
||||||
|
void GyverTM1637::displayByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3) {
|
||||||
|
uint8_t dispArray[] = {bit0, bit1, bit2, bit3};
|
||||||
|
displayByte(dispArray);
|
||||||
|
}
|
||||||
|
void GyverTM1637::display(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3) {
|
||||||
|
uint8_t dispArray[] = {bit0, bit1, bit2, bit3};
|
||||||
|
display(dispArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::clear(void)
|
||||||
|
{
|
||||||
|
display(0x00, 0x7f);
|
||||||
|
display(0x01, 0x7f);
|
||||||
|
display(0x02, 0x7f);
|
||||||
|
display(0x03, 0x7f);
|
||||||
|
lastData[0] = 0x00;
|
||||||
|
lastData[1] = 0x00;
|
||||||
|
lastData[2] = 0x00;
|
||||||
|
lastData[3] = 0x00;
|
||||||
|
}
|
||||||
|
void GyverTM1637::update(void)
|
||||||
|
{
|
||||||
|
displayByte(lastData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::brightness(uint8_t brightness, uint8_t SetData, uint8_t SetAddr)
|
||||||
|
{
|
||||||
|
Cmd_SetData = SetData;
|
||||||
|
Cmd_SetAddr = SetAddr;
|
||||||
|
Cmd_DispCtrl = 0x88 + brightness;//Set the brightness and it takes effect the next time it displays.
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GyverTM1637::point(boolean PointFlag)
|
||||||
|
{
|
||||||
|
if (PointFlag) PointData = 0x80;
|
||||||
|
else PointData = 0;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************** ВСЯКИЕ ФУНКЦИИ *****************************
|
||||||
|
void GyverTM1637::displayClock(uint8_t hrs, uint8_t mins) {
|
||||||
|
if (hrs > 99 || mins > 99) return;
|
||||||
|
uint8_t disp_time[4];
|
||||||
|
if ((hrs / 10) == 0) disp_time[0] = 10;
|
||||||
|
else disp_time[0] = (hrs / 10);
|
||||||
|
disp_time[1] = hrs % 10;
|
||||||
|
disp_time[2] = mins / 10;
|
||||||
|
disp_time[3] = mins % 10;
|
||||||
|
GyverTM1637::display(disp_time);
|
||||||
|
}
|
||||||
|
void GyverTM1637::displayClockScroll(uint8_t hrs, uint8_t mins, int delayms) {
|
||||||
|
if (hrs > 99 || mins > 99) return;
|
||||||
|
uint8_t disp_time[4];
|
||||||
|
if ((hrs / 10) == 0) disp_time[0] = 10;
|
||||||
|
else disp_time[0] = (hrs / 10);
|
||||||
|
disp_time[1] = hrs % 10;
|
||||||
|
disp_time[2] = mins / 10;
|
||||||
|
disp_time[3] = mins % 10;
|
||||||
|
scroll(disp_time, delayms);
|
||||||
|
}
|
||||||
|
void GyverTM1637::displayClockTwist(uint8_t hrs, uint8_t mins, int delayms) {
|
||||||
|
if (hrs > 99 || mins > 99) return;
|
||||||
|
uint8_t disp_time[4];
|
||||||
|
if ((hrs / 10) == 0) disp_time[0] = 10;
|
||||||
|
else disp_time[0] = (hrs / 10);
|
||||||
|
disp_time[1] = hrs % 10;
|
||||||
|
disp_time[2] = mins / 10;
|
||||||
|
disp_time[3] = mins % 10;
|
||||||
|
twist(disp_time, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::displayInt(int value) {
|
||||||
|
if (value > 9999 || value < -999) return;
|
||||||
|
boolean negative = false;
|
||||||
|
boolean neg_flag = false;
|
||||||
|
byte digits[4];
|
||||||
|
if (value < 0) negative = true;
|
||||||
|
value = abs(value);
|
||||||
|
digits[0] = (int)value / 1000; // количесто тысяч в числе
|
||||||
|
uint16_t b = (int)digits[0] * 1000; // вспомогательная переменная
|
||||||
|
digits[1] = ((int)value - b) / 100; // получем количество сотен
|
||||||
|
b += digits[1] * 100; // суммируем сотни и тысячи
|
||||||
|
digits[2] = (int)(value - b) / 10; // получем десятки
|
||||||
|
b += digits[2] * 10; // сумма тысяч, сотен и десятков
|
||||||
|
digits[3] = value - b; // получаем количество единиц
|
||||||
|
|
||||||
|
if (!negative) {
|
||||||
|
for (byte i = 0; i < 3; i++) {
|
||||||
|
if (digits[i] == 0) digits[i] = 10;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (byte i = 0; i < 3; i++) {
|
||||||
|
if (digits[i] == 0) {
|
||||||
|
if (digits[i + 1] == 0){
|
||||||
|
digits[i] = 10;
|
||||||
|
} else {
|
||||||
|
digits[i] = 11;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GyverTM1637::display(digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::runningString(uint8_t DispData[], byte amount, int delayMs) {
|
||||||
|
uint8_t segm_data[amount + 8]; // оставляем место для 4х пустых слотов в начале и в конце
|
||||||
|
for (byte i = 0; i < 4; i++) { // делаем первые 4 символа пустыми
|
||||||
|
segm_data[i] = 0x00;
|
||||||
|
}
|
||||||
|
for (byte i = 0; i < amount; i++) { // далее забиваем тем что на входе (сам текст строки)
|
||||||
|
segm_data[i + 4] = DispData[i];
|
||||||
|
}
|
||||||
|
for (byte i = amount + 4; i < amount + 8; i++) { // и последние 4 тоже забиваем пустыми символами
|
||||||
|
segm_data[i] = 0x00;
|
||||||
|
}
|
||||||
|
for (byte i = 0; i <= amount + 4; i++) { // выводим
|
||||||
|
displayByte(segm_data[i], segm_data[i + 1], segm_data[i + 2], segm_data[i + 3]);
|
||||||
|
delay(delayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GyverTM1637::scroll(uint8_t DispData[], int delayms) {
|
||||||
|
byte DispDataByte[4];
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
DispDataByte[i] = digitHEX[DispData[i]];
|
||||||
|
}
|
||||||
|
scrollByte(DispDataByte, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::scroll(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms) {
|
||||||
|
byte DispData[] = {digitHEX[bit0], digitHEX[bit1], digitHEX[bit2], digitHEX[bit3]};
|
||||||
|
GyverTM1637::scrollByte(DispData, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::scroll(uint8_t BitAddr, uint8_t DispData, int delayms) {
|
||||||
|
byte DispDataByte = digitHEX[DispData];
|
||||||
|
scrollByte(BitAddr, DispDataByte, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::scrollByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms) {
|
||||||
|
byte DispData[] = {bit0, bit1, bit2, bit3};
|
||||||
|
GyverTM1637::scrollByte(DispData, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::scrollByte(uint8_t DispData[], int delayms) {
|
||||||
|
byte lastBytes[4];
|
||||||
|
byte step;
|
||||||
|
byte stepArray[4];
|
||||||
|
boolean changeByte[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
if (DispData[i] != lastData[i]) changeByte[i] = 1;
|
||||||
|
lastBytes[i] = lastData[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
byte lastByte = lastData[i];
|
||||||
|
stepArray[i] = lastByte;
|
||||||
|
|
||||||
|
if (changeByte[i]) {
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, lastByte, 6, 0);
|
||||||
|
swapBytes(&step, lastByte, 2, 1);
|
||||||
|
swapBytes(&step, lastByte, 4, 5);
|
||||||
|
swapBytes(&step, lastByte, 3, 6);
|
||||||
|
stepArray[i] = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
byte lastByte = lastBytes[i];
|
||||||
|
stepArray[i] = lastByte;
|
||||||
|
|
||||||
|
if (changeByte[i]) {
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, lastByte, 3, 0);
|
||||||
|
stepArray[i] = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
if (changeByte[i]) {
|
||||||
|
stepArray[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
byte lastByte = lastBytes[i];
|
||||||
|
byte newByte = DispData[i];
|
||||||
|
stepArray[i] = lastByte;
|
||||||
|
|
||||||
|
if (changeByte[i]) {
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, newByte, 0, 3);
|
||||||
|
stepArray[i] = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
byte newByte = DispData[i];
|
||||||
|
stepArray[i] = lastBytes[i];
|
||||||
|
|
||||||
|
if (changeByte[i]) {
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, newByte, 0, 6);
|
||||||
|
swapBytes(&step, newByte, 1, 2);
|
||||||
|
swapBytes(&step, newByte, 5, 4);
|
||||||
|
swapBytes(&step, newByte, 6, 3);
|
||||||
|
stepArray[i] = step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
displayByte(DispData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::scrollByte(uint8_t BitAddr, uint8_t DispData, int delayms) {
|
||||||
|
byte oldByte = lastData[BitAddr];
|
||||||
|
byte newByte = DispData;
|
||||||
|
byte step;
|
||||||
|
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, oldByte, 6, 0);
|
||||||
|
swapBytes(&step, oldByte, 2, 1);
|
||||||
|
swapBytes(&step, oldByte, 4, 5);
|
||||||
|
swapBytes(&step, oldByte, 3, 6);
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, oldByte, 3, 0);
|
||||||
|
swapBytes(&step, newByte, 0, 3);
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
step = 0;
|
||||||
|
swapBytes(&step, newByte, 0, 6);
|
||||||
|
swapBytes(&step, newByte, 1, 2);
|
||||||
|
swapBytes(&step, newByte, 5, 4);
|
||||||
|
swapBytes(&step, newByte, 6, 3);
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
|
||||||
|
displayByte(BitAddr, newByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swapBytes(byte* newByte, byte oldByte, byte newP, byte oldP) {
|
||||||
|
byte newBit = 0;
|
||||||
|
if (oldByte & (1 << oldP)) newBit = 1;
|
||||||
|
else newBit = 0;
|
||||||
|
*newByte = *newByte | (newBit << newP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twist(uint8_t BitAddr, uint8_t DispData, int delayms) {
|
||||||
|
twistByte(BitAddr, digitHEX[DispData], delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twist(uint8_t DispData[], int delayms) {
|
||||||
|
byte newData[4];
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
newData[i] = digitHEX[DispData[i]];
|
||||||
|
}
|
||||||
|
twistByte(newData, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twist(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms) {
|
||||||
|
byte DispData[] = {digitHEX[bit0], digitHEX[bit1], digitHEX[bit2], digitHEX[bit3]};
|
||||||
|
GyverTM1637::twistByte(DispData, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twistByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms) {
|
||||||
|
byte DispData[] = {bit0, bit1, bit2, bit3};
|
||||||
|
GyverTM1637::twistByte(DispData, delayms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twistByte(uint8_t DispData[], int delayms) {
|
||||||
|
byte step;
|
||||||
|
byte stepArray[4];
|
||||||
|
boolean changeByte[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
if (DispData[i] != lastData[i]) changeByte[i] = 1;
|
||||||
|
stepArray[i] = DispData[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
step = step & 0b00111111; // выкл центральную
|
||||||
|
for (byte i = 0; i < 5; i++) {
|
||||||
|
step |= (1 << i); // зажигаем по одной
|
||||||
|
for (byte k = 0; k < 4; k++) {
|
||||||
|
if (changeByte[k])
|
||||||
|
stepArray[k] = step;
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
//for (byte r = 0; r < 1; r++) {
|
||||||
|
for (byte i = 0; i < 6; i++) {
|
||||||
|
step = 0b11000000;
|
||||||
|
step = ~(step | (1 << i) | (1 << i + 1)); // бегает дырка
|
||||||
|
for (byte k = 0; k < 4; k++) {
|
||||||
|
if (changeByte[k]) stepArray[k] = step;
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
step = 0b11000000;
|
||||||
|
for (byte i = 0; i < 6; i++) {
|
||||||
|
step |= (1 << i);
|
||||||
|
for (byte k = 0; k < 4; k++) {
|
||||||
|
if (changeByte[k])
|
||||||
|
stepArray[k] = ~step;
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
for (byte k = 0; k < 4; k++) {
|
||||||
|
if (changeByte[k])
|
||||||
|
stepArray[k] = 0b0000000;
|
||||||
|
}
|
||||||
|
for (byte i = 0; i < 7; i++) {
|
||||||
|
for (byte k = 0; k < 4; k++) {
|
||||||
|
if (changeByte[k]) {
|
||||||
|
byte newBit = 0;
|
||||||
|
if (DispData[k] & (1 << i)) newBit = 1;
|
||||||
|
else newBit = 0;
|
||||||
|
stepArray[k] |= (newBit << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayByte(stepArray);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GyverTM1637::twistByte(uint8_t BitAddr, uint8_t DispData, int delayms) {
|
||||||
|
byte oldByte = lastData[BitAddr];
|
||||||
|
byte newByte = DispData;
|
||||||
|
byte step = oldByte;
|
||||||
|
|
||||||
|
step = step & 0b0111111; // выкл центральную
|
||||||
|
|
||||||
|
for (byte i = 0; i < 5; i++) {
|
||||||
|
step |= (1 << i); // зажигаем по одной
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
//for (byte r = 0; r < 1; r++) {
|
||||||
|
for (byte i = 0; i < 6; i++) {
|
||||||
|
step = 0b1000000;
|
||||||
|
step = ~(step | (1 << i) | (1 << i + 1)); // бегает дырка
|
||||||
|
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
//}
|
||||||
|
step = 0b1000000;
|
||||||
|
for (byte i = 0; i < 6; i++) {
|
||||||
|
step |= (1 << i);
|
||||||
|
displayByte(BitAddr, ~step);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
step = 0;
|
||||||
|
for (byte i = 0; i < 7; i++) {
|
||||||
|
byte newBit = 0;
|
||||||
|
if (newByte & (1 << i)) newBit = 1;
|
||||||
|
else newBit = 0;
|
||||||
|
step |= (newBit << i);
|
||||||
|
displayByte(BitAddr, step);
|
||||||
|
delay(delayms);
|
||||||
|
}
|
||||||
|
displayByte(BitAddr, newByte);
|
||||||
|
}
|
||||||
214
libraries/GyverTM1637/src/GyverTM1637.h
Normal file
214
libraries/GyverTM1637/src/GyverTM1637.h
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
GyverTM1637 - бибилотека для 7 сегментного дисплея на чипе TM1637 с кучей приколюх
|
||||||
|
Документация:
|
||||||
|
GitHub: https://github.com/GyverLibs/GyverTM1637
|
||||||
|
Возможности:
|
||||||
|
- Вывод цифр массивом или прицельно
|
||||||
|
- Вывод букв из списка доступных (листай ниже) массивом или прицельно
|
||||||
|
- Отдельная функция вывода часов и минут (часы без нуля слева, минуты с нулём)
|
||||||
|
- Вывод числа от -999 до 9999 с учётом знака
|
||||||
|
- Готовая функция бегущей строки
|
||||||
|
- Функции смены яркости и состояния двоеточия автоматически обновляют дисплей
|
||||||
|
- Функция обновления значения с эффектом вертикальной прокрутки
|
||||||
|
- Функция обновления значения с эффектом скручивания (лучше один раз увидеть)
|
||||||
|
|
||||||
|
AlexGyver, alex@alexgyver.ru
|
||||||
|
https://alexgyver.ru/
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Основано на оригинальной библиотеке "Grove_4Digital_Display" от Frankie.Chu
|
||||||
|
https://github.com/Seeed-Studio/Grove_4Digital_Display
|
||||||
|
|
||||||
|
Версии:
|
||||||
|
v1.4 - поправлены типы данных и ошибки, добавлена совместимость с ESP
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GyverTM1637_h
|
||||||
|
#define GyverTM1637_h
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <Arduino.h>
|
||||||
|
class GyverTM1637 {
|
||||||
|
public:
|
||||||
|
|
||||||
|
GyverTM1637(uint8_t clk, uint8_t dio); // объявление и инициализация
|
||||||
|
|
||||||
|
void display(uint8_t DispData[]); // выводит цифры массивом по ячейкам. От 0 до 9 (byte values[] = {3, 5, 9, 0}; )
|
||||||
|
void display(uint8_t BitAddr, uint8_t DispData); // выводит цифру DispData в указанную ячейку дисплея BitAddr
|
||||||
|
void display(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3); // если лень создавать массив, выводит цифры в ячейки
|
||||||
|
|
||||||
|
void displayByte(uint8_t DispData[]); // выводит байт вида 0xe6 и буквы-константы вида _a , _b .... массивом
|
||||||
|
void displayByte(uint8_t BitAddr, uint8_t DispData); // выводит байт вида 0xe6 и буквы-константы вида _a , _b .... в ячейку
|
||||||
|
void displayByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3); // если лень создавать массив, выводит байты в ячейки
|
||||||
|
|
||||||
|
void displayClock(uint8_t hrs, uint8_t mins); // выводит часы и минуты
|
||||||
|
void displayClockScroll(uint8_t hrs, uint8_t mins, int delayms); // выводит часы и минуты с эффектом прокрутки
|
||||||
|
void displayClockTwist(uint8_t hrs, uint8_t mins, int delayms); // выводит часы и минуты с эффектом скрутки
|
||||||
|
|
||||||
|
void displayInt(int value); // выводит число от -999 до 9999 (да, со знаком минус)
|
||||||
|
|
||||||
|
void runningString(uint8_t DispData[], byte amount, int delayMs); // бегущая строка (array, sizeof(array), задержка в мс)
|
||||||
|
|
||||||
|
void clear(void); // очистить дисплей
|
||||||
|
|
||||||
|
void point(boolean PointFlag); // вкл / выкл точку (POINT_ON / POINT_OFF)
|
||||||
|
|
||||||
|
void brightness(uint8_t bright, uint8_t = 0x40, uint8_t = 0xc0); // яркость 0 - 7
|
||||||
|
|
||||||
|
void scroll(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение прокруткой (адрес, ЦИФРА, задержка в мс)
|
||||||
|
void scroll(uint8_t DispData[], int delayms); // обновить значение прокруткой (массив ЦИФР, задержка в мс)
|
||||||
|
void scroll(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // прокрутка посимвольно
|
||||||
|
void scrollByte(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение прокруткой (адрес, БАЙТ, задержка в мс)
|
||||||
|
void scrollByte(uint8_t DispData[], int delayms); // обновить значение прокруткой (массив БАЙТ, задержка в мс)
|
||||||
|
void scrollByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // прокрутка посимвольно
|
||||||
|
|
||||||
|
void twist(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение скручиванием (адрес, ЦИФРА, задержка в мс)
|
||||||
|
void twist(uint8_t DispData[], int delayms); // обновить значение скручиванием (массив ЦИФР, задержка в мс)
|
||||||
|
void twist(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // скрутка посимвольно
|
||||||
|
void twistByte(uint8_t BitAddr, uint8_t DispData, int delayms); // обновить значение скручиванием (адрес, БАЙТ, задержка в мс)
|
||||||
|
void twistByte(uint8_t DispData[], int delayms); // обновить значение скручиванием (массив БАЙТ, задержка в мс)
|
||||||
|
void twistByte(uint8_t bit0, uint8_t bit1, uint8_t bit2, uint8_t bit3, int delayms); // скрутка посимвольно
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t lastData[4];
|
||||||
|
void update();
|
||||||
|
int writeByte(int8_t wr_data);
|
||||||
|
void start(void);
|
||||||
|
void stop(void);
|
||||||
|
|
||||||
|
void sendByte(uint8_t BitAddr, int8_t sendData);
|
||||||
|
void sendArray(uint8_t sendData[]);
|
||||||
|
|
||||||
|
uint8_t Cmd_SetData;
|
||||||
|
uint8_t Cmd_SetAddr;
|
||||||
|
uint8_t Cmd_DispCtrl;
|
||||||
|
uint8_t PointData;
|
||||||
|
|
||||||
|
uint8_t Clkpin;
|
||||||
|
uint8_t Datapin;
|
||||||
|
};
|
||||||
|
|
||||||
|
void swapBytes(byte* newByte, byte oldByte, byte oldP, byte newP);
|
||||||
|
uint8_t digToHEX(uint8_t digit); // вернёт код цифры для displayByte
|
||||||
|
|
||||||
|
//************definitions for TM1637*********************
|
||||||
|
#define ADDR_AUTO 0x40
|
||||||
|
#define ADDR_FIXED 0x44
|
||||||
|
#define STARTADDR 0xc0
|
||||||
|
|
||||||
|
/**** definitions for the clock point of the digit tube *******/
|
||||||
|
#define POINT_ON 1
|
||||||
|
#define POINT_OFF 0
|
||||||
|
|
||||||
|
/**************definitions for brightness***********************/
|
||||||
|
#define BRIGHT_DARKEST 0
|
||||||
|
#define BRIGHT_TYPICAL 2
|
||||||
|
#define BRIGHTEST 7
|
||||||
|
|
||||||
|
/************** БУКВЫ И СИМВОЛЫ *****************/
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
|
#define _A 0x77
|
||||||
|
#define _B 0x7f
|
||||||
|
#define _C 0x39
|
||||||
|
#define _D 0x3f
|
||||||
|
#define _E 0x79
|
||||||
|
#define _F 0x71
|
||||||
|
#define _G 0x3d
|
||||||
|
#define _H 0x76
|
||||||
|
#define _J 0x1e
|
||||||
|
#define _L 0x38
|
||||||
|
#define _N 0x37
|
||||||
|
#define _O 0x3f
|
||||||
|
#define _P 0x73
|
||||||
|
#define _S 0x6d
|
||||||
|
#define _U 0x3e
|
||||||
|
#define _Y 0x6e
|
||||||
|
#define _a 0x5f
|
||||||
|
#define _b 0x7c
|
||||||
|
#define _c 0x58
|
||||||
|
#define _d 0x5e
|
||||||
|
#define _e 0x7b
|
||||||
|
#define _f 0x71
|
||||||
|
#define _h 0x74
|
||||||
|
#define _i 0x10
|
||||||
|
#define _j 0x0e
|
||||||
|
#define _l 0x06
|
||||||
|
#define _n 0x54
|
||||||
|
#define _o 0x5c
|
||||||
|
#define _q 0x67
|
||||||
|
#define _r 0x50
|
||||||
|
#define _t 0x78
|
||||||
|
#define _u 0x1c
|
||||||
|
#define _y 0x6e
|
||||||
|
#define _dash 0x40
|
||||||
|
#define _under 0x08
|
||||||
|
#define _equal 0x48
|
||||||
|
#define _empty 0x00
|
||||||
|
#define _degree 0x63
|
||||||
|
|
||||||
|
#define _0 0x3f
|
||||||
|
#define _1 0x06
|
||||||
|
#define _2 0x5b
|
||||||
|
#define _3 0x4f
|
||||||
|
#define _4 0x66
|
||||||
|
#define _5 0x6d
|
||||||
|
#define _6 0x7d
|
||||||
|
#define _7 0x07
|
||||||
|
#define _8 0x7f
|
||||||
|
#define _9 0x6f
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
enum TM1637_letters {
|
||||||
|
_A = 0x77,
|
||||||
|
_B = 0x7f,
|
||||||
|
_C = 0x39,
|
||||||
|
_D = 0x3f,
|
||||||
|
_E = 0x79,
|
||||||
|
_F = 0x71,
|
||||||
|
_G = 0x3d,
|
||||||
|
_H = 0x76,
|
||||||
|
_J = 0x1e,
|
||||||
|
_L = 0x38,
|
||||||
|
_N = 0x37,
|
||||||
|
_O = 0x3f,
|
||||||
|
_P = 0x73,
|
||||||
|
_S = 0x6d,
|
||||||
|
_U = 0x3e,
|
||||||
|
_Y = 0x6e,
|
||||||
|
_a = 0x5f,
|
||||||
|
_b = 0x7c,
|
||||||
|
_c = 0x58,
|
||||||
|
_d = 0x5e,
|
||||||
|
_e = 0x7b,
|
||||||
|
_f = 0x71,
|
||||||
|
_h = 0x74,
|
||||||
|
_i = 0x10,
|
||||||
|
_j = 0x0e,
|
||||||
|
_l = 0x06,
|
||||||
|
_n = 0x54,
|
||||||
|
_o = 0x5c,
|
||||||
|
_q = 0x67,
|
||||||
|
_r = 0x50,
|
||||||
|
_t = 0x78,
|
||||||
|
_u = 0x1c,
|
||||||
|
_y = 0x6e,
|
||||||
|
_dash = 0x40,
|
||||||
|
_under = 0x08,
|
||||||
|
_equal = 0x48,
|
||||||
|
_empty = 0x00,
|
||||||
|
_degree = 0x63,
|
||||||
|
|
||||||
|
_0 = 0x3f,
|
||||||
|
_1 = 0x06,
|
||||||
|
_2 = 0x5b,
|
||||||
|
_3 = 0x4f,
|
||||||
|
_4 = 0x66,
|
||||||
|
_5 = 0x6d,
|
||||||
|
_6 = 0x7d,
|
||||||
|
_7 = 0x07,
|
||||||
|
_8 = 0x7f,
|
||||||
|
_9 = 0x6f,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user