Ir al contenido principal

CONTROL CON ARDUINO LECCION III. CREAR MENÚ


ALGORITMO PARA CREACIÓN DE MENÚ


Hola a todos, en esta ocasión les traigo un algoritmo para crear un menú interactivo en el LCD, básicamente es la continuación de la lección II, ya que utilizamos el mismo material,  con la diferencia de que esta vez, ya se tiene un menú en forma.


Material:
1 encoder
1 LCD con interfaz I2C
1 Placa arduino 1
10 cables dupont

Conexiones:
Encoder  -  Arduino
GND ------- GND
   + ---------- Vcc (5V)
SW ---------  4
DT ---------- 3
CLK -------- 2

LCD  -  Arduino
GND -------- GND
  Vcc -------- Vcc (5V)
 SDA -------  A4
 SCL -------  A5


Circuito



Algoritmo


#include <Timer.h>  
#include <LiquidCrystal_I2C.h>
Timer t;  //Declaramos un timer, para dar base de tiempo

//Definición de pines de entrada
#define encoder0PinA  2
#define encoder0PinB  3
#define encoder0Pulse 4

//Variables utilizadas tanto en la ISR, como en el void loop
volatile unsigned int encoder0Pos = 6;
volatile char indicadorDegiro;
volatile boolean flagLCD=0;  //Bandera indicadora de interrupción

boolean flagPulse=0; //Bandera indicadora de pulsador presionado
String mensaje1,mensaje2; //Variables para almacenar mensajes que se desplegará en LCD
int conteoInt=0; //Variable para conteo de interrupciones, es necesario puesto que se interrumpe en dos ocasiones, ya que existen 2 flancos de bajada por por giro
boolean renglonLCD=0; //indica el renglon actual
unsigned int indexLCD=6; //Apuntador de LCD; indica el "item" actual

LiquidCrystal_I2C lcd(0x27, 16, 2);  // Configura LCD

void setup() { 

   lcd.begin(); 
   pinMode(encoder0PinA, INPUT_PULLUP); //Habilita pull ups, para contrar siempre con un voltaje de referencia
  pinMode(encoder0PinB, INPUT_PULLUP); 
  pinMode(encoder0Pulse,INPUT_PULLUP); 

  //Inicializar menú
  mensaje1="Item1";
  mensaje2="Item2";
  lcd.setCursor(0,0); 
  lcd.print(">");
  lcd.print(mensaje1);
  lcd.setCursor(1,1);  
  lcd.print(mensaje2);

  attachInterrupt(0, task1,FALLING);  // Habilita interrupción en pin 2, por flanco descendente
  attachInterrupt(1, task1,FALLING);  // Habilita interrupción en pin 3, por flanco descendente





void loop(){

  t.update();
  
if (flagLCD==1 && conteoInt==0){
  flagLCD=0;
  conteoInt++; //Incrementa contador de interrupciones. 
  t.after(170,esperaCambio); //Da tiempo para que se estabilice el encoder, antes de habilitar nuevamente las interrupciones
}
  

 else if (flagLCD==1 && conteoInt>0){
    flagLCD=0;
    lcd.clear();
    imprimeLCD();   
    conteoInt=0; //Limpia contador de interrupciones
    t.after(170,esperaCambio); //Da tiempo para que se estabilice el encoder, antes de habilitar nuevamente las interrupciones
                       }


if (digitalRead(encoder0Pulse)==0 && flagPulse==0){ //Si pulso botón y flag=0 entonces
      t.after(250,verificaPulso); //Llama a rutina verificaPulso despues de 150 ms, para evitar rebote
      flagPulse=1;
       }


}





void task1() {
      // Deshabilitar ambas interrupciones para evitar falsas lecturas en el LCD
    detachInterrupt(0);
    detachInterrupt(1);
  
    if (digitalRead(encoder0PinA)==0 && digitalRead(encoder0PinB)==1) {
              if (encoder0Pos<6){
              encoder0Pos++;
                                }
                           
              indicadorDegiro='+';
              
                            } 
               
    if (digitalRead(encoder0PinA)==1 && digitalRead(encoder0PinB)==0) {
      if (encoder0Pos>0){
    encoder0Pos--;
                        }
      
    
     indicadorDegiro='-';
          }
             
    indexLCD=encoder0Pos; //Instrucción necesaria, porque el compilador no permite leer la variable volatile dentro del switch case
    flagLCD=1;
              }




void esperaCambio(){
attachInterrupt(0, task1,FALLING);  // Habilita interrupción en pin 2, por cambio de nivel
attachInterrupt(1, task1,FALLING);  // Habilita interrupción en pin 2, por cambio de nivel  

}




void verificaPulso(){
 static boolean conmutador1=0, conmutador2=0; //Variable para conmutar brillo del LCD
  

  if (renglonLCD==0){ //Si el índice es par, significa que estoy en el renglon 0
    if (conmutador1==0){
      lcd.setCursor(8,0);
      lcd.print("OK");
    }

    else{
      lcd.setCursor(8,0);
      lcd.print("  ");
    }

      conmutador1=!conmutador1;// Cambia de estado (conmuta)
        
  }




if (renglonLCD==1){ //Si el índice es par, significa que estoy en el renglon 0
    if (conmutador2==0){
      lcd.setCursor(8,1);
      lcd.print("OK");
    }

    else{
      lcd.setCursor(8,1);
      lcd.print("  ");
    }

      conmutador2=!conmutador2;// Cambia de estado (conmuta)
        
  }

     flagPulse=0;
}


void imprimeLCD(){

if (indicadorDegiro=='+' && renglonLCD==0 && indexLCD<6){ //Si está en item1 y mueve hacia "-"
    lcd.setCursor(0,1); //Celda y línea
     renglonLCD=1;
       } 
                  



 else if (indicadorDegiro=='+' && renglonLCD==1 && indexLCD<=6){
    lcd.setCursor(0,0); //Celda y línea
    renglonLCD=0; 
   
}

                   
 else if (indicadorDegiro=='-' && renglonLCD==0 && indexLCD>0){
    lcd.setCursor(0,1); //Celda y línea
    renglonLCD=1;
            } 
                  

 else if (indicadorDegiro=='-' && renglonLCD==1 && indexLCD>=0){
    lcd.setCursor(0,0); //Celda y línea
    renglonLCD=0; 
 }


if (indexLCD==5 || indexLCD==6){
  mensaje1="Item1";
  mensaje2="Item2";
}


if (indexLCD==3 || indexLCD==4){
  mensaje1="Item3";
  mensaje2="Item4";
}

if (indexLCD==1 || indexLCD==2){
  mensaje1="Item5";
  mensaje2="Item6";
}

if (indexLCD==0){
  mensaje1="Item7";
  mensaje2="";
}




lcd.print(">");
lcd.setCursor(1,0); 
lcd.print(mensaje1);
lcd.setCursor(1,1); 
lcd.print(mensaje2);
}




Análisis de algoritmo





Dudas o sugerencias:

talleresarduino@gmail.com
facebook.com/ConsultorMic

Ing. Francisco Galindo.



Comentarios

Entradas más populares de este blog

CONTROL CON ARDUINO. LECCIÓN I

¿Por dónde comienzo? La respuesta aburrida de siempre: Por el principio. Aquí NO encontrarás respuestas vagas. Encontrarás respuestas concretas y sencillas de entender, así de simple; comenzando desde el encendido de un led, hasta el diseño de un scheduler de tiempo real. ¿Es importante la teoría? Desde luego que sí, como en cualquier área, sin embargo aquí nos enfocaremos en una metodología 100% práctica, por lo que la parte teórica será materia de otro blog, que podrás consultar si es de tu interés. Nota. - Las siguientes lecciones están dirigidas a aquellos interesados que por lo menos ya saben armar un circuito serie en un protoboard, ya que el objetivo aquí es la enseñanza de los algoritmos, más que la electrónica. Video introductorio                                                        ALGORITMO 1 int led=3; void setu...

CONTROL CON ARDUINO. LECCION II. ENCODER

Práctica previa a la creación de menú utilizando LCD. Material: Arduino UNO LCD con interfaz I2C Encoder rotativo Objetivo . Aprenderás a utilizar el movimiento rotativo de un encoder y utilizarlo en el desplazamiento de un menú, diseñado para un LCD. Algoritmo: #include <Timer.h>   #include <LiquidCrystal_I2C.h> Timer t; //Definición de pines de entrada #define encoder0PinA  2 #define encoder0PinB  3 #define encoder0Pulse 4 //Variables utilizadas tanto en la interrupción como en el void loop volatile unsigned int encoder0Pos = 0; volatile char indicadorDegiro; volatile boolean flagLCD=0;  //Bandera para refrescar LCD dentro del void loop //Bandera indicadora de pulsador presionado boolean flagPulse=0; LiquidCrystal_I2C lcd(0x27, 16, 2);  // Set the LCD I2C address void setup() {     lcd.begin();     Serial.begin (9600);       pinMode(encoder0PinA, INPUT_PULLUP);...