dosificador-atmel/Dosificador_LCD2004_4buttons/Dosificador_LCD2004_4buttons.ino
2022-07-19 00:52:35 -05:00

1077 lines
37 KiB
C++

/*****************************************
* Dosificador_LCD2004_4buttons *
* 15/03/2021 *
* Versión 0.1.0 *
* koneko.mx *
*****************************************/
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
/**************************************************
* Definición de Constantes
**************************************************/
// LCD2004 I2C
#define LCD_I2C_ADDRESS 0x27
// PINOUT
#define RELAY_PIN A2
#define DOSING_BUTTON_PIN A1
#define SETTINGS_BUTTONS_PIN A0
/**************************************************
* BOTONES
**************************************************/
#define SETTING_BUTTON_IN_VAL 14
#define SETTING_BUTTON_UP_VAL 41
#define SETTING_BUTTON_DOWN_VAL 66
#define SETTING_BUTTON_OUT_VAL 89
#define SETTING_BUTTON_TOLERANCE_READ 5
#define SETTING_BUTTON_CONFIRMATION_REPEATS_MILLIS 5
#define SETTING_BUTTON_DELAY_MILLIS 350
// 4-button configuration
uint16_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;
/**************************************************
* MENÚ
**************************************************/
// BLOQUES DE MEMORIA EEPROM
#define BUTTON_SENSITIVITY_EEPROM_ADDRESS 0
#define DISPENSER_MODE_EEPROM_ADDRESS 1
#define LAG_TIME_MIN_EEPROM_ADDRESS 2 // Minutos, tiempo de retraso
#define LAG_TIME_SEG_EEPROM_ADDRESS 3 // Segundo, tiempo de retraso
#define LAG_TIME_DEC_EEPROM_ADDRESS 4 // Décimas de segundo, tiempo de retraso
#define DOSING_TIME_MIN_EEPROM_ADDRESS 5 // Minutos, tiempo dosificación
#define DOSING_TIME_SEG_EEPROM_ADDRESS 6 // Segundos, tiempo dosificación
#define DOSING_TIME_DEC_EEPROM_ADDRESS 7 // Décimas de segundo, tiempo dosificación
// FACTORY SETTINGS
#define BUTTON_SENSITIVITY_DEFAULT_VALUE 10
#define DISPENSER_MODE_DEFAULT_VALUE 2
#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 OUT_OF_MENU 0
#define ALL_SETTINGS 0
// POSITION MENU
#define IN_SENSITIVITY_BUTTON 1
#define IN_DISPENSER_MODE 2
#define IN_LAG 3
#define IN_DOSING 4
#define IN_FACTORY_RESET 5
#define IN_RESTART 6
#define IN_EXIT 7
#define VIEW 0
#define UPDATE 1
#define POSITION_ONE 0
#define POSITION_TWO 1
#define POSITION_THREE 2
// text_info[] index
#define DISPENSER_MODE 0
#define BELT_MODE 1
#define FACTORY_RESET 2
#define RESTART 3
#define CANCEL 4
// MENU & LCD
#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
// MODE EEPROM DISPENSER
#define DISPENSER_MODE_VALUE 1
#define BELT_MODE_VALUE 2
// RELAY STATUS
#define RELAY_HIGH HIGH
#define RELAY_LOW LOW
// SENSOR STATUS
#define SENSOR_UNLOCK 0
#define SENSOR_LOCK 1
#define SENSOR_ACTIVATED LOW
// SENSOR ACTIVATION BUFFER SIZE
#define SENSOR_BUFFER_SIZE 25
/**************************************************
* 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
**************************************************/
// Configuraciones del dosificador
uint16_t button_sensitivity_millis;
uint8_t dispenser_mode;
uint16_t lag_time_decseg;
uint16_t dosing_time_decseg;
// Momento del bloqueo del sensor
uint32_t sensor_lock_millis;
// Registro del sensor
uint8_t last_sensor_status = SENSOR_UNLOCK;
uint8_t relay_activation_pointer;
uint32_t relay_activation_millis_ini[SENSOR_BUFFER_SIZE];
uint32_t relay_activation_millis_end[SENSOR_BUFFER_SIZE];
// Estado del Relevador
uint8_t relay_state = RELAY_LOW;
// Estado del dosificador
uint8_t dispenser_status;
uint32_t dispenser_status_time_millis;
// Navegación de menú
uint8_t setup_var[3];
uint8_t menu_section;
uint8_t menu_status;
uint8_t menu_cursor_var;
uint32_t blink_millis;
uint32_t last_change_menu_millis;
boolean refresh_lcd_menu;
// LCD2004 Render
LiquidCrystal_I2C lcd(LCD_I2C_ADDRESS, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
String menu[] = {
"SENSIBILIDAD SENSOR",
"MODO DE TRABAJO",
"RETARDO AL INICIAR",
"TIEMPO DOSIFICACION",
"VALORES DE FABRICA",
"REINICIAR",
"SALIR",
};
String status[] = {
"EN ESPERA",
"DETECTANDO",
"DOSIFICARA",
"DOSIFICANDO",
"BLOQUEADO",
};
String text_info[] = {
"DOSIFICADOR",
"BANDA TRANSPORTADOR",
"RESTAURAR",
"REINICAR",
"CANCELAR",
};
/**************************************************
* FRONT PANEL OF CONFIGURATIONS
**************************************************/
// button methods and memory spaces
void loop_settings_panel_buttons()
{
// Leemos valor analogo del botón
uint16_t button_value = analogRead(SETTINGS_BUTTONS_PIN);
// Comprobamos el valor obtenido con un rago de tolerancia SETTING_BUTTON_TOLERANCE_READ
for (uint16_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(uint16_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_DISPENSER_MODE:
if(menu_status == VIEW)
menu_status = UPDATE;
else if(++menu_cursor_var > POSITION_ONE)
save_setting(IN_DISPENSER_MODE);
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_DISPENSER_MODE:
if(menu_status == VIEW){
load_menu_variables(IN_SENSITIVITY_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_DISPENSER_MODE);
}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){
dispenser_mode == DISPENSER_MODE_VALUE?
load_menu_variables(IN_DOSING):
load_menu_variables(IN_LAG);
}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_RESTART);
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_DISPENSER_MODE);
}else{ // UPDATE
setup_var[0] = setup_var[0] <= 1 ? 10 : --setup_var[0];
}
break;
case IN_DISPENSER_MODE:
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){
dispenser_mode == DISPENSER_MODE_VALUE?
load_menu_variables(IN_DOSING):
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_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_DISPENSER_MODE:
EEPROM.write(DISPENSER_MODE_EEPROM_ADDRESS, setup_var[0]);
load_setting(IN_DISPENSER_MODE);
serialPrintln("Save dispenser_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(DISPENSER_MODE_EEPROM_ADDRESS, DISPENSER_MODE_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]){
for (int i = 0; i < SENSOR_BUFFER_SIZE; ++i){
relay_activation_pointer = 0;
relay_activation_millis_ini[i] = 0;
relay_activation_millis_end[i] = 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_DISPENSER_MODE);
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_DISPENSER_MODE:
dispenser_mode = EEPROM.read(DISPENSER_MODE_EEPROM_ADDRESS);
serialPrint("dispenser_mode: ");
serialPrintln(dispenser_mode);
break;
case IN_LAG:
lag_time_decseg = (EEPROM.read(LAG_TIME_MIN_EEPROM_ADDRESS) * 600) + (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_DISPENSER_MODE:
setup_var[0] = EEPROM.read(DISPENSER_MODE_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_DISPENSER_MODE:
switch(setup_var[0]){
case DISPENSER_MODE_VALUE:
lcd.print(fill_string_ws(text_info[DISPENSER_MODE], 20));
break;
case BELT_MODE_VALUE:
lcd.print(fill_string_ws(text_info[BELT_MODE], 20));
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(dispenser_mode == DISPENSER_MODE_VALUE? process_time(): "--:--", 8, 1));
break;
case DISPENSER_BLOCK:
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_FACTORY_RESET:
case IN_RESTART:
lcd.setCursor(3,1);
break;
case IN_DISPENSER_MODE:
lcd.setCursor(0,1);
break;
}
lcd.cursor();
}
}
/**************************************************
* DOSAGE PROCESS
**************************************************/
void loop_dosage_process()
{
dispenser_status = DISPENSER_IDLE;
// Se a activado el Sensor
if(digitalRead(DOSING_BUTTON_PIN) == SENSOR_ACTIVATED){
if(sensor_lock_millis == 0)
sensor_lock_millis = millis();
// Se supero el button_sensitivity_millis
if(last_sensor_status == SENSOR_UNLOCK && millis() >= (sensor_lock_millis + button_sensitivity_millis)){
// Registramos en Inicio de Proceso de dosifiación
relay_activation_millis_ini[relay_activation_pointer] = millis() + (lag_time_decseg * 100);
// En modo Dosificador
if(dispenser_mode == DISPENSER_MODE_VALUE)
relay_activation_millis_end[relay_activation_pointer] = relay_activation_millis_ini[relay_activation_pointer] + (dosing_time_decseg * 100);
last_sensor_status = SENSOR_LOCK;
}
if(dispenser_mode == DISPENSER_MODE_VALUE && relay_activation_millis_end[relay_activation_pointer] == 0){
dispenser_status = DISPENSER_BLOCK;
}
}else if(last_sensor_status == SENSOR_LOCK){
if(dispenser_mode == DISPENSER_MODE_VALUE){
relay_activation_millis_ini[relay_activation_pointer] = 0;
relay_activation_millis_end[relay_activation_pointer] = 0;
}else{
relay_activation_millis_end[relay_activation_pointer++] = millis() + (lag_time_decseg * 100);
// Si supera el tamaño del buffer vamos al inicio del buffer
if(relay_activation_pointer >= SENSOR_BUFFER_SIZE)
relay_activation_pointer = 0;
}
sensor_lock_millis = 0;
last_sensor_status = SENSOR_UNLOCK;
}
// Determinamos el estado del Relevador
relay_state = RELAY_LOW;
if(dispenser_mode == DISPENSER_MODE_VALUE){
// Depuramos
if(relay_activation_millis_end[relay_activation_pointer] > 0 && millis() >= relay_activation_millis_end[relay_activation_pointer]){
relay_activation_millis_ini[relay_activation_pointer] = 0;
relay_activation_millis_end[relay_activation_pointer] = 0;
}
// Existe periodo de dosificación
if(relay_activation_millis_ini[relay_activation_pointer] > 0) {
// Revisamos si se debe encender el Dosificador
if(millis() >= relay_activation_millis_ini[relay_activation_pointer]){
dispenser_status = DISPENSER_DOSING;
dispenser_status_time_millis = relay_activation_millis_end[relay_activation_pointer];
relay_state = RELAY_HIGH;
// Aun no comienza dosificación
}else{
dispenser_status = DISPENSER_LAG;
dispenser_status_time_millis = relay_activation_millis_ini[relay_activation_pointer];
}
}
}else{
for (int i = 0; i < SENSOR_BUFFER_SIZE; ++i){
// Depuramos el Buffer
if(relay_activation_millis_end[i] > 0 && millis() >= relay_activation_millis_end[i]){
relay_activation_millis_ini[i] = 0;
relay_activation_millis_end[i] = 0;
}
if(relay_activation_millis_ini[i] > 0){
// Revisamos en el Buffer si se debe encender el Dosificador
if(millis() >= relay_activation_millis_ini[i]){
dispenser_status = DISPENSER_DOSING;
dispenser_status_time_millis = 0;
relay_state = RELAY_HIGH;
// Aun no comienza dosificación
}else if (relay_state == RELAY_LOW){
dispenser_status = DISPENSER_LAG;
dispenser_status_time_millis = relay_activation_millis_ini[i];
}
}
}
}
// Aplicamos cambios en el estado del relevador
digitalWrite(RELAY_PIN, relay_state);
/*
dispenser_status_time_millis
dispenser_status = DISPENSER_IDLE;
dispenser_status = DISPENSER_LAG;
dispenser_status = DISPENSER_DOSING;
dispenser_status = DISPENSER_BLOCK;
// Determinamos el estado del Dosificador
if(dispenser_mode == DISPENSER_MODE_VALUE){
}else{
}
for (int i = 0; i < SENSOR_BUFFER_SIZE; ++i){
serialPrint(i);
serialPrint(") ");
serialPrint(relay_activation_millis_ini[i]);
serialPrint(", ");
serialPrint(relay_activation_millis_end[i]);
serialPrint(" - ");
serialPrintln((relay_activation_millis_end[i] - relay_activation_millis_ini[i]));
}
serialPrintln("");
serialPrintln("");
serialPrintln("");
*/
}
/**************************************************
* Setup & Loops
**************************************************/
void setup()
{
pinMode(RELAY_PIN, OUTPUT);
pinMode(DOSING_BUTTON_PIN, INPUT_PULLUP);
pinMode(SETTINGS_BUTTONS_PIN, INPUT_PULLUP);
// Salida Serial
serialBegin(115200);
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();
}