#define modeBtn    A5   // кнопка выбора режима 
#define pinEn      A2   // кнопка энкодера (обрабатывается не библиотекой а как простая кнопка)

#define ledPinBlue  5   // светодиод Синий МОЙКА
#define ledPinGreen 3  // светодиод зеленый ОБДУВ
#define ledPinRed   6   // светодиод Красный ЗАСВЕТКА

#define pinBuzz     7   // пин бузера
#define ledPinFan   8   // выход на обдув ( голубой диод имитирует включение ветиляторов )
#define uvPin       9   // выход на всветодиоды засветки ( фиолетовый диод имитирует включение засветки )


#define stepperDir  10   // A4988   DIR
#define stepperStep 11   // A4988   Step 

#define displayDio A1   // TM1637 пин дисплея DIO
#define displayClk A0   // TM1637 пин дисплея CLK

#define encoderClk A3   // Энкодер CLK
#define encoderDT  A4   // Энкодер DT

#define stepdivide 2    // Пин делителя шагов

#define WashTiime 10    // Время режима мойки по умолчанию минуты
#define DryTime   15    // Время режима сушки по умолчанию минуты
#define UvTime    5     // Время режима засветки по умочанию минуты



#include "GyverTimers.h"   // Поделюченные библиотеки можно посмотреть во вкладке "Library Manager"
#include "GyverTM1637.h"
#include "GyverStepper2.h"
#include <EncButton.h>


GyverTM1637 disp(displayClk, displayDio);                        // CLK, DIO  подключаем дисплей
GStepper2 <STEPPER2WIRE> stepper(400, stepperStep, stepperDir);  // STEP, DIR подключаем шаговик
EncButton<EB_TICK, encoderClk, encoderDT > enc;                  // CLK, TD подключаем энкодер



bool dirstep ;  // направление вращениия шаговика
bool rotor = 1 ; // 

uint32_t Now;      // для  таймера обратного отсчета
boolean flag =0;   // флаг таймера

bool buzz_flag=1;  // флаг бузера должно (быть buzz )

bool flagbri = 1 ;     // для изменения яркости таймера
unsigned long timbri;  // для изменения яркости таймера
bool stready = 1;      // для изменения яркости таймера 


byte mode = 0; // выбор режима
unsigned long last_press; // for button
unsigned long last_pressEn; // for en button
bool button_flag = 0; // флаг кнопки

bool btnEn_flag; // flag encoder
int bri=7; // яркость дисплея
bool dir;
bool dirl;

byte mode1_flag = 0;
bool work =0;

int mins ; // минуты
int sek ;  // секунды

uint8_t bit0 ; // 1 - 4 разряд дисплея
uint8_t bit1 ; 
uint8_t bit2 ;
uint8_t bit3 ;

uint32_t tmr;     // Для плавного мигания светодиодами
int val = 1;
bool dirled = true;

ISR(TIMER1_A) {                         // пускаем шаговик по таймеру
  stepper.tick();
}

void setup() {
 Serial.begin(9600);
  //Timer1.setFrequency(3);               // Высокоточный таймер 1 для первого прерывания, частота - 3 Герца
  Timer1.setPeriod(100);                  // то же самое! Частота 3 Гц это период 333 333 микросекунд
  //Timer1.setFrequencyFloat(4.22);       // Если нужна дробная частота в Гц  
  Timer1.enableISR();                     // Запускаем прерывание (по умолч. канал А)
 
 pinMode(ledPinBlue, OUTPUT);  
 pinMode(ledPinGreen, OUTPUT);
 pinMode(ledPinRed, OUTPUT); 
 pinMode(ledPinFan, OUTPUT); 
 pinMode(stepdivide, OUTPUT); 
 pinMode(modeBtn, INPUT_PULLUP);
 pinMode(uvPin, OUTPUT);
 digitalWrite(stepdivide, LOW);
 digitalWrite(modeBtn, HIGH);
 digitalWrite(ledPinRed, LOW);
 digitalWrite(ledPinBlue, HIGH);
 digitalWrite(ledPinFan, LOW); 
 digitalWrite(uvPin, LOW);
 pinMode(pinEn, INPUT_PULLUP);

  disp.clear();
  disp.brightness(bri);  // яркость, 0 - 7 (минимум - максимум)
  disp.clear();
  disp.point(1);
  disp.displayByte(_8, _8, _8, _8);
  delay(500);
 stepper.setMaxSpeed(1800);     // скорость движения к цели 
 stepper.setAcceleration(600); // ускорение
 stepper.setTarget(0);
 }
  
  

     //  LL        OOOOOOO    OOOOOOO   PPPPPPP
     //  LL       OO     OO  OO     OO  PP    PP
     //  LL       OO     OO  OO     OO  PP    PP
     //  LL       OO     OO  OO     OO  PPPPPP
     //  LLLLLLL   OOOOOOO    OOOOOOO   PP


void loop() {
  
  enc.tick(); // запуск обработки энкодера
  buttonRead(); // запуск обработки кнопок
   

  if (mode==0 && mode1_flag==0)  // выбор  режима работы мойки
  {
    mins=WashTiime;
    sek=0;
    displ();  
    digitalWrite(ledPinBlue, HIGH); 
    digitalWrite(ledPinGreen, LOW);
    digitalWrite(ledPinRed, LOW); 
    mode1_flag = 1; 
  }

  if (mode==1 && mode1_flag==1){  //  выбор режима работы Сушка
    mins=DryTime;
    sek=0;
    displ();
    digitalWrite(ledPinBlue, LOW); 
    digitalWrite(ledPinGreen, HIGH);
    digitalWrite(ledPinRed, LOW);
    mode1_flag = 2;
    
  }

if  (mode==2 && mode1_flag==2){  //  выбор режима работы засветка
    mins=UvTime;
    sek=0;
    displ();
    digitalWrite(ledPinBlue, LOW); 
    digitalWrite(ledPinGreen, LOW);
    digitalWrite(ledPinRed, HIGH);
    mode1_flag = 0;
  }
 

if (mode==0 &&  work==1  )          // режим мойки
  {
    ledblinkB();
    rotorFast();
    timer();
    buzz_flag=1;
    digitalWrite(stepdivide, LOW);  // выключение деления шагов 
  }

if (mode==1 &&  work==1  )          // режим обдува
  {
    ledblinkG();
    rotorSlow();
    timer();
    digitalWrite(stepdivide, HIGH); // включение деления шагов 
    digitalWrite(ledPinFan , HIGH); // включает вентиляторы
    buzz_flag=1;
  }
  
if (mode==2 &&  work==1  )          // режим засвета
  {
    ledblinkR();
    rotorSlow();
    timer();
    digitalWrite(stepdivide, HIGH);
    digitalWrite(uvPin , HIGH);     //включает засвет
    buzz_flag=1;
  }

  
  if (enc.right() && mins>0) {
    mins-- ;    
    displ();
    } // поворот налево
  if (enc.left() &&  mins<99) {
    mins++ ;   // поворот направо
    displ();
    }


 if ( work == 0) {
    if (mode == 0) digitalWrite(ledPinBlue, 255); 
    if (mode == 1) digitalWrite(ledPinGreen, 255);
    if (mode == 2) digitalWrite(ledPinRed, 255);
    val = 1;
    dirled = true;
    digitalWrite(uvPin , LOW); // выключаем засвет 
    digitalWrite(ledPinFan , LOW); // выключаем обдув
    rotor = 1;  // для повтоного запуска шаговика
    stepper.stop();
    //stepper.reset();
    if (stepper.getStatus() == 0) {
        brightness(); // мигаем дисплеем 
        disp.point(true);
    }
   
 }
}
 
     //  LL        OOOOOOO    OOOOOOO   PPPPPPP           EEEEEEEEE   NNN    NN   DDDDDd
     //  LL       OO     OO  OO     OO  PP    PP          EE          NN N   NN   DD    DD
     //  LL       OO     OO  OO     OO  PP    PP          EEEEE       NN  N  NN   DD     DD
     //  LL       OO     OO  OO     OO  PPPPPP            EE          NN   N NN   DD    DD
     //  LLLLLLL   OOOOOOO    OOOOOOO   PP                EEEEEEEEE   NN    NNN   DDDDDd



// Вращение шаговика БЫСТРО туда сюда (режим мойки)
void rotorFast() {
  stepper.setMaxSpeed(1800);     // скорость движения к цели
  stepper.setAcceleration(400);
  if (mins==0 && sek<5) stepper.stop();
  
  if (stepper.ready() || rotor==1 ) {
     rotor=0;
     dirstep=!dirstep;
     stepper.setTarget(dirstep *100000);  
  }
  }


// вращение медленно (сушка, засветка)
void rotorSlow() {
 stepper.setMaxSpeed(50);     // скорость движения к цели
 stepper.setAcceleration(200);
  if (stepper.ready()) stepper.reset(); // если вдруг докрутил до максимального -  с
 stepper.setTarget(2147483647); // тупо максимальное значение
}



//ВЫ ВОД НА ДИСПЛЕЙ
void displ() {
 bit0 = mins/10;
 bit1 = mins % 10;
 bit2 = sek/10;
 bit3 = sek % 10;
 disp.display(bit0,  bit1,  bit2,  bit3); // display taimer 
}


// обработка кнопок
 void buttonRead() {
 bool btn = !digitalRead(modeBtn); 
 bool btnEn = !digitalRead(pinEn);                                    // текеущее положение кнопки
 if (btn == true && button_flag==0 && millis() - last_press > 400) {
  last_press = millis();
  tone(pinBuzz, 4000, 50);
  button_flag = 1;
  mode ++;
  if (mode >2) mode =0;
  work = 0;
  
  }
 if (btn == 0 && button_flag==1) {
  
  button_flag = 0;
}
 if (  btnEn==1 && btnEn_flag == 0  &&  millis()- last_pressEn > 400 ) { 
 last_pressEn = millis();
 tone(pinBuzz, 5000, 50);
 if (work==0) sek++; // Возвращаем украденную таймером секунду
 btnEn_flag = 1;
 work = !work;
  }
 if (  btnEn==0 && btnEn_flag == 1  ) {
 btnEn_flag = 0;
 
  }
}



// ТАЙМЕР

void timer()  {

if (sek ==0 && mins>0) { sek=60;  mins--; }

if (millis() - Now > 1000  &&  ((mins + sek) != 0) ) {
      Now = millis();
      sek--;
      displ();
      flag = !flag;   
      disp.point(flag);   // выкл/выкл точки 
 }

if (mins <0) mins = 59;

if (mins==0 && sek == 0) {                             // если время закончилось
  disp.point(1);                                       // включаем точки
  work=0;
  if (buzz_flag==1)  { 
     tone(pinBuzz, 5000, 500);                         // пищим об окончании
     buzz_flag=0;
     if (mode < 2 )   mode = mode + 1;                // Переключаем на следующий режим
     
  }
}
}






// МИГАЕМ ДИСПЛЕЕМ  
void brightness() {
if ( sek == 0 && mins == 0 && bri != 0 &&  (millis()-timbri)  > 100  && flagbri==1) {
    timbri = millis();
    bri--;
    disp.brightness(bri);
    
  if (  bri == 0 ) flagbri = 0;
  } 
if ( sek == 0 && mins == 0 && bri <= 7 &&  millis() - timbri > 100  && flagbri==0) {
    bri++;
    disp.brightness(bri);
    timbri = millis();
  if (  bri == 7 ) flagbri = 1; 
  } 
if ( mins + sek !=0) disp.brightness(7);
}









//             ПЛАВНО  МИГАЕМ СВЕТОДИОДОМ

void ledblinkR() {
  if (millis() - tmr >5) {
    tmr=millis();
    if ( dirled == true )     val++;
    if ( dirled == false)     val--;  
    if (val == 255 || val == 0) dirled = !dirled;
    analogWrite(ledPinRed, val);
    //Serial.println(val);
  }
}
void ledblinkB() {
  
  if (millis() - tmr > 5) {
    tmr=millis();
    if ( dirled == true )     val++;
    if ( dirled == false)     val--;  
    if (val == 255 || val == 0) dirled = !dirled;
    analogWrite(ledPinBlue, val);
  }
}

void ledblinkG() {
  if (millis() - tmr > 5) {
    tmr = millis();
    if ( dirled == true )     val++;
    if ( dirled == false)     val--;  
    if (val == 255 || val == 0) dirled = !dirled;
    analogWrite(ledPinGreen, val);
  }
}


// Переключеие индикации режимов
void ledMode(){
  if (mode==0)  // выбор  режима работы мойки
  {    
    digitalWrite(ledPinBlue, HIGH); 
    digitalWrite(ledPinGreen, LOW);
    digitalWrite(ledPinRed, LOW);
  }

  if (mode==1){  //  выбор режима работы Сушка
    digitalWrite(ledPinBlue, LOW); 
    digitalWrite(ledPinGreen, HIGH);
    digitalWrite(ledPinRed, LOW);
  }

if   (mode==2){  //  выбор режима работы засветка
    digitalWrite(ledPinBlue, LOW); 
    digitalWrite(ledPinGreen, LOW);
    digitalWrite(ledPinRed, HIGH);
  }
}














A4988
4-Digit Display