// WS
// Coil Winder Arduino MEGA 2560 R3 / Arduino Nano
// Stacker 5000p/r or at screw pitch 5мм = 1000p/mm (Oriental Motor ARD-K ARM66SAK)
// 1мм = 1000p
// Bobin motor Panasonic Minas A5 200W 1000p/r

#include <Keypad.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);  // Conected via I2C, pins 20, 21

// Keyboard
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};
byte rowPins[ROWS] = { 31, 33, 35, 37 };
byte colPins[COLS] = { 39, 41, 43, 45 };
Keypad keypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// Keyboard

volatile uint16_t w = 0;  // Number of turns per layer
uint16_t w_temp = 0;
volatile uint16_t wt = 0;  // Number of total turns
uint16_t wt_temp = 0;
uint16_t wl = 0;  // The number of turns in the layer is calculated.
uint16_t wl_temp = 0;
unsigned long pd = 0;    // Number of stacker pulses per wire diameter.
unsigned long pg = 0;    // Error, residual of the number of pulses for all turns and the number of pulses for the entire winding width
unsigned long pl = 0;    // Number of stacker pulses per layer.
unsigned long pd10 = 0;  // Number of stacker pulses per 1/10 of wire diameter.
unsigned long bk = 0;    // Variable for the stacker carriage return cycle
uint8_t Lr = 0;          // Number of layers wound
uint8_t Lr_temp = 0;
float wdt = 0;     // Winding width
float d = 0;       // Wire diameter
uint16_t ii = 0;   // Variable for cycle pd10
uint16_t iii = 0;  // Variable for the layer error compensation cycle
uint16_t prev_iii = 0;
uint8_t iu = 0;             // Variable for manual stacker control cycle
uint8_t ik = 0;             // Variable for manual coil control cycle
volatile uint8_t cont = 0;  // Turn counter variable, max value 255, encoder 100p/r.
volatile uint8_t prev_cont = 0;
uint8_t acc = 1;  // Variable for Non Stop mode. Decreases the speed at the beginning and end of the layer. Depends on the speed mode, normal 450 RPM or high 900 RPM

// Variables for inputting wire diameter and winding width
static int a[3] = { 0, 0, 0 };
static int t = 0;
static int b[4] = { 0, 0, 0, 0 };
static int p = 0;
// Variables for inputting wire diameter and winding width

// Flags
bool f_dir = 0;       // Stacker direction flag
bool f_auto = 0;      // Flag for pressing button "C" start, mode auto/manual
bool f_ukl = 0;       // Flag stacker = 0 / coil = 1
bool f_complete = 0;  // Layer winding completion flag
bool f_servo = 0;     // Coil speed flag, Low = 0, High = 1.
bool f_ready = 0;     // Flag for on/off servo coil drive (Servo-On/Off)
bool f_pg = 0;        // Flag for error compensation
bool f_back = 0;      // Stacker carriage return flag to disable the encoders during cycle operation
bool q = 0;           // Flag for entering the winding width
bool i = 0;           // Wire diameter input flag
bool f_highspd = 0;   // Coil speed flag. 7.5 rev/sec or 15 rev/sec.
bool f_revers = 0;    // Reversing flag of the wire spool reel
bool f_nstp = 0;      // Flag for Non Stop mode
bool f_acc = 1;       // Flag to enable/disable slowdown mode at the beginning and end of layer in Non Stop mode
bool f_pgnstp = 1;    // Flag to enable/disable error accounting at the end of layer in Non Stop mode
// Flags

volatile bool d2 = 0;  // Status polling variable of D2 input for the counter encoder
volatile bool d5 = 0;  // Status polling variable of D5 input for the counter encoder
volatile bool d3 = 0;  // Status polling variable of D3 input for manual encoder MPG
volatile bool d4 = 0;  // Status polling variable of D4 input for manual encoder MPG

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  keypad.addEventListener(keypadEvent);
  cli();  // Disable all interrupts.

  DDRE &= ~(1 << 3);                      // Define board pin 5 as input (D5 PE3) CountB
  DDRE &= ~(1 << 4);                      // Define board pin 2 as input (D2 PE4) CountA
  DDRE &= ~(1 << 5);                      // Define board pin 3 as input (D3 PE5) EncA
  DDRG &= ~(1 << 5);                      // Define board pin 4 as input (D4 PG5) EncB
  DDRH |= (1 << 3);                       // Define board pin 6 as output (D6 PH3) PUL+K
  DDRH |= (1 << 4);                       // Define board pin 7 as output (D7 PH4) DIR+K
  DDRH |= (1 << 5);                       // Define board pin 8 as output (D8 PH5) PUL+U
  DDRH |= (1 << 6);                       // Define board pin 9 as output (D9 PH6) DIR+U
  DDRB |= (1 << 7);                       // Define board pin 13 as output (D13 PB7) STgen
  DDRB |= (1 << 6);                       // Define board pin 12 as output (D12 PB6) Servo-On
  DDRB |= (1 << 5);                       // Define board pin 11 as output (D11 PB5) High Speed. 15r/s or 7.5r/s coil
  DDRB |= (1 << 4);                       // Define board pin 10 as output (D10 PB4) ACC
  SREG |= (1 << 7);                       // Allow all interrupts
  EICRB |= (1 << ISC40) | ~(1 << ISC41);  // CHANGE event interrupt. ISC40 = 1; ISC41 = 0;
  EICRB |= (1 << ISC50) | ~(1 << ISC51);  // CHANGE event interrupt. ISC50 = 1; ISC51 = 0;
  EIMSK |= (1 << INT4);                   // Enable INT4 interrupt on the second leg of the arduino (PE4)
  EIMSK |= (1 << INT5);                   // Enable INT5 interrupt on the third leg of the arduino (PE5)

  sei();  // Allow all interrupts.

  digitalWrite(12, HIGH);  // Enable Servo-On at startup

  lcd.setCursor(0, 0);
  lcd.print("A Wire");
  lcd.setCursor(0, 1);
  lcd.print("B Width");
  lcd.setCursor(0, 3);
  lcd.print("D Direction");
  lcd.setCursor(0, 2);
  lcd.print("C");
  lcd.setCursor(2, 2);
  lcd.print("Start");
  lcd.setCursor(10, 2);
  lcd.print("Lr:");
  lcd.setCursor(13, 2);
  lcd.print(Lr);  // Displaying the number of wound layers
  lcd.setCursor(17, 0);
  lcd.print("Ukl");
  lcd.setCursor(16, 2);
  lcd.print(w);  // Display of the number of turns in the layer
  lcd.setCursor(16, 1);
  lcd.print(wt);  // Display of the number of turns total
  lcd.setCursor(16, 3);
  lcd.print(wl);  // Display of the number of calculated turns in the layer
}

void loop() {
  char key = keypad.getKey();

  // Calculation
  pd = d * 1000;        // Number of stacker pulses per wire diameter
  pd10 = pd / 10;       // Number of stacker pulses per 1/10 of diameter
  wl = wdt / d;  // Number of turns in a layer rounded down to the smaller
  pl = wdt * 1000;      // Number of pulses per winding width
  pg = pl - (wl * pd);  // Error, difference between the number of pulses for all turns in the layer and the number of pulses for the entire winding width
  // Calculation


  if (wl_temp != wl) {
    lcd.setCursor(16, 3);
    lcd.print("    ");
    lcd.setCursor(16, 3);
    lcd.print(wl);  // Display of the calculated number of turns in the layer
    wl_temp = wl;
  }

  if (w_temp != w) {
    lcd.setCursor(16, 2);
    lcd.print("    ");
    lcd.setCursor(16, 2);
    lcd.print(w);  // Display of the number of turns in a layer
    w_temp = w;
  }

  if (wt_temp != wt) {
    lcd.setCursor(16, 1);
    lcd.print("    ");
    lcd.setCursor(16, 1);
    lcd.print(wt);  // Output of the number of turns in total
    wt_temp = wt;
  }


  // Slowing down the coil speed at the beginning and end of the layer in Non Stop mode
  if (f_nstp == 1) {
    if (f_acc == 1 && (wl - w <= acc || w <= acc)) { PORTB |= 1 << 4; }  // If Non Stop mode is selected, switch the generator (Nano) to acceleration and deceleration mode at the beginning and end of the layer
    else {
      PORTB &= ~(1 << 4);
    }
    if (f_highspd == 0 && d < 0.5) { acc = 2; }   // If the wire diameter is less than 0.5mm and low speed mode is selected, the start of acceleration and deceleration is 2 turns
    if (f_highspd == 0 && d >= 0.5) { acc = 1; }  // If the wire diameter is greater than or equal to 0.5mm and low speed mode is selected, the start of acceleration and deceleration is 1 turn
    if (f_highspd == 1 && d < 0.5) { acc = 2; }   // If the wire diameter is less than 0.5mm and low speed mode is selected, the start of acceleration and deceleration is 2 turns
    if (f_highspd == 1 && d >= 0.5) { acc = 1; }  // If the wire diameter is greater than or equal to 0.5mm and low speed mode is selected, the start of acceleration and deceleration is 1 turn
  }
  // Slowing down the coil speed at the beginning and end of the layer in Non Stop mode

  // Slowing down the coil speed at the end of the layer in auto mode
  if (f_nstp == 0) {
    if (f_acc == 1 && wl - w <= acc) { PORTB |= 1 << 4; }  // Switch the generator to slow down mode at the end of the layer
    else {
      PORTB &= ~(1 << 4);
    }
    if (f_highspd == 0 && d < 0.5) { acc = 3; }   // If the wire diameter is less than 0.5 mm and low speed mode is selected, the start of deceleration is 3 turns before the end of the layer
    if (f_highspd == 0 && d >= 0.5) { acc = 2; }  // If the wire diameter is greater than or equal to 0.5 mm and low speed mode is selected, the beginning of deceleration is 2 turns before the end of the layer
    if (f_highspd == 1 && d < 0.5) { acc = 5; }   // If the wire diameter is less than 0.5 mm and high speed mode is selected, the beginning of deceleration is 5 turns before the end of the layer
    if (f_highspd == 1 && d >= 0.5) { acc = 3; }  // If the wire diameter is greater than or equal to 0.5 mm and high speed mode is selected, the beginning of deceleration is 3 turns before the end of the layer
  }
  // Slowing down the coil speed at the end of the layer in auto mode


  // Processing after completion of layer winding
  if (w == wl && wl > 0 && f_complete == 1) {
    if (f_nstp == 0) { PORTB &= ~(1 << 7); }  // Turn GEN to coil OFF, LOW
    // Error at the end of the layer
    if (f_pgnstp == 1) {
      while (iii < pg) {
        PORTH |= (1 << 5);  //PIN8 PUL+U = HIGH
        delayMicroseconds(2);
        PORTH &= ~(1 << 5);  //PIN8 PUL+U = LOW
        delayMicroseconds(2);
        iii++;
      }
    }
    // Error at the end of the layer
    if (f_nstp == 1) { w = 0; }  // Resetting the number of turns in a layer in Non Stop mode
    Lr++;
    f_dir = !f_dir;
    if (f_nstp == 0) {
      f_complete = 0;  // Layer winding completion flag
      f_auto = 0;
    }
    iii = 0;
    if (f_nstp == 0) {
      lcd.setCursor(2, 2);
      lcd.print("Start");
    }
  }

  if (wl - w == 1 && f_complete == 0){   //If after completing the layer you decide to unwind a few turns 
    Lr--;
    f_dir = !f_dir;
    f_complete = 1;
  }
  // Processing after completion of layer winding

  if (Lr_temp != Lr) {
    lcd.setCursor(13, 2);
    lcd.print("  ");
    lcd.setCursor(13, 2);
    lcd.print(Lr);  // Displaying the number of layers
    Lr_temp = Lr;
  }

  // Stacker direction displaying
  if (f_dir == 1) {
    PORTH |= (1 << 6);  // DIR Stacker HIGH D9
    lcd.setCursor(12, 3);
    lcd.print("<--");
  } else {
    PORTH &= ~(1 << 6);  // DIR Stacker LOW D9
    lcd.setCursor(12, 3);
    lcd.print("-->");
  }
  // Stacker direction displaying

  if (wl > 0) {  // If the calculated turns are greater than zero, wire diameter and winding width are entered, auto start is enabled
    f_ready = 1;
  }
  if (w >= wl && wl > 0) {  // After winding a full layer, disable auto-start until the number of turns in the layer has been reset
    f_ready = 0;
  }
}

// Manual operation
void manual() {
  // Manual operation of the stacker
  if (f_ukl == 0 && f_auto == 0) {
    d3 = PINE & (1 << PINE5);
    d4 = PING & (1 << PING5);
    if (d3 == HIGH && d4 == HIGH) {
      PORTH |= (1 << 6);  // Select the direction of the stacker. DIR = HIGH D9
    }
    delayMicroseconds(3);
    if (d3 == HIGH && d4 == LOW) {
      PORTH &= ~(1 << 6);  // Select the direction of the stacker. DIR = LOW D9
    }
    delayMicroseconds(3);
    while (iu < 6) {      // When iu == 1 - 12.5 encoder revolutions(400p/r) at 5000p/r motor
      PORTH |= (1 << 5);  // Write a high level PUL signal to port D8
      delayMicroseconds(3);
      PORTH &= ~(1 << 5);  // Write a low PUL signal to port D8
      delayMicroseconds(3);
      iu++;
    }
    iu = 0;
  }
  // Manual operation of the stacker

  // Manual coil control
  if (f_ukl == 1 && f_auto == 0) {
    d3 = PINE & (1 << PINE5);
    d4 = PING & (1 << PING5);
    if (d3 == HIGH && d4 == HIGH) {
      PORTH |= (1 << 4);  // Select the direction of the coil. Signal DIR = HIGH D7
    }
    delayMicroseconds(5);
    if (d3 == HIGH && d4 == LOW) {
      PORTH &= ~(1 << 4);  // Select the direction of the coil. Signal DIR = LOW D7
    }
    delayMicroseconds(5);
    while (ik < 3) {      // Motor 1000p/r plus 4:1 gearbox, total 4000p/r. Encoder 400p/r. With a counter equal to ik == 3 we have 4000/1200=3.3 encoder revolutions per spool revolution
      PORTH |= (1 << 3);  // Write a high level PUL signal to port D6
      delayMicroseconds(5);
      PORTH &= ~(1 << 3);  // Write a low PUL signal to port D6
      delayMicroseconds(5);
      ik++;
    }
    ik = 0;
  }
  // Manual coil control
}
// Manual operation


// A pack of pulses per stacker, one tenth of the total for one step/turn
void step() {
  // The remainder of the division by 10. After 10 pulses of the counter (36 degrees of coil rotation)
  // Output a pack of pulses to the stacker in the amount of 1/10 of the counted pulses per wire diameter.
  if (f_back == 0 && prev_cont != cont && wl > 0) {
    while (ii < pd10) {
      PORTH |= (1 << 5);  //PIN8 PUL+U = HIGH
      delayMicroseconds(2);
      PORTH &= ~(1 << 5);  //PIN8 PUL+U = LOW
      delayMicroseconds(2);
      ii++;
    }
    if (ii == pd10) {
      ii = 0;
      prev_cont = cont;
    }
  }
}
// A pack of pulses per stacker, one tenth of the total for one step/turn


// Interrupt for manual control of the coil and stacker
ISR(INT5_vect) {
  d3 = PINE & (1 << PINE5);
  d4 = PING & (1 << PING5);
  if (d3 == HIGH && d4 == HIGH && f_back == 0) {
    PORTH |= (1 << 6);  // Select the direction of the stacker. Signal DIR = HIGH D9
  }
  if (d3 == HIGH && d4 == LOW && f_back == 0) {
    PORTH &= ~(1 << 6);  // Select the direction of the stacker. Signal DIR = LOW D9
  }
  if (f_back == 0) { manual(); }
}
// Interrupt for manual control of the coil and stacker


// Stacker - counter
ISR(INT4_vect) {
  d2 = PINE & (1 << PINE4);
  d5 = PINE & (1 << PINE3);
  if (d2 == HIGH && d5 == HIGH && f_back == 0) {
    if (f_dir == 1) { PORTH |= (1 << 6); }   // PIN9 DIR+U = HIGH Change the direction of the stacker immediately in the interrupt
    if (f_dir == 0) { PORTH &= ~(1 << 6); }  // PIN9 DIR+U = LOW Change the direction of the stacker immediately in the interrupt
    if (cont == 100) {
      cont = 0;
      w++;
      wt++;
    }
    cont++;
  }
  if (d2 == HIGH && d5 == LOW && f_back == 0) {
    if (f_dir == 1) { PORTH &= ~(1 << 6); }  // PIN9 DIR+U = LOW Change the direction of the stacker immediately in the interrupt
    if (f_dir == 0) { PORTH |= (1 << 6); }   // PIN9 DIR+U = HIGH Change the direction of the stacker immediately in the interrupt
    if (cont == 0 && w > 0) {
      cont = 100;
      if (w > 0) { w--; }
      if (wt > 0) { wt--; }
    }
    if (cont > 0) { cont--; }
  }
  if (cont % 10 == 0) { step(); }
}
// Stacker - counter


// Keyboard
void keypadEvent(KeypadEvent key) {
  switch (keypad.getState()) {
    case PRESSED:

      // Selection of manual stacker or bobbin control
      if (key == '*' && f_auto == 0 && f_ukl == 0) {
        key = 0;
        q = 0;
        i = 0;
        f_ukl = 1;
        lcd.setCursor(17, 0);
        lcd.print("Kat");
      }

      if (key == '*' && f_auto == 0 && f_ukl == 1) {
        key = 0;
        q = 0;
        i = 0;
        f_ukl = 0;
        lcd.setCursor(17, 0);
        lcd.print("Ukl");
      }
      // Selection of manual stacker or bobbin control


      // Resetting the number of turns in a layer
      if (key == '#' && f_auto == 0) {
        key = 0;
        q = 0;
        i = 0;
        cont = 0;
        w = 0;
        f_complete = 1;
        iii = 0;
        f_pg = 0;
        lcd.setCursor(16, 2);
        lcd.print("    ");
        lcd.setCursor(16, 2);
        lcd.print(w);
      }
      // Resetting the number of turns in a layer


      // Start / Pause
      if (key == 'C' && f_auto == 0 && f_ready == 1 && wl > 0) {
        key = 0;
        q = 0;
        i = 0;
        f_auto = 1;
        lcd.setCursor(9, 0);
        lcd.print(" ");
        lcd.setCursor(9, 1);
        lcd.print(" ");
        lcd.setCursor(2, 2);
        lcd.print("Stop ");
        PORTB |= (1 << 7);                          // GEN coil D13 HIGH
        if (f_revers == 0) { PORTH |= (1 << 4); }   // DIR coil D7 HIGH
        if (f_revers == 1) { PORTH &= ~(1 << 4); }  // DIR coil D7 LOW
      }

      if (key == 'C' && f_auto == 1) {
        key = 0;
        q = 0;
        i = 0;
        f_auto = 0;
        lcd.setCursor(2, 2);
        lcd.print("Start");
        PORTB &= ~(1 << 7);  // GEN coil LOW
      }
      // Start / Pause


      // Direction
      if (key == 'D' && f_auto == 0) {
        key = 0;
        q = 0;
        i = 0;
        f_dir = !f_dir;
      }
      // Direction


      // Resetting previously set diameter and width values
      if (key == 'A' && f_auto == 0) {
        key = 0;
        a[0] = 0;
        a[1] = 0;
        a[2] = 0;
        t = 0;
        i = 1;
        q = 0;
        f_complete = 1;
        lcd.setCursor(10, 0);
        lcd.print("     ");
        lcd.setCursor(10, 0);
        lcd.print(d, 2);
        lcd.setCursor(10, 1);
        lcd.print(wdt, 1);
      }

      if (key == 'B' && f_auto == 0) {
        key = 0;
        b[3] = 0;
        b[2] = 0;
        b[1] = 0;
        b[0] = 0;
        p = 0;
        i = 0;
        q = 1;
        wdt = 0;
        lcd.setCursor(10, 1);
        lcd.print("     ");
        lcd.setCursor(10, 1);
        lcd.print(wdt, 1);
      }
      // Resetting previously set diameter and width values


      // Wire diameter input
      if (i == 1) {
        lcd.setCursor(9, 0);
        lcd.print("*");
        lcd.setCursor(9, 1);
        lcd.print(" ");
        if (key == 'C') { key = 0; }
        if (key) {
          a[t] = key - 48;
          t++;
          if (t == 3) {
            t = 0;
          }
        }
        d = a[0] + 0.1 * a[1] + 0.01 * a[2];
        lcd.setCursor(10, 0);
        lcd.print(d, 2);
      }
      // Wire diameter input


      // EEntering the coil width
      if (q == 1) {
        lcd.setCursor(9, 1);
        lcd.print("*");
        lcd.setCursor(9, 0);
        lcd.print(" ");
        if (key == 'C') { key = 0; }
        if (key) {
          b[p] = key - 48;
          p++;
          if (p == 4) {
            p = 0;
          }
        }
        wdt = (b[0] + 0.1 * b[1] + 0.01 * b[2] + 0.001 * b[3]) * 100.001;
        lcd.setCursor(10, 1);
        lcd.print(wdt, 1);
      }
      // Entering the coil width

      break;


    case HOLD:

      // Returns the carriage to the initial position of the layer
      if (key == 'D' && f_auto == 0) {
        f_back = 1;  // Stacker carriage return flag to disable the encoders during cycle operation
        cli();
        if (f_dir == 1) {
          digitalWrite(9, LOW);
          delayMicroseconds(10);  // Delay after DIR signal
        } else {
          digitalWrite(9, HIGH);
          delayMicroseconds(10);  // Delay after DIR signal
        }
        for (bk = 1; bk <= pl; bk++) {
          PORTH |= (1 << 5);  // Board pin 8 as output (D8 PH5) PUL+U, write HIGH to it
          delayMicroseconds(3);
          PORTH &= ~(1 << 5);  // Board pin 8 as output (D8 PH5) PUL+U, write LOW to it
          delayMicroseconds(3);
          if (bk == pl) {
            f_back = 0;
          }
        }
        sei();
      }
      // Returns the carriage to the initial position of the layer


      // Resetting all counter values
      if (key == '#' && f_auto == 0) {
        w = 0;
        wt = 0;
        Lr = 0;
        cont = 0;
        f_complete = 1;
        lcd.setCursor(13, 2);
        lcd.print("  ");
        lcd.setCursor(13, 2);
        lcd.print(Lr);
        lcd.setCursor(16, 1);
        lcd.print("    ");
        lcd.setCursor(16, 1);
        lcd.print(wt);
        lcd.setCursor(16, 2);
        lcd.print("    ");
        lcd.setCursor(16, 2);
        lcd.print(w);
      }
      // Resetting all counter values


      // Servo=On/Off
      if (key == 'C' && f_auto == 0 && f_servo == 0 && wl == 0) {
        key = 0;
        lcd.setCursor(15, 2);
        lcd.print("S");
        f_servo = 1;
        digitalWrite(12, LOW);
      }

      if (key == 'C' && f_auto == 0 && f_servo == 1 && wl == 0) {
        key = 0;
        lcd.setCursor(15, 2);
        lcd.print(" ");
        f_servo = 0;
        digitalWrite(12, HIGH);
      }
      // Servo=On/Off

      // High Speed On/Off
      if (key == '0' && f_highspd == 0) {
        key = 0;
        lcd.setCursor(15, 3);
        lcd.print("H");
        f_highspd = 1;
        digitalWrite(11, HIGH);
      }

      if (key == '0' && f_highspd == 1) {
        key = 0;
        lcd.setCursor(15, 3);
        lcd.print(" ");
        f_highspd = 0;
        digitalWrite(11, LOW);
      }
      // High Speed On/Off


      // Coil Reverse On/Off
      if (key == '*' && f_revers == 0 && f_auto == 0) {
        key = 0;
        lcd.setCursor(15, 1);
        lcd.print("R");
        f_revers = 1;
      }

      if (key == '*' && f_revers == 1 && f_auto == 0) {
        key = 0;
        lcd.setCursor(15, 1);
        lcd.print(" ");
        f_revers = 0;
      }
      // Coil Reverse On/Off

      // Full Auto Non Stop mode
      if (key == 'A' && f_nstp == 0 && f_auto == 0) {
        key = 0;
        lcd.setCursor(15, 0);
        lcd.print("N");
        f_nstp = 1;
      }

      if (key == 'A' && f_nstp == 1 && f_auto == 0) {
        key = 0;
        lcd.setCursor(15, 0);
        lcd.print(" ");
        f_nstp = 0;
      }
      // Full Auto Non Stop mode

      // Enable/disable slowdown mode at the beginning and end of a layer in Non Stop mode
      if (key == '1' && f_acc == 1 && f_auto == 0) {
        key = 0;
        lcd.setCursor(8, 0);
        lcd.print("A");
        f_acc = 0;
      }

      if (key == '1' && f_acc == 0 && f_auto == 0) {
        key = 0;
        lcd.setCursor(8, 0);
        lcd.print(" ");
        f_acc = 1;
      }
      // Enable/disable slowdown mode at the beginning and end of a layer in Non Stop mode

      // Enable/disable end-of-layer error accounting in Non Stop mode
      if (key == 'B' && f_pgnstp == 1 && f_auto == 0) {
        key = 0;
        lcd.setCursor(8, 1);
        lcd.print("P");
        f_pgnstp = 0;
      }

      if (key == 'B' && f_pgnstp == 0 && f_auto == 0) {
        key = 0;
        lcd.setCursor(8, 1);
        lcd.print(" ");
        f_pgnstp = 1;
      }
      // Enable/disable end-of-layer error accounting in Non Stop mode
      break;
  }
}
// Keyboard