TP01-SE2018-PUNTO3

Dependencies:   mbed

main.cpp

Committer:
KilianPolkov
Date:
2018-06-05
Revision:
0:8519ab8e8a30

File content as of revision 0:8519ab8e8a30:

/* BOTON ARRIBA: 2do izquierda, BOTON ABAJO: 3ero izquierda, BOTON OK/STOP: 1ero derecha*/

/* consola */
/* pc.printf("TEMP: %d\n", temperaturaActual);
   pc.printf("TIME: %d\n", tiempoActual);
   pc.printf("MOTOR: %d\n", MOTOR_estado);
*/

#include "mbed.h"
#include <string.h>

/* -----definiciones----- */
#define DATA                1   // para mandar caracter al display LCD
#define CMND                0   // para configurar registro al display LCD
#define APRETADO            0   // para indicar el apretado del pulsador
#define NO_APRETADO         1   // para indicar el no apretado del pulsador

/* -----enumeraciones----- */
enum{MENU_MODO, MENU_TEMPERATURA, MENU_CENTRIFUGADO, MENU_TIEMPO, MENU_ENJUAGUE, MENU_LAVADO, CONFIG_MODO, CONFIG_TEMPERATURA, CONFIG_CENTRIFUGADO, CONFIG_TIEMPO, CONFIG_ENJUAGUE, LAVANDO, PAUSADO}; // SELECTOR_Step
enum{OFF, ENJUAGADO, ENJABONADO, SUAVIZADO, DESAGOTE, CENTRIFUGADO};                                                                                        // LAVADO_Step
enum{ALGODON, SINTETICO, PROGRAMA_BEBE, PESADO, RAPIDO};                                                                                                    // MODO_Step
enum{RPM_OFF = 0, RPM_MIN = 3, RPM_NORMAL = 6, RPM_MAX = 9};                                                                                                // CENTRIFUGADO_Step
enum{TEMP_MIN = 10, TEMP_BAJA = 20, TEMP_NORMAL = 30, TEMP_ALTA = 40, TEMP_MAX = 50};                                                                       // TEMP_Step
enum{TIEMPO_FINAL_MIN = 30, TIEMPO_FINAL_BAJO = 40, TIEMPO_FINAL_NORMAL = 50, TIEMPO_FINAL_MEDIO = 60, TIEMPO_FINAL_ALTO = 70, TIEMPO_FINAL_MAX = 80};      // TIEMPO_Step
enum{TIEMPO_OFF = 0, TIEMPO_MIN = 5, TIEMPO_NORMAL = 10, TIEMPO_MAX = 15};                                                                                  // ENJUAGUE_Step y variables tiempo
enum{PULS_NO_APRETADO, PULS_FLANCO_1, PULS_APRETADO, PULS_FLANCO_2};                                                                                        // PULS_Step
enum{NO_CALENTAR = 1, CALENTAR = 0};                                                                                                                        // ACTUADOR_Step
enum{NO_GIRAR = 0, GIRAR = 1};                                                                                                                              // MOTOR_Step

/* -----clases----- */
/* entradas */
DigitalIn PULSDOWN(PTB0);       // boton abajo
DigitalIn PULSUP(PTB1);         // boton arriba
DigitalIn PULSOK(PTB3);         // boton aceptar
AnalogIn LM35(PTC1);            // sensor de temperatura analogico
/* salidas */
DigitalOut CALENTADOR(LED1);    // es un led para indicar el encendido/apagado del CALENTADOR
DigitalOut MOTOR(PTC9);         // es el enable para el driver del MOTOR
PwmOut pwm(PTA5);               // es la señal para variar la velocidad del MOTOR
/* objetos */
Ticker timerMili;               // instancia de la clase Ticker
Ticker timerSeg;                // instancia de la clase Ticker
Serial pc(USBTX, USBRX);        // instancia de la clase Serial
I2C i2c(PTE0, PTE1);            // instancia de la clase I2C - PTEO: SDA (data), PTE1: SCL (clock)

typedef unsigned char BYTE;     // sirve para escribir "BYTE" en ves de "unsigned char" que es mas largo

/* -----variables globales----- */
/* modulo i2c */
const int address = 0x7E;       // address de 8bits I2C
int i2c_error = 0;              // si hay error en el ACK se pone en 1, sino en 0
char fila1[17];
char fila2[17];
/* sensor LM35 */
char i = 0;
float sensado[10], promedio;
/* estados de funciones */
BYTE SELECTOR_estado;           // SELECTOR_Step
BYTE LAVADO_estado;             // LAVADO_Step
BYTE LAVADO_ultimoEstado;       // LAVADO_Step
BYTE MODO_estado;               // MODO_Step
BYTE CENTRIFUGADO_estado;       // CENTRIFUGADO_Step
BYTE TEMP_estado;               // TEMP_Step
BYTE TIEMPO_estado;             // TIEMPO_Step
BYTE ENJUAGUE_estado;           // ENJUAGUE_Step
BYTE PULS_tout;                 // PULS_Step
BYTE ACTUADOR_estado;           // ACTUADOR_Step
BYTE MOTOR_estado;              // MOTOR_Step
/* estados de pulsadores */
BYTE PULSOK_estado, PULSUP_estado, PULSDOWN_estado; //variables utilizadas en la maquina de estados
/* variables maquinas de estados */
char temperaturaSeteada, temperaturaActual, rpmSeteado, vecesEnjuagado;
char tiempoActual, tiempoDiferido, tiempoSeteado, tiempoEnjuague, tiempoEnjabonado, tiempoSuavizado, tiempoDesagote, tiempoCentrifugado; // tiempos
    
/* -----prototipos funciones----- */
/* funciones generales */
void miliSegundo(void);                     // se ejecuta cada milisegundo
void segundo(void);                         // se ejecuta cada segundo
void initMCU(void);                         // se ejecuta una sola vez al inicializar el microcontrolador
void showTimeNow(void);                     // imprime en pantalla el tiempo actual
void detectForBack(void);                   // vuelve al menu principal MENU_MODO
void readSensor(void);                      // lee 10 valores y saca el promedio del sensor LM35
char isWashing(void);                       // devuelve true si esta lavando, sino false
/* funciones maquina de estados */
void SELECTOR_Step(void);                   // maquina de estados principal
void LAVADO_Step(void);                     // maquina de estados lavado
void MODO_Step(void);                       // maquina de estados para setear modo o programa (algodon, sintetico)
void CENTRIFUGADO_Step(void);               // maquina de estados para setear centrifugado (configura las RPM, si esta en 0 RPM es que no centrifuga)
void TEMP_Step(void);                       // maquina de estados para setear temperatura (para configurar manualmente la temperatura en vez de utilizar los modos o programas)
void TIEMPO_Step(void);                     // maquina de estados para setear el tiempo diferido (cuando finaliza el ciclo de lavado)
void ENJUAGUE_Step(void);                   // maquina de estados para setear ciclos de enjuague
void ACTUADOR_Step(void);                   // maquina de estados para activar/desactivar el calentador
void MOTOR_Step(void);                      // maquina de estados para activar/desactivar el motor
BYTE PULS_Step(BYTE PULSADOR, BYTE& estado);// maquina de estados para detectar el flanco de los pulsadores
/* funciones I2C */
void LCD_wr( BYTE dato );                   // funcion para escritura de un byte
/* funciones display LCD */
void LCD_init(void);                        // inicializacion del display LCD
void LCD_send(BYTE data, BYTE reset);       // manda 4 bits mas significativos, despues 4 bits menos significativos
void printstr(char* s);                     // muestra en el display LCD un string
void LCD_print(void);                       // muestra el display LCD       
    
int main() {
    LCD_init();
    initMCU();
    while(1) {
        /* ejecuta */
        SELECTOR_Step();     // maquina de estados principal
        LCD_print();         // printea en el LCD
        
        /* girar o no girar el motor */
        if(LAVADO_estado == ENJUAGADO || LAVADO_estado == CENTRIFUGADO) 
            MOTOR_estado = GIRAR;
        else 
            MOTOR_estado = NO_GIRAR;
            
        /* activa o desactiva el motor dependiendo de MOTOR_estado */
        MOTOR_Step();
            
        /* si esta lavando */
        if(isWashing()) {    // si no para de girar cuando esta pausado, CAMBIAR ACA
            showTimeNow();
            ACTUADOR_Step(); // maquina de estados para activar/desactivar el calentador
        }
    }
}

/* -----contador que se decrementa cada milisegundo----- */
void miliSegundo() {
    if(PULS_tout > 0) PULS_tout--;
}

/* -----cada segundo se decrementa el valor del temporizador(si no esta pausado) y tambien se lee el valor de temperatura del LM35----- */
void segundo() {
    readSensor();
    if(isWashing()) tiempoActual--;
}

/* -----guarda en el vector de la fila1 el tiempoActual----- */
void showTimeNow() {
    strcpy(fila1, "TIME ACTUAL:xxs ");
    fila1[12] = (tiempoActual / 10) + 0x30;
    fila1[13] = (tiempoActual % 10) + 0x30;    
}

/* -----vuelve al menu principal MENU_MODO----- */
void detectForBack() {
    if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_MODO; // cuando se presiona el pulsador vuelve al menu principal
}

/* -----lee 10 valores y saca el promedio del sensor LM35----- */
void readSensor(void) {
    promedio = 0;
    for(i = 0; i < 10; i++){
        sensado[i] = LM35.read(); 
    }
    for(i = 0; i < 10; i++){
        promedio += sensado[i]/10;
    }
    temperaturaActual = (promedio*3.25*100);
}

/* -----devuelve true si esta lavando, sino false----- */
char isWashing() {
   if(LAVADO_estado == ENJUAGADO || LAVADO_estado == ENJABONADO || LAVADO_estado == SUAVIZADO || LAVADO_estado == DESAGOTE || LAVADO_estado == CENTRIFUGADO) return 1; // devuelve true
   return 0; // si no se cumple la sentencia if, devuelve false
}

/* -----se ejecuta una sola vez al inicializar el microcontrolador----- */
void initMCU(void) {
    pc.printf("PROGRAMA INICIALIZADO\n");
    
    /* PWM */
    pwm.period_ms(10);
    pwm.pulsewidth_ms(RPM_OFF);
    pc.printf("pwm set to %.2f %%\n", pwm.read() * 100);
    
    /* TIMER */
    PULS_tout = TIEMPO_OFF;
    timerMili.attach(&miliSegundo, 0.001);  // timer en 1ms
    timerSeg.attach(&segundo, 1);           // timer en 1s
    
    /* SELECTOR_Step */
    SELECTOR_estado = MENU_MODO;
    
    /* LAVADO_Step */
    LAVADO_estado = OFF;
    tiempoCentrifugado = TIEMPO_OFF;    // se inicializa en 0s por si no se configura el centrifugado, se puede modificar
    tiempoEnjuague = TIEMPO_MIN;        // se inicializa en 5s, se puede modificar
    tiempoEnjabonado = TIEMPO_MIN;      // se inicializa en 5s, se puede modificar
    tiempoSuavizado = TIEMPO_MIN;       // se inicializa en 5s, se puede modificar
    tiempoDesagote = TIEMPO_MIN;        // se inicializa en 5s, se puede modificar
    vecesEnjuagado = 1;                 // se inicializa en 1, despues se incrementa hasta 3 porque es la cantidad maxima de enjuagues
    
    /* MODO_Step */
    MODO_estado = ALGODON;
    
    /* CENTRIFUGADO_Step */
    CENTRIFUGADO_estado = RPM_OFF;
    rpmSeteado = RPM_OFF; // se inicializa en 0rps, se puede modificar
    
    /* TEMP_Step */
    TEMP_estado = TEMP_MIN;
    
    /* TIEMPO_Step */
    TIEMPO_estado = TIEMPO_FINAL_BAJO;
    tiempoActual = tiempoDiferido = tiempoSeteado = TIEMPO_FINAL_BAJO; // se inicializa en 40s, se puede modificar
    
    /* PULSADORES */
    PULSOK_estado = PULS_NO_APRETADO;
    PULSUP_estado = PULS_NO_APRETADO;
    PULSDOWN_estado = PULS_NO_APRETADO;
    
    /* ACTUADOR_Step */
    ACTUADOR_estado = NO_CALENTAR;
    CALENTADOR = NO_CALENTAR;
    
    /* MOTOR_Step */
    MOTOR_estado = NO_GIRAR;
    
    /* ENJUAGUE_Step */
    ENJUAGUE_estado = TIEMPO_MIN;
} 

/* -----maquina de estados principal----- */
void SELECTOR_Step() {
    switch(SELECTOR_estado) {
        default:
        case MENU_MODO:
            strcpy(fila1, "MENU:           ");
            strcpy(fila2, "CONFIG MODE     ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_LAVADO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_TEMPERATURA;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = CONFIG_MODO;
            break;
        case MENU_TEMPERATURA:
            strcpy(fila2, "CONFIG TEMP     ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_MODO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_CENTRIFUGADO;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = CONFIG_TEMPERATURA;
            break;
        case MENU_CENTRIFUGADO:
            strcpy(fila2, "CONFIG RPM      ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_TEMPERATURA;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_TIEMPO;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = CONFIG_CENTRIFUGADO;
            break;
        case MENU_TIEMPO:
            strcpy(fila2, "CONFIG TIME     ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_CENTRIFUGADO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_ENJUAGUE;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = CONFIG_TIEMPO;
            break;
        case MENU_ENJUAGUE:
            strcpy(fila2, "CONFIG ENJUAGUE ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_TIEMPO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_LAVADO;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) SELECTOR_estado = CONFIG_ENJUAGUE;
            break;
        case MENU_LAVADO:
            strcpy(fila2, "COMENZAR          ");
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_ENJUAGUE;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) SELECTOR_estado = MENU_MODO;
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) {
                SELECTOR_estado = LAVANDO;
                LAVADO_estado = ENJUAGADO;
                tiempoSeteado -= tiempoEnjuague; //primer ciclo de lavado
            }
            break;
        case CONFIG_MODO:
            MODO_Step();
            detectForBack();
            break;
        case CONFIG_TEMPERATURA:
            TEMP_Step();
            detectForBack();
            break;
        case CONFIG_CENTRIFUGADO:
            CENTRIFUGADO_Step();
            detectForBack();
            break;
        case CONFIG_TIEMPO:
            TIEMPO_Step();
            detectForBack();
            break;
        case CONFIG_ENJUAGUE:
            ENJUAGUE_Step();
            detectForBack();
            break;
        case LAVANDO:
            LAVADO_Step();
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1) {
                LAVADO_estado = OFF;        // pone en OFF, es decir, deja de lavar en LAVADO_Step
                SELECTOR_estado = PAUSADO;  // va al estado PAUSADO del SELECTOR_Step
            }
            break;
        case PAUSADO:
            strcpy(fila2, "PAUSADO...      ");
            if(PULS_Step(PULSOK, PULSOK_estado) == PULS_FLANCO_1){ 
                LAVADO_estado = LAVADO_ultimoEstado; // vuelve al ultimo estado de LAVADO_estado
                SELECTOR_estado = LAVANDO;  // vuelve al estado LAVANDO del SELECTOR_Step
            }
            break;
    }
}

/* -----maquina de estados lavado----- */
void LAVADO_Step() {
    switch(LAVADO_estado) {
        default:
        case OFF:
            tiempoSeteado = tiempoActual = tiempoDiferido;
            vecesEnjuagado = 1;
            CALENTADOR = NO_CALENTAR;
            SELECTOR_estado = MENU_MODO;
            break;
        case ENJUAGADO:
            strcpy(fila2, "ENJUAGANDO...   ");
            /* finaliza tiempo enjuagado */ 
            if(tiempoActual == tiempoSeteado) {
                switch(vecesEnjuagado) {
                    case 1: /* finaliza primer enjuague */ 
                        tiempoSeteado -= tiempoEnjabonado; // segundo ciclo de lavado
                        LAVADO_estado = ENJABONADO;
                        break;
                    case 2: /* finaliza segundo enjuague, despues del enjabonado */
                        tiempoSeteado -= tiempoSuavizado; // cuarto ciclo de lavado
                        LAVADO_estado = SUAVIZADO;
                        break;
                    case 3: /* finaliza tercer enjuague, despues del suavizado */
                        tiempoSeteado -= tiempoDesagote; // sexto ciclo de lavado
                        LAVADO_estado = DESAGOTE;
                        break;
                }
            }
            LAVADO_ultimoEstado = ENJUAGADO;
            break;
        case ENJABONADO:
            strcpy(fila2, "ENJABONANDO...  ");
            /* finaliza tiempo enjabonado */ 
            if(tiempoActual == tiempoSeteado) {
                vecesEnjuagado++;
                tiempoSeteado -= tiempoEnjuague; // tercer ciclo de lavado
                LAVADO_estado = ENJUAGADO;
            }
            LAVADO_ultimoEstado = ENJABONADO;
            break;
        case SUAVIZADO:
            strcpy(fila2, "SUAVIZANDO...   ");
            /* finaliza tiempo suavizado */ 
            if(tiempoActual == tiempoSeteado) {
                vecesEnjuagado++;
                tiempoSeteado -= tiempoEnjuague; // quinto ciclo de lavado
                LAVADO_estado = ENJUAGADO;
            }
            LAVADO_ultimoEstado = SUAVIZADO;
            break;
        case DESAGOTE:
            strcpy(fila2, "DESAGOTANDO...  ");
            /* finaliza tiempo desagote */
            if(tiempoActual == tiempoSeteado && rpmSeteado != RPM_OFF) {
                tiempoSeteado -= tiempoCentrifugado; // septimo ciclo de lavado, se ejecuta solo si queres centrifugar
                LAVADO_estado = CENTRIFUGADO;
            }
            LAVADO_ultimoEstado = DESAGOTE;
            if(tiempoActual == 0) LAVADO_estado = OFF;
            break;
        case CENTRIFUGADO:
            strcpy(fila2, "CENTRIFUGANDO...");
            LAVADO_ultimoEstado = CENTRIFUGADO;
            if(tiempoActual == 0) LAVADO_estado = OFF;
            break;
    }
}

/* -----maquina de estados para setear modo o programa (algodon, sintetico, etc)----- */
void MODO_Step() {
    strcpy(fila1, "CONFIG:         ");
    switch(MODO_estado) {
        default:
        case ALGODON:
            strcpy(fila2, "MODO:ALGODON   ");
            temperaturaSeteada = TEMP_BAJA;
            tiempoEnjuague = TIEMPO_MAX; //15s tiempo enjuague
            if(rpmSeteado)
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_ALTO; //70s tiempo total, 10s tiempo centrifugado  
            else
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MEDIO; //60s tiempo total, 0s tiempo centrifugado
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) MODO_estado = PESADO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) MODO_estado = SINTETICO;
            break;
        case SINTETICO:
            strcpy(fila2, "MODO:SINTETICO ");
            temperaturaSeteada = TEMP_NORMAL;
            tiempoEnjuague = TIEMPO_NORMAL; //10s tiempo enjuague
            if(rpmSeteado)
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MEDIO; //60s tiempo total, 15s tiempo centrifugado
            else
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_NORMAL; //50s tiempo total, 0s tiempo centrifugado
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) MODO_estado = ALGODON;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) MODO_estado = RAPIDO;
            break;
        case RAPIDO:
            strcpy(fila2, "MODO:RAPIDO    ");
            temperaturaSeteada = TEMP_NORMAL;
            tiempoEnjuague = TIEMPO_MIN; //5s tiempo enjuague
            if(rpmSeteado)
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_BAJO; //40s tiempo total, 10s tiempo centrifugado
            else
                tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MIN; //30s tiempo total, 0s tiempo centrifugado
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) MODO_estado = SINTETICO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) MODO_estado = PROGRAMA_BEBE;
            break;
        case PROGRAMA_BEBE:
            strcpy(fila2, "MODO:BEBE      ");
            temperaturaSeteada = TEMP_MAX;
            tiempoEnjuague = TIEMPO_MAX; //15s tiempo enjuague
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MAX; //80s tiempo total, 20s tiempo centrifugado
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) MODO_estado = RAPIDO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) MODO_estado = PESADO;
            break;
        case PESADO:
            strcpy(fila2, "MODO:PESADO    ");
            temperaturaSeteada = TEMP_NORMAL;
            tiempoEnjuague = TIEMPO_MIN; //5s tiempo enjuague
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_NORMAL; //50s tiempo total, 20s tiempo centrifugado
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) MODO_estado = PROGRAMA_BEBE;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) MODO_estado = ALGODON;
            break;
    }
}

/* -----maquina de estados para setear centrifugado (configura las RPM, si esta en 0 RPM es que no centrifuga)----- */
void CENTRIFUGADO_Step() {
    strcpy(fila1, "CONFIG:         ");
    strcpy(fila2, "RPM SET:xx      ");
    fila2[8] = (rpmSeteado / 10) + 0x30;
    fila2[9] = (rpmSeteado % 10) + 0x30; 
    switch(CENTRIFUGADO_estado) {
        default:
        case RPM_OFF:
            rpmSeteado = RPM_OFF;
            pwm.pulsewidth_ms(RPM_OFF);
            tiempoCentrifugado = TIEMPO_OFF;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_MAX;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_MIN;
            break;
        case RPM_MIN:
            rpmSeteado = RPM_MIN;
            pwm.pulsewidth_ms(RPM_MIN);
            tiempoCentrifugado = TIEMPO_MIN;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_OFF;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_NORMAL;
            break;
        case RPM_NORMAL:
            rpmSeteado = RPM_NORMAL;
            pwm.pulsewidth_ms(RPM_NORMAL);
            tiempoCentrifugado = TIEMPO_MIN;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_MIN;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_MAX;
            break;
        case RPM_MAX:
            rpmSeteado = RPM_MAX;
            pwm.pulsewidth_ms(RPM_MAX);
            tiempoCentrifugado = TIEMPO_MIN;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_NORMAL;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) CENTRIFUGADO_estado = RPM_OFF;
            break;
    }
}

/* -----maquina de estados para setear temperatura (para configurar manualmente la temperatura en vez de utilizar los modos o programas)----- */
void TEMP_Step() {
    strcpy(fila1, "TEMP NOW:xxg    ");
    fila1[9] = (temperaturaActual / 10) + 0x30;
    fila1[10] = (temperaturaActual % 10) + 0x30;
    fila1[11] = 0xDF; // para el simbolo de grado
    strcpy(fila2, "TEMP SET:xxg    ");
    fila2[9] = (temperaturaSeteada / 10) + 0x30;
    fila2[10] = (temperaturaSeteada % 10) + 0x30;
    fila2[11] = 0xDF; // para el simbolo de grado
    switch(TEMP_estado) {
        default:
        case TEMP_MIN:
            temperaturaSeteada = TEMP_MIN;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_MAX;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_BAJA;
            break;
        case TEMP_BAJA:
            temperaturaSeteada = TEMP_BAJA;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_MIN;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_NORMAL;
            break;
        case TEMP_NORMAL:
            temperaturaSeteada = TEMP_NORMAL;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_BAJA;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_ALTA;
            break;
        case TEMP_ALTA:
            temperaturaSeteada = TEMP_ALTA;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_NORMAL;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_MAX;
            break;
        case TEMP_MAX:
            temperaturaSeteada = TEMP_MAX;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_ALTA;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TEMP_estado = TEMP_MIN;
            break;
    }
}

/* -----maquina de estados para setear el tiempo diferido (cuando finaliza el ciclo de lavado)----- */
void TIEMPO_Step() {
    strcpy(fila1, "CONFIG:         ");
    strcpy(fila2, "TIME SET:x      ");
    fila2[9] = (tiempoDiferido / 10) + 0x30;
    fila2[10] = (tiempoDiferido % 10) + 0x30; 
    switch(TIEMPO_estado) {
        default:
        case TIEMPO_FINAL_BAJO:
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_BAJO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_NORMAL;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_MAX;
            break;
        case TIEMPO_FINAL_NORMAL:
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_NORMAL;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_MEDIO;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_BAJO;
            break;
        case TIEMPO_FINAL_MEDIO:
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MEDIO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_ALTO;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_NORMAL;
            break;
        case TIEMPO_FINAL_ALTO:
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_ALTO;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_MAX;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_MEDIO;
            break;
        case TIEMPO_FINAL_MAX:
            tiempoSeteado = tiempoActual = tiempoDiferido = TIEMPO_FINAL_MAX;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_BAJO;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) TIEMPO_estado = TIEMPO_FINAL_ALTO;
            break; 
    }
}

/* -----maquina de estados para setear ciclos de enjuague----- */
void ENJUAGUE_Step() {
    strcpy(fila1, "CONFIG:         ");
    strcpy(fila2, "TIME ENJUAGUE:xx");
    fila2[14] = (tiempoEnjuague / 10) + 0x30;
    fila2[15] = (tiempoEnjuague % 10) + 0x30;
    switch(ENJUAGUE_estado) {
        default:
        case TIEMPO_MIN:
            tiempoEnjuague = TIEMPO_MIN;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_NORMAL;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_MAX;
            break;
        case TIEMPO_NORMAL:
            tiempoEnjuague = TIEMPO_NORMAL;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_MAX;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_MIN;
            break;
        case TIEMPO_MAX:
            tiempoEnjuague = TIEMPO_MAX;
            if(PULS_Step(PULSUP, PULSUP_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_MIN;
            if(PULS_Step(PULSDOWN, PULSDOWN_estado) == PULS_FLANCO_1) ENJUAGUE_estado = TIEMPO_NORMAL;
            break;
    }
}

/* -----maquina de estados para activar/desactivar el calentadorl----- */
void ACTUADOR_Step() {
    switch(ACTUADOR_estado) {
        default:
        case NO_CALENTAR:
            CALENTADOR = NO_CALENTAR;
            if(temperaturaActual < temperaturaSeteada) ACTUADOR_estado = CALENTAR;
            break;
        case CALENTAR:
            CALENTADOR = CALENTAR;
            if(temperaturaActual >= temperaturaSeteada) ACTUADOR_estado = NO_CALENTAR;
            break;
    }
}

/* -----maquina de estados para activar/desactivar el motor----- */
void MOTOR_Step() {
    switch(MOTOR_estado) {
        default:
        case NO_GIRAR:
            MOTOR = NO_GIRAR;
            break;
        case GIRAR:
            MOTOR = GIRAR;
            break;
    }
}

/* -----maquina de estados para detectar el flanco de los pulsadores----- */
BYTE PULS_Step(BYTE PULSADOR, BYTE& estado) {
    switch(estado){
        default:
        case PULS_NO_APRETADO:
            if(PULSADOR == APRETADO && PULS_tout == 0){
                estado = PULS_FLANCO_1;
                PULS_tout = 5; // 5ms de espera
            }
            break;
        case PULS_FLANCO_1:
            if(PULSADOR == APRETADO && PULS_tout == 0){
                estado = PULS_APRETADO;
                PULS_tout = 5; // 5ms de espera
            }
            if(PULSADOR == NO_APRETADO && PULS_tout == 0){
                estado = PULS_NO_APRETADO;
                PULS_tout = 5; // 5ms de espera
            }
            break;  
        case PULS_APRETADO:
            if(PULSADOR == NO_APRETADO && PULS_tout == 0){
                estado = PULS_NO_APRETADO;
                PULS_tout = 5; //5ms de espera
            }
            break;  
    }
    return estado;
}

/* -----escribe un byte----- */
void LCD_wr( BYTE dato ) {
    dato = dato & 0xF0; // hace una mascara con 0b11110000 para que queda los 4 MSB
    do{
        i2c.start();
        i2c_error = i2c.write( address );
    }while( i2c_error == 0 ); /* espera fin ciclo escritura (ACK polling) */
    /* Primero mando los 4 bits mas significativos */
    i2c.write( dato | 0x09 );  // esta mascara pone BACKLIGHT = 1, ENABLE = 0, RW = 0, RESET = 1
    i2c.write( dato | 0x0D );  // esta mascara pone BACKLIGHT = 1, ENABLE = 1, RW = 0, RESET = 1
    i2c.write( dato | 0x09 );  // esta mascara pone BACKLIGHT = 1, ENABLE = 0, RW = 0, RESET = 1
    /* Mando STOP */
    i2c.stop();
}

/* -----escribe 4 MSB, luego 4 LSB, si reset = 1 es porque manda un caracter, si reset = 0 configura registro----- */
void LCD_send(BYTE data, BYTE reset) {
    BYTE DataHIGH, DataLOW;
    DataHIGH = data & 0xF0;         // hace una mascara con 0b11110000 para que queda los 4 MSB
    DataLOW = ( data << 4 ) & 0xF0; // mueve los 4 LSB a la izquierda
    do{
        i2c.start();
        i2c_error = i2c.write( address );
    }while( i2c_error == 0 ); /* espera fin ciclo escritura (ACK polling) */
    /* primero mando los 4 bits mas significativos */
    i2c.write( DataHIGH | ( 0x0C | reset ) );   // esta mascara pone BACKLIGHT = 1, ENABLE = 1, RW = 0, RESET = X
    i2c.write( DataHIGH | ( 0x08 | reset ) );   // esta mascara pone BACKLIGHT = 1, ENABLE = 0, RW = 0, RESET = X
    /* despues mando los 4 bits menos significativos */
    i2c.write( DataLOW | ( 0x0C | reset ) );    // esta mascara pone BACKLIGHT = 1, ENABLE = 1, RW = 0, RESET = X
    i2c.write( DataLOW | ( 0x08 | reset ) );    // esta mascara pone BACKLIGHT = 1, ENABLE = 0, RW = 0, RESET = X
    i2c.write( DataLOW | 0x0C );                // esta mascara pone BACKLIGHT = 1, ENABLE = 1, RW = 0, RESET = 0
    /* mando STOP */
    i2c.stop(); 
}

/* -----inicializacion LCD----- */
void LCD_init() {
    i2c.frequency(300000);
    wait(0.4);
    LCD_wr( 0x30 );
    LCD_wr( 0x30 );
    LCD_wr( 0x30 );
    LCD_wr( 0x20 );             /* --- modo 4 bit --- */
    LCD_send( 0x28 , CMND );    /* --- modo 4b - 2 lin - car 5x7 --- */
    LCD_send( 0x08 , CMND );    /* --- apaga display --- */
    LCD_send( 0x01 , CMND );    /* --- clear --- */
    wait(0.2);
    LCD_send( 0x0C , CMND );    /* --- disp on - cur off - blink off --- */
    LCD_send( 0x06 , CMND );    /* --- inc - no scroll --- */
    pc.printf("DISPLAY INICIALIZADO\n");
}

/* -----muestra string en el display LCD----- */
void printstr(char* s) {
    /* recorre el vector s (el string parametro de la funcion), hasta que llega al final "\0" */
    for (char i = 0; s[i] != '\0'; i++) LCD_send(s[i], DATA);
}

/* -----muestra en el display LCD los vectores fila1 y fila2----- */
void LCD_print() {
    LCD_send( 0x80 , CMND );    // posiciona en columna de arriba, y en la primer linea
    printstr(fila1);            // una vez posicionado, muestra el texto en la fila 1
    LCD_send( 0xC0 , CMND );    // posiciona en columna de abajo, y en la segunda linea
    printstr(fila2);            // una vez posicionado, muestra el texto en la fila 2
}