 
				 
				MODELO MENU

		
CODIGO

		//librerias
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
//PINES DE ENTRADA DE LOS PULSADORES         █
const int in_A = 2;     //ADD                █
const int in_B = 4;     //LESS               █
const int swPin = 3;    //OK                 █
bool btnpress = false;  //memoria boton OK   █
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
//PINES DE SALIDA PARA CONTROLAR LOS MOTORES                                   █
#define pwm_motor1 9   //Salidas PWM para el motor 1                           █
#define pwm_motor2 10  //Salidas PWM para el motor 2                           █
#define der_m1 5       // señal para que el motor 1 gire hacia la derecha      █
#define izq_m1 6       // señal para que el motor 1 gire hacia la izquierda    █
#define der_m2 7       // señal para que el motor 2 gire hacia la derecha      █
#define izq_m2 8       // señal para que el motor 2 gire hacia la ziquierda    █ \
                       /////                                                   █
//MEMORIAS PARA LA VELOCIDAD DEL MOTOR                                         █
int vel_moto1 = 0;    // variable para la velocidad del motor1                 █
int vel_moto2 = 0;    // variable para la velocidad del motor2                 █
int direc_moto1 = 1;  //Direccion EEPROM para almacenar la variable vel_moto1  █
int direc_moto2 = 2;  //Direccion EEPROM para almacenar la variable vel_moto2  █
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
//---------------------------------------------------MENUS--------------------------------------------------------------------------------------------------
String menu1[] = { "ON // OFF", "ADJ VELOCIDAD", "INVER GIRO", "Atras" };  //Palabras del menu principal
int sizemenu1 = sizeof(menu1) / sizeof(menu1[0]);                          // Aqui vamos a obtener el número de elementos ocupados en la matriz. en este caso 3
String menu2[] = { "Motor1", "Motor2", "Atras" };
int sizemenu2 = sizeof(menu2) / sizeof(menu2[0]);
String menu3[] = { "ON", "OFF", "Atras" };
int sizemenu3 = sizeof(menu3) / sizeof(menu3[0]);
String menu4[] = { "Izquierda", "Derecha", "Atras" };
int sizemenu4 = sizeof(menu4) / sizeof(menu4[0]);
String linea1, linea2;  //lines o filas del lcd 16x2
int level_menu = 0;     // para ubicarnos en un menú { "ON // OFF", "ADJ VELOCIDAD", "INVER GIRO", "Atras" } { "Motor1", "Motor2", "Atras" };
int level2_menu = 0;    // para ubicarnos en el subnemu { "ON", "OFF", "Atras" } { "Izquierda", "Derecha", "Atras" }
int contador = 0;  // CONTADOR PARA EL DESPLAZAMIENTO ENTRE LOS MENUS
byte flecha[] = { B10000, B11000, B11100, B11110, B11100, B11000, B10000, B00000 };  //Creamos un array de 8 posiciones para la flecha del menu
//▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
void setup() {
  pinMode(in_A, INPUT);
  pinMode(in_B, INPUT);
  pinMode(swPin, INPUT);
  pinMode(pwm_motor1, OUTPUT);
  pinMode(pwm_motor2, OUTPUT);
  pinMode(der_m1, OUTPUT);
  pinMode(izq_m1, OUTPUT);
  pinMode(der_m2, OUTPUT);
  pinMode(izq_m2, OUTPUT);
  lcd.init();
  lcd.backlight();
  lcd.createChar(0, flecha);  //Caracter personalizado
  vel_moto1 = EEPROM.read(direc_moto1);  // Obtiene el dato de EEPROM y lo envía a la variable vel_moto1
  vel_moto2 = EEPROM.read(direc_moto2);
  analogWrite(pwm_motor1, map(vel_moto1, 0, 9, 0, 255));  //Enviamos el dato leido de EEPROM al MOTOR 1
  analogWrite(pwm_motor2, map(vel_moto2, 0, 9, 0, 255));
}
void loop() {
  selectOption();  //Funcion para detectar cuando se Presionar el pusador de OK
  //███████████████████████████████████ PANTALLA PRINCIPAL ██████████████████████████████████████████
  if (level_menu == 0) {
    lcd.setCursor(0, 0);  //Detalles mas importantes del motor1 // linea0
    lcd.print("Motor1: ");
    if (vel_moto1) lcd.print("ON, ");
    else lcd.print("OFF, ");
    lcd.print(vel_moto1);
    lcd.setCursor(0, 1);  //Detalles mas importantes del motor2  // linea1
    lcd.print("Motor2: ");
    if (vel_moto2) lcd.print("ON, ");
    else lcd.print("OFF, ");
    lcd.print(vel_moto2);
    if (btnpress) {  // si se presiona el pulsador de OK nos llevará al menu principal
      level_menu = 1;
      fn_menu(contador, menu1, sizemenu1);
      btnpress = false;
    }
  }  //███████████████████████████████████████████████████████████████████████████████████████████████
  //███████████████████████████████████ MENU 1 PRINCIPAL ██████████████████████████████████████████
  if (level_menu == 1) {  //Esta variable corresponde al nivel principal del menu. level_menu = 1.
    if (fnSwitch(sizemenu1)) {              //Esta funcion muestra en el LCD el menu en el que estamos
      fn_menu(contador, menu1, sizemenu1);  //Esta funcion muestra la posicion dentro de ese menu segun el valor de la variable contador
    }
    if (btnpress) {  //Verificamos si el boton del encoder fue oprimido. btnpress == true
      // >ON // OFF
      if (contador == 0) {
        contador = 0;                         //Seleccionamos la posicion donde quedara la flecha de seleccion. On, Off, Atras
        fn_menu(contador, menu2, sizemenu2);  //Vamos a la funcion que nos muestra las opciones para el Led 1
        level_menu = 2;                       //Esta variable corresponde al nivel secundario del menu. level_menu = 1.
      }
      // > ADJ VELOCIDAD
      if (contador == 1) {
        contador = 0;
        fn_menu(contador, menu2, sizemenu2);
        level_menu = 3;
      }
      //> INVERSION DE GIRO
      if (contador == 2) {
        contador = 0;
        fn_menu(contador, menu2, sizemenu2);
        level_menu = 4;
      }
      //>Atras
      if (contador == 3) {
        contador = 0;
        level_menu = 0;
      }
      btnpress = false;  //  Nos aseguramos que esta variable de retorno de la funcion selectOption() vuelva a su estado inicial
    }
  }  //██████████████████████████████████████████████████████████████████████████████████████████████████████████████
  //███████████████████████████████████ MENU2: { "Motor1", "Motor2", "Atras" } ██████████████████████████████████████████
  if (level_menu == 2) {
    if (level2_menu == 0) {
      if (fnSwitch(sizemenu2)) {  //Nos desplazamos con el encoder sleccionando las diferentes opciones
        fn_menu(contador, menu2, sizemenu2);
      }
      if (btnpress) {  //Verificamos si el boton del encoder fue oprimido. btnpress == true
        if (contador == 0) {  // motor1
          contador = 0;
          fn_menu(contador, menu3, sizemenu3);
          level2_menu = 1;
        }
        if (contador == 1) {  // motor2
          contador = 0;
          fn_menu(contador, menu3, sizemenu3);
          level2_menu = 2;
        }
        if (contador == 2) {  //atras
          contador = 0;
          fn_menu(contador, menu1, sizemenu1);
          level_menu = 1;
        }
        btnpress = false;
      }
    }
    //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ MENU 3: { "ON", "OFF", "Atras" } ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
    if (level2_menu == 1) {
      if (fnSwitch(sizemenu3)) {  //Nos desplazamos con el encoder sleccionando las diferentes opciones
        fn_menu(contador, menu3, sizemenu3);
      }
      if (btnpress) {
        if (contador == 0) {
          digitalWrite(pwm_motor1, HIGH);  //Encedemos motor 1
          vel_moto1 = 9;                   //Maximo velocidad
          EEPROM.write(direc_moto1, vel_moto1);
        }
        if (contador == 1) {
          digitalWrite(pwm_motor1, LOW);  //Apagamos motor 1
          vel_moto1 = 0;                  //minima velocidad
          EEPROM.write(direc_moto1, vel_moto1);
        }
        if (contador == 2) {  //atras
          contador = 0;
          fn_menu(contador, menu2, sizemenu2);
          level2_menu = 0;
        }
        btnpress = false;
      }
    }
    if (level2_menu == 2) {
      if (fnSwitch(sizemenu3)) {  //Nos desplazamos con el encoder sleccionando las diferentes opciones
        fn_menu(contador, menu3, sizemenu3);
      }
      if (btnpress) {
        if (contador == 0) {
          digitalWrite(pwm_motor2, HIGH);  // ON MOTOR 2
          vel_moto2 = 9;                   // velocidad maxima
          EEPROM.write(direc_moto2, vel_moto2);
        }
        if (contador == 1) {
          digitalWrite(pwm_motor2, LOW);  //OFF MOTOR2
          vel_moto2 = 0;                  //Velocidad minima
          EEPROM.write(direc_moto2, vel_moto2);
        }
        if (contador == 2) {  //atras
          contador = 0;
          fn_menu(contador, menu2, sizemenu2);
          level2_menu = 0;
        }
        btnpress = false;
      }
    }  //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  }    //██████████████████████████████████████████████████████████████████████████████████████████████████████████████
  //███████████████████████████████████ MENU3: velocidad motor1, velocidad motor2 ██████████████████████████████████████████
  if (level_menu == 3) {
    if (fnSwitch(sizemenu2)) {  // MENU2: { "Motor1", "Motor2", "Atras" }
      fn_menu(contador, menu2, sizemenu2);
    }
    if (btnpress) {
      if (contador == 0) {
        contador = vel_moto1;
        lcd.clear();
        do {
          fn_contador_brillo();
          vel_moto1 = contador;
          lcd.setCursor(0, 0);
          lcd.print("velocidad motor1");
          analogWrite(pwm_motor1, map(vel_moto1, 0, 9, 0, 255));
          lcd.setCursor(0, 1);
          lcd.print(vel_moto1);
        } while (digitalRead(swPin) == LOW);  //Instrucciones despues del do se repetirán mientras esta condición sea cierta
        delay(500);
        EEPROM.write(direc_moto1, vel_moto1);  // Se agrega a EEPROM con la dirección primero y valor de la variable después
        contador = 0;
        fn_menu(contador, menu2, sizemenu2);
      }
      if (contador == 1) {
        contador = vel_moto2;
        lcd.clear();
        do {
          fn_contador_brillo();
          vel_moto2 = contador;
          lcd.setCursor(0, 0);
          lcd.print("velocidad motor2");
          analogWrite(pwm_motor2, map(vel_moto2, 0, 9, 0, 255));
          lcd.setCursor(0, 1);
          lcd.print(vel_moto2);
        } while (digitalRead(swPin) == LOW);  //Instrucciones despues del do se repetirán mientras esta condición sea cierta
        delay(500);
        EEPROM.write(direc_moto2, vel_moto2);
        contador = 1;
        fn_menu(contador, menu2, sizemenu2);
      }
      if (contador == 2) {                    //ATRAS
        contador = 1;                         //Posicion del menu donde se genero el llamado 0 --> 5
        fn_menu(contador, menu1, sizemenu1);  //Retorna al Menu Principal a la posicion del menu donde se genero el llamado
        level_menu = 1;
      }
      btnpress = false;
    }
  }  //██████████████████████████████████████████████████████████████████████████████████████████████████████████████
  //███████████████████████████████████ MENU2: { "Motor1", "Motor2", "Atras" } ██████████████████████████████████████████
  if (level_menu == 4) {
    if (level2_menu == 0) {
      if (fnSwitch(sizemenu2)) {
        fn_menu(contador, menu2, sizemenu2);
      }
      if (btnpress) {
        if (contador == 0) {  // MOTOR 1
          contador = 0;
          fn_menu(contador, menu4, sizemenu4);
          level2_menu = 1;
        }
        if (contador == 1) {  // MOTOR 2
          contador = 0;
          fn_menu(contador, menu4, sizemenu4);
          level2_menu = 2;
        }
        if (contador == 2) {  //ATRAS
          contador = 0;
          fn_menu(contador, menu1, sizemenu1);
          level_menu = 1;
        }
        btnpress = false;
      }
    }
    //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ MENU 3.1: { "IZQUIERDA", "DERECHA", "Atras" } ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
    if (level2_menu == 1) {  // IZQUIERDA, DERECHA, ATRAS: MOTOR 2
      if (fnSwitch(sizemenu4)) {
        fn_menu(contador, menu4, sizemenu4);
      }
      if (btnpress) {
        if (contador == 0) {  //IZQUIERDA
          digitalWrite(der_m1, 1);
          digitalWrite(izq_m1, 0);
        }
        if (contador == 1) {  //DERECHA
          digitalWrite(der_m1, 0);
          digitalWrite(izq_m1, 1);
        }
        if (contador == 2) {  //ATRAS
          contador = 0;
          fn_menu(contador, menu2, sizemenu2);
          level2_menu = 0;
        }
        btnpress = false;
      }
    }
    if (level2_menu == 2) {  // IZQUIERDA, DERECHA, ATRAS: MOTOR 2
      if (fnSwitch(sizemenu4)) {
        fn_menu(contador, menu4, sizemenu4);
      }
      if (btnpress) {
        if (contador == 0) {  // IZQUIERDA
          digitalWrite(der_m2, 1);
          digitalWrite(izq_m2, 0);
        }
        if (contador == 1) {  //DERECHA
          digitalWrite(der_m2, 0);
          digitalWrite(izq_m2, 1);
        }
        if (contador == 2) {  //ATRAS
          contador = 1;
          fn_menu(contador, menu2, sizemenu2);
          level2_menu = 0;
        }
        btnpress = false;
      }
    }  //▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
  }    //██████████████████████████████████████████████████████████████████████████████████████████████████████████████
}
void selectOption() {  //funcion para leer el pulsador de ok
  if (digitalRead(swPin) == HIGH) {
    delay(500);
    btnpress = true;
  }
}
void fn_contador_brillo() {
  if (digitalRead(in_A) == HIGH) {
    contador++;
    delay(250);
  } else if (digitalRead(in_B) == HIGH) {
    contador--;
    delay(250);
  }
  if (contador > 9) {
    contador = 9;
  }
  if (contador < 0) {
    contador = 0;
  }
}
void fn_menu(int pos, String menus[], byte sizemenu) {  // funcion de desplazamiento de los menús
  lcd.clear();
  linea1 = "";
  linea2 = "";
  if ((pos % 2) == 0) {
    lcd.setCursor(0, 0);
    lcd.write(byte(0));
    linea1 = menus[pos];
    if (pos + 1 != sizemenu) {
      linea2 = menus[pos + 1];
    }
  } else {
    linea1 = menus[pos - 1];
    lcd.setCursor(0, 1);
    lcd.write(byte(0));
    linea2 = menus[pos];
  }
  lcd.setCursor(1, 0);
  lcd.print(linea1);
  lcd.setCursor(1, 1);
  lcd.print(linea2);
}
bool fnSwitch(byte sizemenu) {  //Lee las señales de los pulsadores, exepto el de ok
  bool retorno = false;
  if (digitalRead(in_A) == 1 || digitalRead(in_B) == 1) {
    if (digitalRead(in_A) == HIGH) {
      contador++;
      delay(250);
    } else if (digitalRead(in_B) == HIGH) {
      contador--;
      delay(250);
    }
    if (contador <= 0) {
      contador = 0;
    }
    if (contador >= sizemenu - 1) {
      contador = sizemenu - 1;
    }
    retorno = true;
  }
  return retorno;
}
		

