commit 69a9e12d0ca9c032320e5592d26e329f94aea4e5 Author: Arturo Corro Date: Mon Mar 15 23:01:21 2021 -0600 First commit diff --git a/Dosificador_LCD2004_4buttons/Dosificador_LCD2004_4buttons.ino b/Dosificador_LCD2004_4buttons/Dosificador_LCD2004_4buttons.ino new file mode 100644 index 0000000..719a1d5 --- /dev/null +++ b/Dosificador_LCD2004_4buttons/Dosificador_LCD2004_4buttons.ino @@ -0,0 +1,1047 @@ +/***************************************** +* Dosificador_LCD2004_4buttons * +* 15/03/2021 * +* Versión 0.1.0 * +* koneko.mx * +*****************************************/ + +#include +#include + +/************************************************** +* Definición de Constantes +**************************************************/ + // LCD2004 I2C + #define LCD_I2C_ADDRESS 0x27 + + // PINOUT + #define RELAY_PIN 4 + #define DOSING_BUTTON_PIN 3 + #define SETTINGS_BUTTONS_PIN A2 + + // BUTTON SETTINGS + #define SETTING_BUTTON_IN_VAL 15 + #define SETTING_BUTTON_OUT_VAL 92 + #define SETTING_BUTTON_UP_VAL 42 + #define SETTING_BUTTON_DOWN_VAL 67 + + #define SETTING_BUTTON_TOLERANCE_READ 2 + #define SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS 80 + #define SETTING_BUTTON_DELAY_MILLIS 450 + + // BLOQUES DE MEMORIA EEPROM + #define BUTTON_SENSITIVITY_EEPROM_ADDRESS 0 + #define PRESS_BUTTON_EEPROM_ADDRESS 1 + #define HOLD_DOWN_BUTTON_EEPROM_ADDRESS 2 + #define LAG_TIME_MIN_EEPROM_ADDRESS 3 // Minutos, tiempo de retraso + #define LAG_TIME_SEG_EEPROM_ADDRESS 4 // Segundo, tiempo de retraso + #define LAG_TIME_DEC_EEPROM_ADDRESS 5 // Décimas de segundo, tiempo de retraso + #define DOSING_TIME_MIN_EEPROM_ADDRESS 6 // Minutos, tiempo dosificación + #define DOSING_TIME_SEG_EEPROM_ADDRESS 7 // Segundos, tiempo dosificación + #define DOSING_TIME_DEC_EEPROM_ADDRESS 8 // Décimas de segundo, tiempo dosificación + + // FACTORY SETTINGS + #define BUTTON_SENSITIVITY_DEFAULT_VALUE 9 + #define PRESS_BUTTON_DEFAULT_VALUE 3 + #define HOLD_DOWN_BUTTON_DEFAULT_VALUE 1 + #define LAG_TIME_MIN_DEFAULT_VALUE 0 // Minutos, tiempo de retraso + #define LAG_TIME_SEG_DEFAULT_VALUE 3 // Segundo, tiempo de retraso + #define LAG_TIME_DEC_DEFAULT_VALUE 5 // Décimas de segundo, tiempo de retraso + #define DOSING_TIME_MIN_DEFAULT_VALUE 1 // Minutos, tiempo dosificación + #define DOSING_TIME_SEG_DEFAULT_VALUE 10 // Segundos, tiempo dosificación + #define DOSING_TIME_DEC_DEFAULT_VALUE 9 // Décimas de segundo, tiempo dosificación + + // SETTINGS MENU + #define ALL_SETTINGS 0 + #define OUT_OF_MENU 0 + + #define IN_SENSITIVITY_BUTTON 1 + #define IN_PRESS_BUTTON 2 + #define IN_HOLD_DOWN_BUTTON 3 + #define IN_LAG 4 + #define IN_DOSING 5 + #define IN_FACTORY_RESET 6 + #define IN_RESTART 7 + #define IN_EXIT 8 + + #define VIEW 0 + #define UPDATE 1 + + #define POSITION_ONE 0 + #define POSITION_TWO 1 + #define POSITION_THREE 2 + + #define MODE_1 0 + #define MODE_2 1 + #define MODE_3 2 + #define FACTORY_RESET 3 + #define RESTART 4 + #define CANCEL 5 + + #define AUTO_EXIT_MENU_MILLIS 15000 + #define BLINK_MILLIS 1600 + #define LCD_PROCESS_REFRESH_MILLIS 333 + + // DISPENSER + #define DISPENSER_RESTART 10 + #define DISPENSER_IDLE 0 + #define DISPENSER_DETECTING 1 + #define DISPENSER_LAG 2 + #define DISPENSER_DOSING 3 + #define DISPENSER_BLOCK 4 + + // STATUS RELAY + #define RELAY_HIGH HIGH + #define RELAY_LOW LOW + + // STATUS BUTTON + #define DOSING_BUTTON_PUSH 0 + #define DOSING_BUTTON_IDLE 1 + + +/************************************************** +* Debug +* Define DEBUG_SERIAL_ENABLE to enable debug serial. +* Comment it to disable debug serial. +**************************************************/ + //#define DEBUG_SERIAL_ENABLE + + #define dbSerial Serial + + #ifdef DEBUG_SERIAL_ENABLE + #define serialPrint(a) dbSerial.print(a) + #define serialPrintln(a) dbSerial.println(a) + #define serialBegin(a) dbSerial.begin(a) + #define serialBeginWhile(a) while(!dbSerial) delay(1) + #else + #define serialPrint(a) do{}while(0) + #define serialPrintln(a) do{}while(0) + #define serialBegin(a) do{}while(0) + #define serialBeginWhile(a) do{}while(0) + #endif + + +/************************************************** +* ENVIRONMENT VARIABLES +**************************************************/ + // Dosing + uint16_t button_sensitivity_millis; + uint8_t press_button_mode; + uint8_t hold_down_button_mode; + uint16_t lag_time_decseg; + uint16_t dosing_time_decseg; + + uint32_t button_pressed_millis; + uint8_t release_button; + + uint8_t dispenser_status; + uint32_t dispenser_status_time_millis; + + // 4-button configuration + uint8_t button_values[] = {SETTING_BUTTON_IN_VAL, SETTING_BUTTON_OUT_VAL, SETTING_BUTTON_UP_VAL, SETTING_BUTTON_DOWN_VAL}; + uint32_t _bt[sizeof(button_values)]; // millis + uint32_t confirmation_repeats_millis; + + uint8_t menu_section; + uint8_t menu_status; + uint8_t menu_cursor_var; + + uint8_t setup_var[3]; + + uint32_t last_change_menu_millis; + + + // LCD2004 Render + LiquidCrystal_I2C lcd(LCD_I2C_ADDRESS, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); + + String menu[] = { + "SENSIBILIDAD BOTON", + "AL PRESIONAR BOTON", + "AL MANTENER PRESIO", + "RETARDO AL INICIAR", + "TIEMPO DOSIFICACION", + "VALORES DE FABRICA", + "REINICIAR", + "SALIR", + }; + + String status[] = { + "EN ESPERA", + "DETECTANDO", + "DOSIFICARA", + "DOSIFICANDO", + "BLOQUEADO", + }; + + String text_info[] = { + "MODO 1", + "MODO 2", + "MODO 3", + "RESTAURAR", + "REINICAR", + "CANCELAR", + }; + + boolean refresh_lcd_menu; + uint32_t blink_millis; + + +/************************************************** +* FRONT PANEL OF CONFIGURATIONS +**************************************************/ + // button methods and memory spaces + void loop_settings_panel_buttons() + { + // Leemos valor analogo del botón + uint8_t button_value = analogRead(SETTINGS_BUTTONS_PIN); + + // Comprobamos el valor obtenido con un rago de tolerancia SETTING_BUTTON_TOLERANCE_READ + for (uint8_t i = 0; i < sizeof button_values / sizeof button_values[0]; i++) { + if(button_values[i] >= (button_value - SETTING_BUTTON_TOLERANCE_READ) && button_values[i] <= (button_value + SETTING_BUTTON_TOLERANCE_READ)) + button_value = button_values[i]; + } + + //Valoramos si se presiono un botón y ejecutamos el metodo correspondiente + switch(button_value) { + case SETTING_BUTTON_IN_VAL: + if(millis() >= _bt[0] + SETTING_BUTTON_DELAY_MILLIS) { + if(confirmation_repeats_millis == 0) + confirmation_repeats_millis = millis() + SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS; + + if(millis() > confirmation_repeats_millis){ + action_button(SETTING_BUTTON_IN_VAL); + + _bt[0] = millis(); + } + } + break; + + case SETTING_BUTTON_OUT_VAL: + if(millis() >= _bt[1] + SETTING_BUTTON_DELAY_MILLIS) { + if(confirmation_repeats_millis == 0) + confirmation_repeats_millis = millis() + SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS; + + if(millis() > confirmation_repeats_millis){ + action_button(SETTING_BUTTON_OUT_VAL); + + _bt[1] = millis(); + } + } + break; + + case SETTING_BUTTON_UP_VAL: + if(millis() >= _bt[2] + SETTING_BUTTON_DELAY_MILLIS) { + if(confirmation_repeats_millis == 0) + confirmation_repeats_millis = millis() + SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS; + + if(millis() > confirmation_repeats_millis){ + action_button(SETTING_BUTTON_UP_VAL); + + _bt[2] = millis(); + } + } + break; + + case SETTING_BUTTON_DOWN_VAL: + if(millis() >= _bt[3] + SETTING_BUTTON_DELAY_MILLIS) { + if(confirmation_repeats_millis == 0) + confirmation_repeats_millis = millis() + SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS; + + if(millis() > confirmation_repeats_millis){ + action_button(SETTING_BUTTON_DOWN_VAL); + + _bt[3] = millis(); + } + } + break; + + default: + confirmation_repeats_millis = 0; + } + + // Verificamos y salimos del menú si a pasan AUTO_EXIT_MENU_MILLIS + if((menu_section != OUT_OF_MENU) && (millis() >= last_change_menu_millis + AUTO_EXIT_MENU_MILLIS)){ + load_menu_variables(OUT_OF_MENU); + + refresh_lcd_menu = true; + + serialPrintln("AUTO_EXIT_MENU_MILLIS"); + } + } + + void action_button(uint8_t button_value) + { + switch(button_value) { + case SETTING_BUTTON_IN_VAL: + switch(menu_section) { + case OUT_OF_MENU: + load_menu_variables(IN_SENSITIVITY_BUTTON); + break; + + case IN_SENSITIVITY_BUTTON: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_ONE) + save_setting(IN_SENSITIVITY_BUTTON); + break; + + case IN_PRESS_BUTTON: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_ONE) + save_setting(IN_PRESS_BUTTON); + break; + + case IN_HOLD_DOWN_BUTTON: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_ONE) + save_setting(IN_HOLD_DOWN_BUTTON); + break; + + case IN_LAG: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_THREE) + save_setting(IN_LAG); + break; + + case IN_DOSING: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_THREE) + save_setting(IN_DOSING); + break; + + case IN_FACTORY_RESET: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_ONE) + save_setting(IN_FACTORY_RESET); + break; + + case IN_RESTART: + if(menu_status == VIEW) + menu_status = UPDATE; + + else if(++menu_cursor_var > POSITION_ONE) + save_setting(IN_RESTART); + break; + + case IN_EXIT: + load_menu_variables(OUT_OF_MENU); + break; + } + break; + + case SETTING_BUTTON_OUT_VAL: + switch(menu_status){ + case VIEW: + load_menu_variables(OUT_OF_MENU); + break; + + case UPDATE: + if(menu_cursor_var == 0) + load_menu_variables(menu_section); + else + menu_cursor_var--; + } + break; + + case SETTING_BUTTON_UP_VAL: + switch(menu_section) { + case OUT_OF_MENU: + load_menu_variables(IN_RESTART); + break; + + case IN_SENSITIVITY_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_EXIT); + + }else{ // UPDATE + setup_var[0] = setup_var[0] >= 10 ? 1 : ++setup_var[0]; + } + break; + + case IN_PRESS_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_SENSITIVITY_BUTTON); + + }else{ // UPDATE + setup_var[0] = setup_var[0] <= 1 ? 3 : --setup_var[0]; + } + break; + + case IN_HOLD_DOWN_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_PRESS_BUTTON); + + }else{ // UPDATE + setup_var[0] = setup_var[0] <= 1 ? 2 : --setup_var[0]; + } + break; + + case IN_LAG: + if(menu_status == VIEW){ + load_menu_variables(IN_PRESS_BUTTON); + + }else{ // UPDATE + if(menu_cursor_var == POSITION_ONE) + setup_var[0] = setup_var[0] >= 60 ? 0 : ++setup_var[0]; // Minutos + + else if(menu_cursor_var == POSITION_TWO) + setup_var[1] = setup_var[1] >= 59 ? 0 : ++setup_var[1]; // Segundo + + else if(menu_cursor_var == POSITION_THREE) + setup_var[2] = setup_var[2] >= 9 ? 0 : ++setup_var[2]; // Decimas de segundo + } + break; + + case IN_DOSING: + if(menu_status == VIEW){ + load_menu_variables(IN_LAG); + + }else{ // UPDATE + if(menu_cursor_var == POSITION_ONE) + setup_var[0] = setup_var[0] >= 60 ? 0 : ++setup_var[0]; // Minutos + + else if(menu_cursor_var == POSITION_TWO) + setup_var[1] = setup_var[1] >= 59 ? 0 : ++setup_var[1]; // Segundo + + else if(menu_cursor_var == POSITION_THREE) + setup_var[2] = setup_var[2] >= 9 ? 0 : ++setup_var[2]; // Decimas de segundo + } + break; + + case IN_FACTORY_RESET: + if(menu_status == VIEW){ + load_menu_variables(IN_DOSING); + + }else{ // UPDATE + setup_var[0] = setup_var[0] >= 1 ? 0 : ++setup_var[0]; + } + break; + + case IN_RESTART: + if(menu_status == VIEW){ + load_menu_variables(IN_FACTORY_RESET); + + }else{ // UPDATE + setup_var[0] = setup_var[0] >= 1 ? 0 : ++setup_var[0]; + } + break; + + case IN_EXIT: + load_menu_variables(IN_FACTORY_RESET); + break; + } + break; + + case SETTING_BUTTON_DOWN_VAL: + switch(menu_section) { + case OUT_OF_MENU: + load_menu_variables(IN_SENSITIVITY_BUTTON); + break; + + case IN_SENSITIVITY_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_PRESS_BUTTON); + + }else{ // UPDATE + setup_var[0] = setup_var[0] <= 1 ? 10 : --setup_var[0]; + } + break; + + case IN_PRESS_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_LAG); + + }else{ // UPDATE + setup_var[0] = setup_var[0] >= 3 ? 1 : ++setup_var[0]; + } + break; + + case IN_HOLD_DOWN_BUTTON: + if(menu_status == VIEW){ + load_menu_variables(IN_LAG); + + }else{ // UPDATE + setup_var[0] = setup_var[0] >= 2 ? 1 : ++setup_var[0]; + } + break; + + case IN_LAG: + if(menu_status == VIEW){ + load_menu_variables(IN_DOSING); + + }else{ // UPDATE + if(menu_cursor_var == POSITION_ONE) + setup_var[0] = setup_var[0] <= 0 ? 60 : --setup_var[0]; // Minutos + + else if(menu_cursor_var == POSITION_TWO) + setup_var[1] = setup_var[1] <= 0 ? 59 : --setup_var[1]; // Segundo + + else if(menu_cursor_var == POSITION_THREE) + setup_var[2] = setup_var[2] <= 0 ? 9 : --setup_var[2]; // Decimas de segundo + } + break; + + case IN_DOSING: + if(menu_status == VIEW){ + load_menu_variables(IN_FACTORY_RESET); + + }else{ // UPDATE + if(menu_cursor_var == POSITION_ONE) + setup_var[0] = setup_var[0] <= 0 ? 60 : --setup_var[0]; // Minutos + + else if(menu_cursor_var == POSITION_TWO) + setup_var[1] = setup_var[1] <= 0 ? 59 : --setup_var[1]; // Segundo + + else if(menu_cursor_var == POSITION_THREE) + setup_var[2] = setup_var[2] <= 0 ? 9 : --setup_var[2]; // Decimas de segundo + } + break; + + case IN_FACTORY_RESET: + if(menu_status == VIEW){ + load_menu_variables(IN_RESTART); + + }else{ // UPDATE + setup_var[0] = setup_var[0] <= 0 ? 1 : --setup_var[0]; + } + break; + + case IN_RESTART: + if(menu_status == VIEW){ + load_menu_variables(IN_EXIT); + + }else{ // UPDATE + setup_var[0] = setup_var[0] <= 0 ? 1 : --setup_var[0]; + } + break; + + case IN_EXIT: + load_menu_variables(IN_SENSITIVITY_BUTTON); + break; + } + break; + } + + refresh_lcd_menu = true; + last_change_menu_millis = millis(); + + serialPrint("button_value: "); + serialPrintln(button_value); + + serialPrint("menu_section: "); + serialPrint(menu_section); + serialPrint(", menu_status: "); + serialPrint(menu_status); + serialPrint(", menu_cursor_var: "); + serialPrint(menu_cursor_var); + serialPrint(", setup_var[0]: "); + serialPrint(setup_var[0]); + serialPrint(", setup_var[1]: "); + serialPrint(setup_var[1]); + serialPrint(", setup_var[2]: "); + serialPrintln(setup_var[2]); + } + + void save_setting(uint8_t _setting) + { + menu_status = VIEW; + menu_cursor_var = POSITION_ONE; + + switch(_setting){ + case IN_SENSITIVITY_BUTTON: + EEPROM.write(BUTTON_SENSITIVITY_EEPROM_ADDRESS, setup_var[0]); + + load_setting(IN_SENSITIVITY_BUTTON); + + serialPrintln("Save button_sensitivity_millis"); + break; + + case IN_PRESS_BUTTON: + EEPROM.write(PRESS_BUTTON_EEPROM_ADDRESS, setup_var[0]); + + load_setting(IN_PRESS_BUTTON); + + serialPrintln("Save press_button_mode"); + break; + + case IN_HOLD_DOWN_BUTTON: + EEPROM.write(HOLD_DOWN_BUTTON_EEPROM_ADDRESS, setup_var[0]); + + load_setting(IN_HOLD_DOWN_BUTTON); + + serialPrintln("Save hold_down_button_mode"); + break; + + case IN_LAG: + EEPROM.write(LAG_TIME_MIN_EEPROM_ADDRESS, setup_var[0]); + EEPROM.write(LAG_TIME_SEG_EEPROM_ADDRESS, setup_var[1]); + EEPROM.write(LAG_TIME_DEC_EEPROM_ADDRESS, setup_var[2]); + + load_setting(IN_LAG); + + serialPrintln("Save lag_time"); + break; + + case IN_DOSING: + EEPROM.write(DOSING_TIME_MIN_EEPROM_ADDRESS, setup_var[0]); + EEPROM.write(DOSING_TIME_SEG_EEPROM_ADDRESS, setup_var[1]); + EEPROM.write(DOSING_TIME_DEC_EEPROM_ADDRESS, setup_var[2]); + + load_setting(IN_DOSING); + + serialPrintln("Save dosing_time"); + break; + + case IN_FACTORY_RESET: + if(setup_var[0]){ + EEPROM.write(BUTTON_SENSITIVITY_EEPROM_ADDRESS, BUTTON_SENSITIVITY_DEFAULT_VALUE); + EEPROM.write(PRESS_BUTTON_EEPROM_ADDRESS, PRESS_BUTTON_DEFAULT_VALUE); + EEPROM.write(HOLD_DOWN_BUTTON_EEPROM_ADDRESS, HOLD_DOWN_BUTTON_DEFAULT_VALUE); + EEPROM.write(LAG_TIME_MIN_EEPROM_ADDRESS, LAG_TIME_MIN_DEFAULT_VALUE); + EEPROM.write(LAG_TIME_SEG_EEPROM_ADDRESS, LAG_TIME_SEG_DEFAULT_VALUE); + EEPROM.write(LAG_TIME_DEC_EEPROM_ADDRESS, LAG_TIME_DEC_DEFAULT_VALUE); + EEPROM.write(DOSING_TIME_MIN_EEPROM_ADDRESS, DOSING_TIME_MIN_DEFAULT_VALUE); + EEPROM.write(DOSING_TIME_SEG_EEPROM_ADDRESS, DOSING_TIME_SEG_DEFAULT_VALUE); + EEPROM.write(DOSING_TIME_DEC_EEPROM_ADDRESS, DOSING_TIME_DEC_DEFAULT_VALUE); + + load_setting(ALL_SETTINGS); + load_menu_variables(OUT_OF_MENU); + + serialPrintln("Restore factory settings"); + } + break; + + case IN_RESTART: + if(setup_var[0]){ + dispenser_status = DISPENSER_DOSING; + dispenser_status_time_millis = 0; + + load_menu_variables(OUT_OF_MENU); + + serialPrintln("Restart"); + } + break; + } + } + + void load_setting(uint8_t _setting) + { + switch(_setting){ + case ALL_SETTINGS: + load_setting(IN_SENSITIVITY_BUTTON); + load_setting(IN_PRESS_BUTTON); + load_setting(IN_HOLD_DOWN_BUTTON); + load_setting(IN_LAG); + load_setting(IN_DOSING); + break; + + case IN_SENSITIVITY_BUTTON: + button_sensitivity_millis = 1100 - (EEPROM.read(BUTTON_SENSITIVITY_EEPROM_ADDRESS) * 110); + + serialPrint("button_sensitivity_millis: "); + serialPrintln(button_sensitivity_millis); + break; + + case IN_PRESS_BUTTON: + press_button_mode = EEPROM.read(PRESS_BUTTON_EEPROM_ADDRESS); + + serialPrint("press_button_mode: "); + serialPrintln(press_button_mode); + break; + + case IN_HOLD_DOWN_BUTTON: + hold_down_button_mode = EEPROM.read(HOLD_DOWN_BUTTON_EEPROM_ADDRESS); + + serialPrint("hold_down_button_mode: "); + serialPrintln(hold_down_button_mode); + break; + + case IN_LAG: + lag_time_decseg = (EEPROM.read(LAG_TIME_SEG_EEPROM_ADDRESS) * 10) + EEPROM.read(LAG_TIME_DEC_EEPROM_ADDRESS); + + serialPrint("lag_time_decseg: "); + serialPrintln(lag_time_decseg); + break; + + case IN_DOSING: + dosing_time_decseg = (EEPROM.read(DOSING_TIME_MIN_EEPROM_ADDRESS) * 600) + (EEPROM.read(DOSING_TIME_SEG_EEPROM_ADDRESS) * 10) + EEPROM.read(DOSING_TIME_DEC_EEPROM_ADDRESS); + + serialPrint("dosing_time_decseg: "); + serialPrintln(dosing_time_decseg); + break; + } + } + + void load_menu_variables(uint8_t _menu_section) + { + menu_section = _menu_section; + menu_status = VIEW; + menu_cursor_var = POSITION_ONE; + + switch(_menu_section){ + case OUT_OF_MENU: + case IN_FACTORY_RESET: + case IN_RESTART: + setup_var[0] = 0; + setup_var[1] = 0; + setup_var[2] = 0; + break; + + case IN_SENSITIVITY_BUTTON: + setup_var[0] = EEPROM.read(BUTTON_SENSITIVITY_EEPROM_ADDRESS); + break; + + case IN_PRESS_BUTTON: + setup_var[0] = EEPROM.read(PRESS_BUTTON_EEPROM_ADDRESS); + break; + + case IN_HOLD_DOWN_BUTTON: + setup_var[0] = EEPROM.read(HOLD_DOWN_BUTTON_EEPROM_ADDRESS); + break; + + case IN_LAG: + setup_var[0] = EEPROM.read(LAG_TIME_MIN_EEPROM_ADDRESS); // Minutos + setup_var[1] = EEPROM.read(LAG_TIME_SEG_EEPROM_ADDRESS); // Segundos + setup_var[2] = EEPROM.read(LAG_TIME_DEC_EEPROM_ADDRESS); // Decimas de segundo + break; + + case IN_DOSING: + setup_var[0] = EEPROM.read(DOSING_TIME_MIN_EEPROM_ADDRESS); // Minutos + setup_var[1] = EEPROM.read(DOSING_TIME_SEG_EEPROM_ADDRESS); // Segundos + setup_var[2] = EEPROM.read(DOSING_TIME_DEC_EEPROM_ADDRESS); // Decimas de segundo + break; + } + } + + +/************************************************** +* LCD2004 rendering +**************************************************/ + // Helpers + String fill_string_ws(String _text_info, uint8_t _length, uint8_t _first_spaces = 0, String _char = " ") + { + if(_text_info.length() >= _length) + return _text_info.substring(0, _length); + + for(uint8_t i = 0; _first_spaces > i; i++) + if(_text_info.length() < _length) + _text_info = _char + _text_info; + + while(_text_info.length() < _length) + _text_info = _text_info + _char; + + return _text_info; + } + + String min_seg_dec_to_string(uint8_t _min, uint8_t _seg, uint8_t _dec) + { + String min = String(_min < 10? "0": "") + String(_min); + String seg = String(_seg < 10? "0": "") + String(_seg); + + return min + ":" + seg + "." + String(_dec); + } + + String process_time() + { + String process_time_string = "0"; + + if(dispenser_status_time_millis - millis()){ + uint32_t min = (dispenser_status_time_millis - millis()) / 60000; + uint16_t seg = ((dispenser_status_time_millis - millis()) - (min * 60000)) / 1000; + uint8_t dec = ((dispenser_status_time_millis - millis()) - (min * 60000) - (seg * 1000)) / 100; + + String _min = min >= 1? String(min) + ":": ""; + String _seg = (min >= 1 && seg <= 9? "0": "") + String(seg); + + process_time_string = _min + _seg + "." + String(dec); + } + + serialPrintln(process_time_string); + + return process_time_string; + } + + + // Methods + void loop_screen_rendering() + { + if(refresh_lcd_menu){ + print_lcd_menu(); + + refresh_lcd_menu = false; + } + + if(millis() % LCD_PROCESS_REFRESH_MILLIS == 0){ + print_lcd_process(); + setCursor_lcd_menu(); + } + } + + void print_lcd_menu() + { + lcd.noCursor(); + + // Menú de configuraciones + lcd.setCursor(0, 0); + + menu_section == OUT_OF_MENU? + lcd.print(fill_string_ws("", 20)): + lcd.print(fill_string_ws(menu[menu_section -1], 20)); + + // Detalles de configuraciones + lcd.setCursor(0, 1); + + switch(menu_section){ + case OUT_OF_MENU: + lcd.print(fill_string_ws("", 20)); + break; + + case IN_SENSITIVITY_BUTTON: + lcd.print(fill_string_ws(fill_string_ws(String(setup_var[0]), 2, 1, "0"), 20, 3)); + break; + + case IN_PRESS_BUTTON: + case IN_HOLD_DOWN_BUTTON: + switch(setup_var[0]){ + case 1: + lcd.print(fill_string_ws(text_info[MODE_1], 20, 3)); + break; + + case 2: + lcd.print(fill_string_ws(text_info[MODE_2], 20, 3)); + break; + + case 3: + lcd.print(fill_string_ws(text_info[MODE_3], 20, 3)); + break; + } + break; + + case IN_LAG: + case IN_DOSING: + lcd.print(fill_string_ws(min_seg_dec_to_string(setup_var[0], setup_var[1], setup_var[2]), 20, 3)); + break; + + case IN_FACTORY_RESET: + if(menu_status == UPDATE){ + setup_var[0]? + lcd.print(fill_string_ws(text_info[FACTORY_RESET], 20, 3)): + lcd.print(fill_string_ws(text_info[CANCEL], 20, 3)); + + }else + lcd.print(fill_string_ws("", 20)); + break; + + case IN_RESTART: + if(menu_status == UPDATE){ + setup_var[0]? + lcd.print(fill_string_ws(text_info[RESTART], 20, 3)): + lcd.print(fill_string_ws(text_info[CANCEL], 20, 3)); + + }else + lcd.print(fill_string_ws("", 20)); + break; + } + + // Limpiamos línea de proceso + if(menu_status == UPDATE){ + lcd.setCursor(0, 2); + lcd.print(fill_string_ws("", 20)); + + lcd.setCursor(0, 3); + lcd.print(fill_string_ws("", 20)); + } + } + + void print_lcd_process() + { + if(menu_section == OUT_OF_MENU || menu_status == VIEW){ + lcd.setCursor(0, 2); + + lcd.print(status[dispenser_status]); + + switch(dispenser_status){ + case DISPENSER_IDLE: + if(millis() >= blink_millis) + blink_millis = millis() + (BLINK_MILLIS * 2); + + lcd.print(fill_string_ws(blink_millis - millis() >= BLINK_MILLIS? "": "***", 11, 2)); + break; + + case DISPENSER_LAG: + lcd.print(fill_string_ws(process_time(), 8, 2)); + break; + + case DISPENSER_DOSING: + lcd.print(fill_string_ws(process_time(), 8, 1)); + break; + + case DISPENSER_BLOCK: + //lcd.print(fill_string_ws(process_time(), 8, 1)); + break; + } + } + } + + void setCursor_lcd_menu() + { + if(menu_status == UPDATE){ + switch(menu_section){ + case OUT_OF_MENU: + break; + + case IN_LAG: + case IN_DOSING: + // Posicionamos el cursos, para la edición + if(menu_cursor_var == POSITION_ONE) + lcd.setCursor(3,1); + + else if(menu_cursor_var == POSITION_TWO) + lcd.setCursor(6,1); + + else if(menu_cursor_var == POSITION_THREE) + lcd.setCursor(9,1); + break; + + case IN_SENSITIVITY_BUTTON: + case IN_PRESS_BUTTON: + case IN_HOLD_DOWN_BUTTON: + case IN_FACTORY_RESET: + case IN_RESTART: + lcd.setCursor(3,1); + break; + } + + lcd.cursor(); + } + } + + +/************************************************** +* DOSAGE PROCESS +**************************************************/ + void loop_dosage_process() + { + if(digitalRead(DOSING_BUTTON_PIN) == DOSING_BUTTON_PUSH){ + if(button_pressed_millis == 0) + button_pressed_millis = millis(); + + // Se supero el button_sensitivity_millis + if (millis() >= (button_pressed_millis + button_sensitivity_millis)) + start_dosing_process(); + + }else{ + + release_button = 0; + button_pressed_millis = 0; + } + + continue_dosing_process(); + } + + void start_dosing_process() + { + + + + if(press_button_mode == 3 && + dispenser_status != DISPENSER_IDLE && + dispenser_status_time_millis >= button_pressed_millis && + release_button == 0){ + + dispenser_status = DISPENSER_DOSING; + dispenser_status_time_millis = 0; + + serialPrint("Proceso detenido"); + serialPrintln(millis()); + + + }else if((press_button_mode == 1 || press_button_mode == 3) && dispenser_status == DISPENSER_IDLE){ + dispenser_status = DISPENSER_LAG; + dispenser_status_time_millis = millis() + ((uint32_t) lag_time_decseg * 100); + + release_button = 1; + + serialPrint("Iniciando proceso "); + serialPrintln(millis()); + + }else if(press_button_mode == 2){ + dispenser_status = DISPENSER_RESTART; + + release_button = 1; + } + } + + void continue_dosing_process() + { + switch(dispenser_status){ + case DISPENSER_RESTART: + digitalWrite(RELAY_PIN, RELAY_LOW); + + dispenser_status = DISPENSER_LAG; + dispenser_status_time_millis = millis() + ((uint32_t) lag_time_decseg * 100); + break; + + case DISPENSER_LAG: + if(millis() >= dispenser_status_time_millis){ + dispenser_status = DISPENSER_DOSING; + dispenser_status_time_millis = millis() + ((uint32_t) dosing_time_decseg * 100); + + digitalWrite(RELAY_PIN, RELAY_HIGH); + } + break; + + case DISPENSER_DOSING: + if(millis() >= dispenser_status_time_millis){ + dispenser_status = button_pressed_millis == 0? DISPENSER_IDLE: DISPENSER_BLOCK; + dispenser_status_time_millis = 0; + + digitalWrite(RELAY_PIN, RELAY_LOW); + } + break; + + case DISPENSER_BLOCK: + if(button_pressed_millis == 0) + dispenser_status = DISPENSER_IDLE; + break; + } + } + + +/************************************************** +* Setup & Loops +**************************************************/ + void setup() + { + pinMode(RELAY_PIN, OUTPUT); + pinMode(DOSING_BUTTON_PIN, INPUT_PULLUP); + pinMode(SETTINGS_BUTTONS_PIN, INPUT_PULLUP); + + // Salida Serial + serialBegin(9600); + serialBeginWhile(); + + // Cargamos configuraciones de la EEPROM a la ram + load_setting(ALL_SETTINGS); + + //Iniciamos la pantalla + lcd.begin(20, 4); + } + + void loop() + { + loop_settings_panel_buttons(); + loop_dosage_process(); + loop_screen_rendering(); + } diff --git a/README.md b/README.md new file mode 100644 index 0000000..76924b9 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Dosificador Atmel LCD2004 4-buttons