Buenas noches a todos
Quiero compartir con ustedes algo que hice para aprender a realizar maquina de estados con interrupción interna.
Está funcionando en Arduino Due con un display Robot.
Utilice estas librerías #include <LiquidCrystal.h> #include <DueTimer.h>
Se trata de una idea simple, un led que parpadea a un ritmo y este se modifica según el botón que se mantenga presionado, incluso se puede modificar en forma independiente el tiempo de encendido y apagado.
Al hacerlo con interrupciones internas no hay demoras en el funcionamiento, ya que no se utiliza la función Delay.
Por otro lado la máquina de estados permite separar las funciones que debe realizar el programa.
En estado de reposo el display indica "opciones listas " y "normal"
Al presionar el botón de arriba el display indica " rápido" y el led acelera su ritmo.
El botón de abajo lo hace mas lento.
El de la izquierda lo mantiene permanentemente prendido.
El de la derecha lo apaga.
Por último el segundo de la izquierda lo hace asimétrico, el tiempo prendido es menor al apagado.
Modificando esta estructura se puede utilizar en varios proyectos.
Espero que sea útil.
Este es el código. Cuando no es muy grande es mejor postearlo a ponerlo en un archivo zipeado que pocos veremos.
#include <LiquidCrystal.h>
#include <DueTimer.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // DEFINE LOS PINES PARA EL DISPLAY
int timer_1=0;
int timer_2=0;
int timer_recarga_1=0;
int timer_recarga_2=0;
unsigned char estado=0;
unsigned char estado_1=0;
unsigned char estado_2=0;
unsigned char flag_1=0;
unsigned char flag_2=0;
unsigned char prendido=1;
unsigned char apagado=0;
int lcd_key =0;
int adc_key_in = 0;
#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
//RUTINA DE INTERRUPCION DE TIMER
void irq_timer() { //ENTRA CADA VEZ QUE SE PRODUCE UNA INTERRUPCION DE TIMER
timer_1--; //DEFINE EL TIEMPO DE TIMER 1
if (timer_1<=0)
flag_1=1;
timer_2--; //DEFINE EL TIEMPO DE TIMER 2
if (timer_2<=0)
flag_2=1;
}
//FUNCION PARA LEER LOS BOTOS TIENEN RESISTENCIAS, VARIAN EL VALOR DE TENSION EN LA ENTRADA ANALOGICA CERO
int read_LCD_buttons() {
adc_key_in = analogRead(0); // LEE LOS VALORES DE LA ENTRADA ANALOGICA Y LOS GUARDA EN LA VARIABLE adc_key_in
if (adc_key_in > 1000) return btnNONE; // VALOR SIN APRETAR NADA
if (adc_key_in < 50) return btnRIGHT; // VALORES PARA LOS DIFERENTES BOTONES Y LO QUE DEVUELVE LA FUNCION SI SE CUMPLE LA CONDICION
if (adc_key_in < 250) return btnUP;
if (adc_key_in < 450) return btnDOWN;
if (adc_key_in < 650) return btnLEFT;
if (adc_key_in < 1000) return btnSELECT;
return btnNONE; // CUANDO TODOS FALLAN DEVUELVA ESTE
}
//MAQUINA DE ESTADO UNO LA FUNCION ES PRENDER Y APAGAR EL LED
void maquinaEstado_1(void) {
switch(estado_1) {
case 0: //CUANDO EL ESTADO VALE 0
digitalWrite(53, prendido); // PRENDE LED SE UTILIZA LA VARIABLE prendido PARA PODER MODIFICARLA MAS ADELANTE
timer_1 = timer_recarga_1;
flag_1 = 0;
estado_1 = 1;
break;
case 1:
if(flag_1 == 1)
estado_1 = 2;
break;
case 2:
digitalWrite(53, apagado); // APAGA LED SE UTILIZA LA VARIABLE apagado PARA PODER MODIFICARLA MAS ADELANTE
timer_2 = timer_recarga_2;
flag_2 = 0;
estado_1=3;
break;
case 3:
if(flag_2==1)
estado_1 = 4;
break;
case 4:
estado_1 = 0;
break;
}
}
// MAQUINA DE ESTADO DOS MODIFICA LOS TIMER PARA CAMBIAR EL RITMO DEL LED PRENDIDO Y APAGADO EN FORMA INDEPENDIENTE Y EL TEXTO SEGUN EL BOTON
void maquinaEstado_2(void) {
switch (lcd_key) { // DEPENDE DEL BOTON APRETADO ENTRA EN EL CASE
case btnRIGHT: // PARA BOTON DERECHO EL LED QUEDA APAGADO PERMANENTE
lcd.setCursor(0,1); //UBICA EL CURSOR EN LA POSICION UNO DE LA SEGUNDA FILA
lcd.print(" APAGADO ");
digitalWrite(53, LOW);
prendido=0;
apagado=0;
break;
case btnLEFT: // PARA BOTON IZQUIERDO LED ENCENDIDO PERMANENTE
lcd.setCursor(0,1);
lcd.print(" FIJO ");
digitalWrite(53, HIGH);
prendido=1;
apagado=1;
break;
case btnUP: // PARA BOTON DE ARRIBA TITILA RAPIDO
lcd.setCursor(0,1);
lcd.print(" RAPIDO ");
timer_recarga_1=150;
timer_recarga_2=150;
break;
case btnDOWN: // PARA BOTON DE ABAJO TITILA LENTO
lcd.setCursor(0,1);
lcd.print(" LENTO ");
timer_recarga_1=1000;
timer_recarga_2=1000;
break;
case btnSELECT: // BOTON SELECCION NO UTILIZADO
lcd.setCursor(0,1);
lcd.print(" ASIMETRICO ");
timer_recarga_1=200;
timer_recarga_2=1200;
break;
case btnNONE: // CUANDO NO HAY BOTON APRETADO TITILA INTERMEDIO
lcd.setCursor(0,1);
lcd.print(" NORMAL ");
timer_recarga_1=500;
timer_recarga_2=500;
prendido=1;
apagado=0;
break;
}
}
void setup() {
pinMode(53, OUTPUT); //DEFINE EL PIN DONDE ESTA EL LED Y LO PONE COMO SALIDA
lcd.begin(16, 2); // DEFINE DISPLAY DE 16 * 2
Timer3.start(1000); // INTERRUMPE CADA 1mS
Timer3.attachInterrupt(irq_timer); // LLAMA A LA RUTINA DE INTERRUPCION
}
void loop() {
lcd_key = read_LCD_buttons(); // GUARDA EN LA VARIABLE (LCD_KEY) LO QUE RETORNA LA FUNCION QUE LEE LOS BOTONES
lcd.setCursor(0,0); // EL CURSOR A LA PRIMERA POSICION DEL PRIMER RENGLON
lcd.print("OPCIONES LISTAS"); // ESCRIBE EN EL DISPLAY
maquinaEstado_1(); // VA A EJECUTAR LA MAQUINA DE ESTADOS UNO
maquinaEstado_2(); // VA A EJECUTAR LA MAQUINA DE ESTADOS DOS
}