/* 
////////////// STEPMOTOR CONTROLLER //////////////
by Asher
*/

#include <LiquidCrystal.h>
#include <EEPROM.h>
#include "GyverStepper2.h"
#include "GyverEncoder.h"

#define PIN_STEP 5
#define PIN_DIR 11
#define PIN_EN 13

#define ENCODER_SW 2     // SW нажатие
#define ENCODER_A_CLK 3  // CLK по часовой
#define ENCODER_B_DT 4   // DT против

#define RS 12
//#define RW 11 // Опционально
#define EN 10
#define DB4 9
#define DB5 8
#define DB6 7
#define DB7 6

LiquidCrystal lcd(RS, EN, DB4, DB5, DB6, DB7);
GStepper2<STEPPER2WIRE> stepper(2048, PIN_STEP, PIN_DIR, PIN_EN);  // (steps, step, dir, en)
Encoder enc1(ENCODER_A_CLK, ENCODER_B_DT, ENCODER_SW);

int32_t setRev = 50;    // Кол-во оборотов
int32_t setVel = 9000;  // Скорость

bool flagStart = false; // start - stop
bool flagEnter = false; // enter - cancel
int posCursor = 3;      // 1-SPEED; 2-REV; 3-START;

byte charCursorOn[8] = { 0b10000, 0b11000, 0b11100, 0b11110, 0b11110, 0b11100, 0b11000, 0b10000 };
byte charCursorOff[8] = { 0b00000, 0b00000, 0b11110, 0b11110, 0b11110, 0b11110, 0b00000, 0b00000 };
byte charArrow1[8] = { 0b00111, 0b00100, 0b00000, 0b00100, 0b01110, 0b11111, 0b00100, 0b00111 };
byte charArrow2[8] = { 0b11100, 0b00100, 0b11111, 0b01110, 0b00100, 0b00000, 0b00100, 0b11100 };

void setup() {

  pinMode(ENCODER_SW, INPUT_PULLUP);
  pinMode(ENCODER_A_CLK, INPUT);
  pinMode(ENCODER_B_DT, INPUT);

  enc1.setType(TYPE2); 
  enc1.setFastTimeout(40);

  /* Настройки из памяти */
  //EEPROM.get(0, setRev);
  //EEPROM.get(2, setVel);

  /* Initialize LCD */
  lcd.createChar(0, charCursorOn);
  lcd.createChar(1, charCursorOff);
  lcd.createChar(2, charArrow1);
  lcd.createChar(3, charArrow2);
  lcd.begin(16, 2);
  printAll();
  
  /* Motor setup */
  stepper.disable();
  stepper.setCurrent(0);          // Начальная позиция
  stepper.setAcceleration(1000);  // Ускорение
  //stepper.setMaxSpeed(5000);
  
}

void loop() {

  /* Шаг */
  motor();

  /* Энкодер */
  enc1.tick();
  if (enc1.isRight()) moveEncoder(1);
  if (enc1.isLeft()) moveEncoder(0);
  if (enc1.isClick()) enterEncoder();
  if (enc1.isHolded()) saveSetting();

  /* Обновление экрана */
  static uint32_t last_time;
  if (millis() - last_time > 200) {
    last_time = millis();
    printCurrent();
  }
}

void moveEncoder(bool dir) {

  if (flagEnter && !flagStart) { 
    switch (posCursor) {

      case 1:
        if (dir == 1 && setVel < 9000) { 
          setVel = setVel + 100; 
          printVel(); 
        }
        if (dir == 0 && setVel > 0) { 
          setVel = setVel - 100; 
          printVel(); 
        }
        break;
      
      case 2:
        if (dir == 1 && setRev < 90000) { 
          setRev = setRev + 10; 
          printRev();
        }
        if (dir == 0 && setRev > 0) { 
          setRev = setRev - 10;
          printRev();
        }
        break;
      
      case 3:
        break;
    
    }

  }

  if (!flagEnter && !flagStart) { 
    if (dir == HIGH && posCursor < 3) { posCursor++; printCursor(); } 
    else if (dir == LOW && posCursor > 1) { posCursor--; printCursor(); } 
    else if (dir == HIGH && posCursor == 3) { posCursor = 1; printCursor(); } 
    else if (dir == LOW && posCursor == 1) { posCursor = 3; printCursor(); }
  }

}

void enterEncoder() {

  flagEnter = !flagEnter;
  printCursor();

  if (posCursor == 3) { 
    flagStart = !flagStart; 
    printMode(); 
  }

}

void saveSetting() {
  if (!flagStart) {
    EEPROM.put(0, setRev);
    EEPROM.put(2, setVel);

    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("SAVE SETTING");

    delay(1000);
    printAll();
  }
}

void printAll() {
  lcd.clear();
  printMenu();
  printVel();
  printRev();
  printCursor();
  printMode();
  //printCurrent(); 
}

void printMenu() {
  lcd.setCursor(1, 0);
  lcd.print("V:");

  lcd.setCursor(9, 0);
  lcd.print("N:");

  lcd.setCursor(10, 1);
  lcd.print(":");

  lcd.setCursor(8, 1);
  lcd.write((byte)2);
  lcd.setCursor(9, 1);
  lcd.write((byte)3);
}

void printVel() {
  lcd.setCursor(3, 0);
  lcd.print("      ");
  lcd.setCursor(3, 0);
  lcd.print(setVel);
}

void printRev() {
  lcd.setCursor(11, 0);
  lcd.print("     ");
  lcd.setCursor(11, 0);
  lcd.print(setRev);
}

void printCursor() {

  lcd.setCursor(0, 0);
  lcd.print(" ");
  lcd.setCursor(8, 0);
  lcd.print(" ");
  lcd.setCursor(0, 1);
  lcd.print(" ");
  lcd.setCursor(0, 0);

  switch (posCursor) {
  case 1: lcd.setCursor(0, 0); break; // SPEED
  case 2: lcd.setCursor(8, 0); break; // REV
  case 3: lcd.setCursor(0, 1); break; // START
  }

  if (flagEnter) { 
    lcd.write((byte)1); 
  } 
  else { 
    lcd.write((byte)0); 
  }

}

void printMode() {

  lcd.setCursor(1, 1);
  lcd.print("     ");

  lcd.setCursor(1, 1);
  if (!flagStart) { 
    lcd.print("START"); 
  } 
  else { 
    lcd.print("STOP"); 
  }

}

void printCurrent() {
  lcd.setCursor(11, 1);
  lcd.print("     ");
  lcd.setCursor(11, 1);
  lcd.print(stepper.getCurrent() / 200);
}

void motor() {

  /* Motor loop */
  if (flagStart) {

    stepper.enable();
    stepper.tick();                   // Старт

    /* Выбор режима двигателя */
    if (setRev > 0) {                 // Режим оборотов
      stepper.setMaxSpeed(setVel);
      stepper.setTarget(setRev*200);  // 2147483647
      
      /* Финиш */
      int posCurrent = stepper.getCurrent();
      if (posCurrent == (setRev*200)) {
        flagStart = !flagStart;
        flagEnter = !flagEnter;
        stepper.setCurrent(0);
        stepper.disable();

        printMode();
        printCursor();
      }

    } else {                          // Режим скорости
      //stepper.setSpeed(setVel);
      stepper.setMaxSpeed(setVel);
      stepper.setTarget(99999);
      int posCurrent = stepper.getCurrent();
      if (posCurrent == 90000) { stepper.setCurrent(0); }
    }

  } else if (setRev == 0) {           // Обнулить счетчик при остоновке, если режим скорости
    stepper.brake();
    //stepper.setCurrent(0);
    stepper.reset();
    stepper.disable();

  } else {
    stepper.brake();
    stepper.disable();
  }

}
A4988