/* ================= ПОДКЛЮЧЕНИЕ БИБЛЕОТЕК ================ */
//#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_SoftServo.h>
#include <EEPROM.h>
/* ======================= КОНСТАНТЫ ====================== */
#define EEPROM_defKey 35 // Ключ проверки наличия данных в EEPROM
#define EEPROM_defKey_Address 1 // Адресс EEPROM в котором хранится ключ defKey
#define WORK_MIN 1 // Минимальное значение режимов работы \ 1 - ручной режим
#define WORK_MAX 2 // Максимальное значение режимов работы \ 2 - авто режим, с интервалом сработки PAUSE
#define WORK_default 1 // Значение по умолчанию паузы для полного открытия\закрытия сервы
#define PAUSE_first 1111 // пауза при инициалицации устройств // после включения
#define PAUSE_MIN 1000 // Минимальное значение паузы для между срабатыванием сервы в автоматическом режиме
#define PAUSE_MAX 10000 // Максимальное значение паузы для между срабатыванием сервы в автоматическом режиме
#define PAUSE_default 5500 // Значение по умолчанию паузы для между срабатыванием сервы в автоматическом режиме
#define EEPROM_PAUSE_Address 10 // Адресс EEPROM в котором хранится значение паузы
#define SPEED_MIN 1 // Минимальное значение угла положения сервы
#define SPEED_MAX 11 // Максимальное значение угла положения сервы
#define SPEED_default 5 // Значение по умолчанию угла положения сервы
#define EEPROM_SPEED_Address 20 // Адресс EEPROM в котором хранится значение угла сервы
#define DOWN_MIN 1 // Минимальное значение угла положения сервы
#define DOWN_MAX 180 // Максимальное значение угла положения сервы
#define DOWN_default 173 // Значение по умолчанию угла положения сервы
#define EEPROM_DOWN_Address 30 // Адресс EEPROM в котором хранится значение угла сервы
#define UP_MIN 1 // Минимальное значение угла положения сервы
#define UP_MAX 180 // Максимальное значение угла положения сервы
#define UP_default 33 // Значение по умолчанию угла положения сервы
#define EEPROM_UP_Address 40 // Адресс EEPROM в котором хранится значение угла сервы
/* ================== ОБЪЯВЛЕНИЕ ОБЪЕКТОВ ================= */
/* ======================================================== */
/* ===================== СЕРВОПРИВОД ====================== */
#define SERVO_Pin 11 // определение порта подключения сервы I
Adafruit_SoftServo SERVO; // создание объекта сервопривод I
/* ======================== КНОПКА ======================== */
#define BUTTON_Pin 2 // определение порта подключения кнопки
/* ======================== ЭНКОДЕР ======================= */
#define Encoder_CLK_Pin A0 // определение порта подключения энкодкра (поворот в лево)
#define Encoder_DT_Pin A1 // определение порта подключения энкодкра (поворот в право)
#define Encoder_SW_Pin A2 // определение порта подключения энкодкра (клик)
/* ======================== ДИСПЛЕЙ ======================= */
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
/* ====================== ПЕРЕМЕННЫЕ ====================== */
typedef enum {
WORK,
Set_PAUSE,
Set_SPEED,
Set_DOWN,
Set_UP,
} Mode;
Mode mode = WORK;
int8_t prevClk = HIGH;
int8_t lastState = HIGH;
int16_t Counter = 0;
uint16_t WORK_Vol;
uint16_t PAUSE_Vol;
uint16_t SPEED_Vol;
uint16_t DOWN_Vol;
uint16_t UP_Vol;
int8_t DIR_Vol = 1; // направление движение сервы // 1 по часовой // -1 против часовой
uint32_t POS_Vol = 0; // позиция сервы
/* ======================== ФУНКЦИИ ======================== */
bool debounceRead(uint8_t Pin, bool Level) { // антидребезг кнопки
const uint8_t DEBOUNCE_TIME = 20; // время сработки кнопки не чаще чем 1 раз в XXмс
static bool dLastBTN = false;
static uint32_t dLastTime;
bool dBTN = digitalRead(Pin) == Level;
if (dBTN != dLastBTN) {
dLastBTN = dBTN;
dLastTime = millis();
} else {
if (millis() - dLastTime >= DEBOUNCE_TIME) {
return dBTN;
}
}
return false;
}
bool SERVOActive() {
SERVO.write(POS_Vol); // двигаем серву
SERVO.refresh();
POS_Vol = POS_Vol + 1 * DIR_Vol; // задаем следующий шаг
if (POS_Vol >= DOWN_Vol) { DIR_Vol = -1; Counter ++; updateDisplay(); } // если серва докатилась до нижнего значения меняем направление
if (POS_Vol <= UP_Vol) { DIR_Vol = 1; } // если серва докатилась до верхнего значения меняем направление
if (POS_Vol != UP_Vol) { return true; } else { return false; } // если серва не в верхней точке значит она еще двигается
}
void setup() {
pinMode(BUTTON_Pin, INPUT_PULLUP); // Инициализация кнопки
pinMode(Encoder_CLK_Pin, INPUT); // Инициализация эгкодера
pinMode(Encoder_DT_Pin, INPUT); // Инициализация эгкодера
pinMode(Encoder_SW_Pin, INPUT_PULLUP); // Инициализация эгкодера
SERVO.attach(SERVO_Pin); // Инициализация сервы
initDisplay(); // Инициализация дисплея
EEPROMdefVol(); // Чтение переменных EEPROM
WORK_Vol = WORK_default;
POS_Vol = UP_Vol;
SERVOActive(); //Перевод сервы в крайнее верхнее положение
delay(PAUSE_first);
}
void loop() {
static uint32_t modeLastChanged;
static uint32_t previousMillis; // предыдущее время
static bool Move_SERVO = false; // false - серва не работает // true - серва работает
static bool LastBTN = false; // предыдущее состояние кнопки
if (digitalRead(Encoder_SW_Pin) == LOW && millis() - modeLastChanged >= 300) {
modeLastChanged = millis();
nextMode();
updateDisplay();
}
int8_t clk = digitalRead(Encoder_CLK_Pin);
if (clk != prevClk && clk == LOW) {
int8_t dt = digitalRead(Encoder_DT_Pin);
int8_t delta = dt == HIGH ? 1 : -1;
updateValue(delta);
updateDisplay();
}
prevClk = clk;
if (mode == WORK) {
if (Move_SERVO == false) { // если серва не работает
bool BTN = debounceRead(BUTTON_Pin, LOW); // опрашиваем кнопку
if (BTN != LastBTN) {
LastBTN = BTN; // если её состояние изменилось изменяем переменную состояния
if (BTN == true) { Move_SERVO = true; } // если кнопка нажата даем разрешение н движение сервы
}
if (WORK_Vol == 2 && Move_SERVO == false && millis() - previousMillis >= PAUSE_Vol) { // если тумблер включен и серва не двигается а также прошло времени больше заданного интервала
previousMillis = millis(); // запоминаем время
Move_SERVO = true; // даем разрешение на движение сервы
}
}
if (Move_SERVO == true && millis() - previousMillis >= SPEED_Vol) { // если разрешено движение сервы и прошло время микро задержки для плавности хода
previousMillis = millis(); // запоминаем время
Move_SERVO = SERVOActive(); // двигаем серву, опрашивая её позицию
}
}
}
void EEPROMdefVol() {
int8_t defKey = 0;
EEPROM.get(EEPROM_defKey_Address, defKey);
if (defKey != EEPROM_defKey) {
EEPROM.put(EEPROM_defKey_Address, EEPROM_defKey);
EEPROM.put(EEPROM_SPEED_Address, SPEED_default);
EEPROM.put(EEPROM_UP_Address, UP_default);
EEPROM.put(EEPROM_DOWN_Address, DOWN_default);
EEPROM.put(EEPROM_PAUSE_Address, PAUSE_default);
}
EEPROM.get(EEPROM_SPEED_Address, SPEED_Vol);
EEPROM.get(EEPROM_UP_Address, UP_Vol);
EEPROM.get(EEPROM_DOWN_Address, DOWN_Vol);
EEPROM.get(EEPROM_PAUSE_Address, PAUSE_Vol);
}
void updateDisplay() {
static String STR = "";
static String DIG = "";
static uint16_t Progress;
display.clearDisplay();
switch (mode) {
case WORK:
if (WORK_Vol == 1) {
STR = F("MANUAL WORK");
}
if (WORK_Vol == 2) {
STR = F("AUTO WORK");
}
Progress = map(WORK_Vol, WORK_MIN, WORK_MAX, 0, 101);
DIG = String(Counter);
break;
case Set_PAUSE:
STR = F("PAUSE");
DIG = String(PAUSE_Vol);
Progress = map(PAUSE_Vol, PAUSE_MIN, PAUSE_MAX, 0, 101);
break;
case Set_SPEED:
STR = F("SPEED");
DIG = String(SPEED_Vol);
Progress = map(SPEED_Vol, SPEED_MIN, SPEED_MAX, 0, 101);
break;
case Set_UP:
STR = F("UP");
DIG = String(UP_Vol);
Progress = map(UP_Vol, UP_MIN, UP_MAX, 0, 101);
break;
case Set_DOWN:
STR = F("DOWN");
DIG = String(DOWN_Vol);
Progress = map(DOWN_Vol, DOWN_MIN, DOWN_MAX, 0, 101);
break;
}
display.setCursor((SCREEN_WIDTH - STR.length() * 6) / 2, 13);
display.print(STR);
display.drawRoundRect(10, 26, 102, 9, 2, WHITE);
display.fillRect(11, 27, Progress, 7, WHITE);
display.setCursor((SCREEN_WIDTH - DIG.length() * 6) / 2, 39);
display.print(DIG);
display.display();
}
void nextMode() {
switch (mode) {
case WORK:
mode = Set_PAUSE;
break;
case Set_PAUSE:
mode = Set_SPEED;
break;
case Set_SPEED:
mode = Set_UP;
break;
case Set_UP:
mode = Set_DOWN;
break;
case Set_DOWN:
mode = WORK;
break;
}
}
void updateValue(int8_t delta) {
uint16_t Vol_EEPROM;
switch (mode) {
case WORK:
WORK_Vol = constrain(WORK_Vol + delta, WORK_MIN, WORK_MAX);
break;
case Set_PAUSE:
PAUSE_Vol = constrain(PAUSE_Vol + delta * 100, PAUSE_MIN, PAUSE_MAX);
break;
case Set_SPEED:
SPEED_Vol = constrain(SPEED_Vol + delta, SPEED_MIN, SPEED_MAX);
break;
case Set_DOWN:
DOWN_Vol = constrain(DOWN_Vol + delta, DOWN_MIN, DOWN_MAX);
break;
case Set_UP:
UP_Vol = constrain(UP_Vol + delta, UP_MIN, UP_MAX);
break;
}
EEPROM.get(EEPROM_PAUSE_Address, Vol_EEPROM);
if (Vol_EEPROM != PAUSE_Vol) { EEPROM.put(EEPROM_PAUSE_Address, PAUSE_Vol); }
EEPROM.get(EEPROM_SPEED_Address, Vol_EEPROM);
if (Vol_EEPROM != SPEED_Vol) { EEPROM.put(EEPROM_SPEED_Address, SPEED_Vol); }
EEPROM.get(EEPROM_DOWN_Address, Vol_EEPROM);
if (Vol_EEPROM != DOWN_Vol) { EEPROM.put(EEPROM_DOWN_Address, DOWN_Vol); }
EEPROM.get(EEPROM_UP_Address, Vol_EEPROM);
if (Vol_EEPROM != UP_Vol) { EEPROM.put(EEPROM_UP_Address, UP_Vol); }
}
void initDisplay() { // инициализация дисплея
if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
display.display();
display.clearDisplay();
display.setFont();
display.setTextColor(1);
logobitmap();
}
}
void logobitmap(void) {
#define LOGO_HEIGHT 64
#define LOGO_WIDTH 64
static const unsigned char PROGMEM logo_bmp[] = { B00000000, B00000000, B00000000, B00000111, B11100000, B00000000, B00000000, B00000000,
B00000000, B00000000, B00000001, B11111111, B11111111, B10000000, B00000000, B00000000,
B00000000, B00000000, B00001111, B11111111, B11111111, B11110000, B00000000, B00000000,
B00000000, B00000000, B00111111, B11110000, B00001111, B11111100, B00000000, B00000000,
B00000000, B00000000, B11111111, B00000000, B00000000, B11111111, B00000000, B00000000,
B00000000, B00000001, B11111000, B00000000, B00000000, B00011111, B10000000, B00000000,
B00000000, B00000111, B11100000, B00000000, B00000000, B00000111, B11100000, B00000000,
B00000000, B00001111, B10000000, B00000000, B00000000, B00000001, B11110000, B00000000,
B00000000, B00011111, B00111111, B01111110, B00000000, B00000000, B11111000, B00000000,
B00000000, B00111100, B11111111, B00111111, B11111000, B00000000, B00111100, B00000000,
B00000000, B01111000, B00111110, B00111111, B11111110, B00000000, B00011110, B00000000,
B00000000, B11110000, B00000000, B00111111, B11101111, B11000000, B00001111, B00000000,
B00000001, B11100000, B00000000, B11111111, B11000111, B11110000, B00000111, B10000000,
B00000011, B11000000, B00000011, B11111111, B11000011, B11111100, B00000011, B11000000,
B00000011, B10001100, B00000111, B11111111, B11100011, B11111110, B00000001, B11000000,
B00000111, B10011110, B00001111, B11111011, B11111111, B11111111, B00000001, B11100000,
B00001111, B00011110, B00011111, B11111101, B11111111, B11111111, B10000000, B11110000,
B00001110, B00111111, B00111111, B11111100, B11111111, B11111111, B11000000, B01110000,
B00011110, B00111111, B00111111, B11111110, B11111111, B11111111, B11100000, B01111000,
B00011100, B00111111, B10111111, B11111110, B01111111, B11111111, B11110000, B00111000,
B00111100, B00111111, B10111111, B11111110, B01111111, B11111111, B11111000, B00111100,
B00111000, B00111111, B00011111, B11111111, B00111111, B11111111, B11111000, B00011100,
B00111000, B01111111, B00001111, B11111111, B00011111, B11111111, B11111100, B00011100,
B01111000, B01111111, B00000111, B11111111, B00011111, B11111111, B11111110, B00011110,
B01110000, B00111111, B00000011, B11111111, B00011111, B11111111, B11111110, B00001110,
B01110000, B00111110, B00000001, B11111110, B00001111, B11111111, B11111111, B00001110,
B01110000, B00011100, B00000000, B01111000, B00001111, B11111111, B11111111, B11001110,
B01110000, B00000000, B10001111, B00000000, B00001111, B11111111, B11111111, B11111110,
B01110000, B00000011, B11001111, B11110000, B00000111, B11111111, B11111111, B11001110,
B11100000, B00000011, B11001111, B11111100, B00100111, B11111111, B11111111, B10000111,
B11100000, B00000011, B11001111, B11111100, B00110111, B11111111, B11111111, B10000111,
B11100000, B00000011, B11001111, B11111100, B01110111, B11111111, B11111111, B10000111,
B11100000, B00000011, B11101111, B11111100, B01110111, B11111111, B11111111, B11000111,
B11100000, B00000001, B11101111, B11111100, B11110011, B11111111, B11111111, B11000111,
B11100000, B00000001, B11101111, B11111000, B11111111, B11111111, B11111111, B11000111,
B01100000, B00000001, B11100111, B11111001, B11111111, B11111111, B11111111, B11100110,
B01110000, B00000000, B11110111, B11111001, B11111111, B11111111, B11111111, B11101110,
B01110000, B00000000, B11110111, B11111011, B11111111, B11111111, B11111111, B11101110,
B01110000, B00000011, B01110111, B11110011, B11111111, B11111111, B11111111, B11111110,
B01110000, B00000011, B01111111, B11110011, B11111111, B11111111, B11111111, B11111110,
B01111000, B00000011, B10111011, B11110111, B11111111, B11111111, B11111111, B11111110,
B00111000, B00000111, B10011011, B11110111, B11111111, B11111111, B11111111, B11111100,
B00111000, B00000111, B11001001, B11100111, B11111111, B11111111, B11111111, B11111100,
B00111100, B00000111, B11100000, B01000111, B11111111, B11111111, B11111111, B11111100,
B00011100, B00000111, B11110000, B00001111, B11111111, B11111111, B11111111, B11111000,
B00011110, B00001111, B11111100, B00011111, B11111111, B11111111, B11111111, B11111000,
B00001110, B00001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11110000,
B00001111, B00001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11110000,
B00000111, B10001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11100000,
B00000011, B10001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11000000,
B00000011, B11001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11000000,
B00000001, B11101111, B11111111, B11111111, B11111111, B11111111, B11111111, B10000000,
B00000000, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
B00000000, B01111111, B11111111, B11111111, B11111111, B11111111, B11111110, B00000000,
B00000000, B00111111, B11111111, B11111111, B11111111, B11111111, B11111100, B00000000,
B00000000, B00011111, B11111111, B11111111, B11111111, B11111111, B11111000, B00000000,
B00000000, B00001111, B11111111, B11111111, B11111111, B11111111, B11110000, B00000000,
B00000000, B00000111, B11111111, B11111111, B11111111, B11111111, B11100000, B00000000,
B00000000, B00000001, B11111111, B11111111, B11111111, B11111111, B10000000, B00000000,
B00000000, B00000000, B11111111, B11111111, B11111111, B11111111, B00000000, B00000000,
B00000000, B00000000, B00111111, B11111111, B11111111, B11111100, B00000000, B00000000,
B00000000, B00000000, B00001111, B11111111, B11111111, B11110000, B00000000, B00000000,
B00000000, B00000000, B00000001, B11111111, B11111111, B10000000, B00000000, B00000000,
B00000000, B00000000, B00000000, B00000111, B11100000, B00000000, B00000000, B00000000 };
display.drawBitmap((display.width() - LOGO_WIDTH) / 2, (display.height() - LOGO_HEIGHT) / 2, logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
display.display();
}