/** * Name: Arduino - Menu for Shield LCD * Autor: Alberto Gil Tesa * Web: http://giltesa.com * License: CC BY-NC-SA 3.0 * Date: 2016/10/22 * * Arduino Uno, Pinout: * _______________ * | USB | * RELE A1 |13 12| * |3V3 11| * |AREF 10| * APAD |A0 9| LCD * |A1 8| LCD * |A2 7| LCD * |A3 6| LCD * |A4 5| LCD * |A5 4| LCD * | 3/SCL| * | 2/SDA| * |5V GND| * |RST RST| * |GND 1/INT2/RX| * |VIN 0/INT3/TX| * |MISO SS| * |SCK MOSI| * |_______________| * */ /*******************************/ /***** LIBRERIAS Y OBJETOS *****/ /*******************************/ //#include //LCD I2C //#include //LCD I2C //#include //LCD I2C #include //SHIELD LCD #include LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //LiquidCrystal_I2C lcd( 0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE ); /*******************************/ /********* CONSTANTES **********/ /*******************************/ #define TYPE_RELEA 1 #define TYPE_RELEB 2 #define TYPE_BOOL 3 #define TYPE_INT 4 // Generador de iconos: http://mikeyancey.com/hamcalc/lcd_characters.php byte ico0[8] = { B00000, B00010, B00010, B00010, B11111, B11111, B11111, B00000 }; // Emisora byte ico1[8] = { B00000, B01110, B01010, B01110, B00100, B00100, B00100, B00000 }; // Microfono byte ico2[8] = { B00001, B00011, B00101, B00001, B11101, B10100, B10100, B11100 }; // Digital byte ico3[8] = { B00000, B00000, B11100, B11111, B10001, B11111, B11111, B00000 }; // Grabadora byte ico4[8] = { B00000, B00010, B00110, B11110, B11110, B00110, B00010, B00000 }; // Llamador byte ico5[8] = { B00000, B00000, B11111, B11111, B10101, B10001, B11111, B00000 }; // Mensaje byte ico6[8] = { B00000, B00000, B10000, B11000, B11110, B11111, B00000, B00000 }; // Pedal byte ico7[8] = { B00000, B00100, B00110, B11111, B00110, B00100, B00000, B00000 }; // Flecha const byte icoEmisora=0, icoMicrofono=1, icoDigital=2, icoGrabadora=3, icoLlamador=4, icoMensaje=5, icoPedal=6, icoFlecha=7; /* RELES A */ const byte zRELE_A = 5; const char *nRELE_A[] = { "1. OPCION 1 ", "2. OPCION 2 ", "3. OPCION 3 ", "4. OPCION 4 ", "5. OPCION 5 " }; const byte iRELE_A[] = { icoEmisora, icoEmisora, icoEmisora, icoEmisora, icoEmisora }; /* RELES B */ const byte zRELE_B = 4; const char *nRELE_B[] = { "1. MICROFONO ", "2. MODOS DIGITAL", "3. GRABADORA ", "4. LLAMADOR " }; const char iRELE_B[] = { icoMicrofono, icoDigital, icoGrabadora, icoLlamador }; /* TEXTOS MENUS */ const char *nMENU[] = { "Rele GrupoA ", "Rele GrupoB ", "Rele Msg Es ", "Rele Msg T. ", "Rele Msg T. ", "Rele Aux ", "Rele Pedal ", "Guardar salir ", "No guardar salir", "Salir " }; /*******************************/ /** ESTRUCTURAS CONFIGURACION **/ /*******************************/ struct MYDATA{ int initialized; int sGroupA; // Estado rele grupo A -1(OFF), 0(R1), 1(R2), 2(R3), 3(R4), 4(R5) int sGroupB; // Estado rele grupo B -1(OFF), 0(R1), 1(R2), 2(R3), 3(R4) int sMsg; // Estado rele mensaje 0, 1 int tMsgSleep; // Tiempo pausa rele mensaje 0~32767 segundos int tMsgWork; // Tiempo trabajo rele mensaje 0~32767 segundos int sAux; // Estado rele auxiliar 0, 1 int tPedalWork; // Tiempo trabajo rele pedal 0~32767 segundos }; union MEMORY{ MYDATA d; byte b[sizeof(MYDATA)]; } memory; /*******************************/ /***** VARIABLES GLOBALES ******/ /*******************************/ unsigned long tNow = 0; unsigned long tPedalBefore = 0; unsigned long tMsgSleepBefore = 0; unsigned long tMsgWorkBefore = 0; boolean updateStatus = true; boolean btnLeft = false; boolean btnRight = false; boolean btnCenter = false; boolean btnPedal = false; boolean bPedal = false; boolean exitMenu = false; byte menuPosition = 0; const byte menuOptions = 10; // Numero de opciones de configuracion del menu principal const byte rowsLCD = 2; // Numero de filas del LCD const byte columnsLCD = 16; // Numero de columnas del LCD /** * Configura el Arduino y carga la ultima configuracion. */ void setup() { // Carga la configuracion de la EEPROM, y la configura la primera vez: readConfiguration(); // Inicia el LCD: lcd.begin(columnsLCD, rowsLCD); //lcd.backlight(); lcd.createChar( icoEmisora, ico0 ); lcd.createChar( icoMicrofono, ico1 ); lcd.createChar( icoDigital, ico2 ); lcd.createChar( icoGrabadora, ico3 ); lcd.createChar( icoLlamador, ico4 ); lcd.createChar( icoMensaje, ico5 ); lcd.createChar( icoPedal, ico6 ); lcd.createChar( icoFlecha, ico7 ); // Imprime la informacion del proyecto: lcd.setCursor(0,0); lcd.print("Menu Shield LCD "); lcd.setCursor(0,1); lcd.print(" giltesa.com "); delay(2000); lcd.clear(); } /** * */ void loop() { tNow = seconds(); readButtons(); if( btnPedal && !bPedal ){ bPedal = true; tPedalBefore = tNow; } else if( btnPedal && bPedal ){ bPedal = false; } if( btnCenter ) openMenu(); // Tareas que se ejecutan solo cada 1 segundo: if( millis()%990 == 0 ) { // Actualiza LCD linea 1 y 2: Con estado de los reles del grupo A y B: lcd.setCursor(0,0); if( memory.d.sGroupA == -1 ){ lcd.print(" OFF "); }else{ lcd.write(iRELE_A[memory.d.sGroupA]); lcd.print(nRELE_A[memory.d.sGroupA]); } lcd.setCursor(0,1); if( memory.d.sGroupB == -1 ){ lcd.print(" OFF "); }else{ lcd.write(iRELE_B[memory.d.sGroupB]); lcd.print(nRELE_B[memory.d.sGroupB]); } } } /** * Muestra el Menu principal en el LCD. */ void openMenu() { lcd.clear(); while( !exitMenu ) { readButtons(); if( btnPedal ) { exitMenu = true; } else if( btnLeft && menuPosition-1 >= 0 ) { menuPosition--; } else if( btnRight && menuPosition+1 < menuOptions ) { menuPosition++; } else if( btnCenter ) { switch( menuPosition ) { case 0: openSubMenu( 0, TYPE_RELEA, &memory.d.sGroupA, -1, 4 ); break; // Rele Grupo A case 1: openSubMenu( 1, TYPE_RELEB, &memory.d.sGroupB, -1, 3 ); break; // Rele Grupo B case 2: openSubMenu( 2, TYPE_BOOL, &memory.d.sMsg, 0, 1 ); break; // Rele Msg Estado case 3: openSubMenu( 3, TYPE_INT, &memory.d.tMsgSleep, 0, 32767 ); break; // Rele Msg T. reposo case 4: openSubMenu( 4, TYPE_INT, &memory.d.tMsgWork, 0, 32767 ); break; // Rele Msg T. func. case 5: openSubMenu( 5, TYPE_BOOL, &memory.d.sAux, 0, 1 ); break; // Rele Aux case 6: openSubMenu( 6, TYPE_INT, &memory.d.tPedalWork, 0, 32767 ); break; // Rele Pedal T. apag case 7: writeConfiguration(); exitMenu = true; break; // Guarda y sale case 8: readConfiguration(); exitMenu = true; break; // Cancela los cambios y sale case 9: exitMenu = true; break; // Sale, pero mantiene los cambios temporalmente } } if( !exitMenu && millis()%500 == 0 ) { if( menuPosition % rowsLCD == 0 ) { for( int i=menuPosition ; i<(menuPosition+rowsLCD) ; i++ ) { lcd.setCursor(1, i % rowsLCD); lcd.print( i= minValue ) { (*value)--; } else if( btnRight && (*value)+1 <= maxValue ) { (*value)++; } if( !exitMenu && millis()%250 == 0 ) { lcd.setCursor(0,0); lcd.print(nMENU[nameID]); lcd.setCursor(0,1); lcd.print("<"); lcd.setCursor(columnsLCD-1,1); lcd.print(">"); if( typeMenu == TYPE_RELEA ) { lcd.setCursor(1,1); lcd.print(*value > minValue ? nRELE_A[*value] : "OFF " ); } else if( typeMenu == TYPE_RELEB ) { lcd.setCursor(1,1); lcd.print(*value > minValue ? nRELE_B[*value] : "OFF " ); } else if( typeMenu == TYPE_BOOL ) { lcd.setCursor(columnsLCD/2-2,1); lcd.print(*value == 0 ? "OFF" : "ON "); } else if( typeMenu == TYPE_INT ) { lcd.setCursor(columnsLCD/2-4,1); lcd.print(*value); lcd.print(" seg "); } } } exitMenu = false; menuPosition = 0; lcd.clear(); } /** * */ void readConfiguration() { for( int i=0 ; i < sizeof(memory.d) ; i++ ) memory.b[i] = EEPROM.read(i); if( !memory.d.initialized ) { memory.d.initialized = true; memory.d.sGroupA = -1; memory.d.sGroupB = -1; memory.d.sMsg = false; memory.d.tMsgSleep = 0; memory.d.tMsgWork = 0; memory.d.sAux = false; memory.d.tPedalWork = 0; } } /** * */ void writeConfiguration() { for( int i=0 ; i