My apologies
#include <Wire.h> #include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <WString.h>
#include "defines.h"
/*
* Procedimiento y funciones del reloj
*/
String name_of_month(month_name m) { //Recibe un valor de variable month_name y devuelve el valor
switch (m) { //que identifica en la definiciĂłn correspondiente del mes
case january: return month_01; //en el lenguaje seleccionado (#define LANGAUGE_
case february: return month_02;
case march: return month_03;
case april: return month_04;
case may: return month_05;
case june: return month_06;
case july: return month_07;
case august: return month_08;
case september: return month_09;
case october: return month_10;
case november: return month_11;
case december: return month_12;
}
}
String name_of_the_day_of_the_week(dow_name d) { //Recibe un valor de variable dow (DayOfWeek) y devuelve
switch (d) { //el valor que identifica en la definiciĂłn correspondiente
case sunday: return week_7; //del dĂa de la semana en el lenguaje seleccionado
case monday: return week_1;
case tuesday: return week_2;
case wednesday: return week_3;
case thusday: return week_4;
case friday: return week_5;
case saturday: return week_6;
}
}
int calc_time_offset(DateTime dt_utc) { //Rebibe una instancia de la clase DateTime y devuelve
byte last_day_before_last_monday = 24; //el lapso de tiempo entre la hora UTC y local en
byte hour_of_change = 2; //en el huso horario de España horario de invierno
int winter_offset = 3600; //1 hora = 3600seg //en periodo de verano e invierno
int summer_offset = 3600 * 2;
month_name number_month = dt_utc.month();
dow_name dow_number = dt_utc.dayOfTheWeek();
if (number_month > march && number_month < october) { //Si el mes está entre marzo y octubre
return summer_offset;
}
if (number_month > october || number_month < march) { //Si el mes stá entre octubre y el siguiente marzo
return winter_offset;
}
if (number_month == march) { //Si el mes es marzo y..
if (dt_utc.day() < last_day_before_last_monday) { //el dĂa es inferior a 24 (ultimo dĂa que puede ser domingo
return winter_offset; //comĂąn a todos los meses
} else {
if (dow_number == sunday) { //Si el dĂas es posterior al 24 y es domingo
if (dt_utc.hour() < hour_of_change) {
return winter_offset;
} else {
return summer_offset;
}
} else { //Si 24 - dĂa dĂa del mes + dia de la semana >= 0
if (last_day_before_last_monday - dt_utc.day() + dow_number >= 0) { //no ha cambiado el periodo
return winter_offset;
} else {
return summer_offset;
}
}
}
}
if (number_month = october) { //Mismo cálculo que para marzo
if (dt_utc.day() < last_day_before_last_monday) {
return summer_offset;
} else {
if (dow_number == sunday) {
if (dt_utc.hour() < hour_of_change) {
return summer_offset;
} else {
return winter_offset;
}
} else {
if (last_day_before_last_monday - dt_utc.day() + dow_number >= 0) {
return summer_offset;
} else {
return winter_offset;
}
}
}
}
}
byte check_next_day() { //Detecta si ha cambiado de dia para sacar la fecha al display
DateTime dt_utc = rtc.now();
int time_offset = calc_time_offset(dt_utc);
DateTime dt_local = dt_utc.unixtime() + time_offset;
bool is_next_day = dt_local.hour() == 0 && dt_local.minute() == 0 && dt_local.second() == 0;
if (is_next_day) {
delay(1000);
}
return is_next_day;
}
void show_invalid_data() { //Indica que hay error si los datos introducidos en el monitos serie
lcd.clear(); //son incorrectos
lcd.setCursor(0, 0);
lcd.print(" DEBE INTRODUCIR");
lcd.setCursor(0, 1);
lcd.print(" UNA FECHA VALIDA");
lcd.setCursor(0, 2);
lcd.print(" Y/O");
lcd.setCursor(0, 3);
lcd.print(" HORA VALIDOS");
delay(2000);
lcd.clear();
}
bool button_pressed (int button) { //Devuelve TRUE (1) si ha sido pulsado el boton button
bool bp = digitalRead(button) == LOW;
if (bp) {
delay(250);
}
return bp;
}
void show_end_of_process_display () { //Prsenta en el display la opciĂłn grabar en la puesta en hora por botones
lcd.setCursor(0, 0);
lcd.print("B.SUP(+) = GRABAR ");
lcd.setCursor(0, 1);
lcd.print("B.INF(-) = SUSPENDER");
}
void switch_clock_mode() {
if (cm_mode == mode_end_of_process) { //Cambia secuencialmente el dato de ajuste de fecha y hora
cm_mode = mode_normal; //Año, mes, dĂa, hora, minuto
} else {
cm_mode = cm_mode + 1;
}
}
void clear_clock_display() { //Deja en blanco las tres p`rimeras lĂneas del display
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" ");
}
void show_settings_label (String s_label) { //Muestra en el display la etiqueta del dato a ajustar
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(s_label);
}
void show_settings_data(int i_data) { //Muestra el nuevo ajuste de cada dato
lcd.setCursor(9, 0);
lcd.print(" ");
lcd.setCursor(9, 0);
lcd.print(i_data, DEC);
}
void show_set_date_time(int yr, int mt, int dy, int hr, int me) { //Muestras los nuevos datos para el ajuste
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(String(dy) + "/" + String(mt) + "/" + String(yr));
lcd.setCursor(11, 2);
lcd.print(" ");
lcd.setCursor(11, 2);
lcd.print(String(hr) + ":" + String(me));
}
int month_bounds(int mt) { //Modifica el mes en los lĂmites
if (mt > 12) {
return 1;
} else if (mt == 0) {
return 12;
} else {
return mt;
}
}
int day_bounds(int yr, int mt, int dy) { //Modifica los dĂas del mes en los lĂmites
int day_top = 31;
if (mt == february) {
if (leap_year(yr)) {
day_top = 29;
} else {
day_top = 28;
}
} else if (mt == april || mt == june || mt == september || mt == november) {
day_top = 30;
}
if (dy > day_top) {
return 1;
} else if (dy == 0) {
return day_top;
} else {
return dy;
}
}
int hour_bounds(int hr) { //Modifica la hora del dĂa en los lĂimites
if (hr > 23) {
return 0;
} else if (hr < 0) {
return 23;
} else {
return hr;
}
}
int minute_bounds(int mi) { //Modifica los lĂmites de los minutos
if (mi > 59) {
return 0;
} else if (mi < 0) {
return 59;
} else {
return mi;
}
}
bool leap_year (int y) { //Calcula si el año actual es bisiesto
return y%4 == 0 && y%10 != 0;
}
bool check_valid_data(int dy, int mt, int yr, int mi, int se) { //Comprueba que la fecha y hora ropuesta para
int days_offset = 0; //ajustar el reloj desde el monitor serie
//son correctos
if (mt == april || mt == june || mt == september || mt == november) {
days_offset = 1;
} else if (mt == february) {
if (leap_year(yr)) {
days_offset = 2;
} else {
days_offset = 3;
}
}
if (mt <= january || mt > december) {
return false;
} else if (dy <= 0 || dy + days_offset > 31) {
return false;
} else if (mi < 0 || mi > 59) {
return false;
} else {
return true;
}
}
void service_clock_set_serial () { //Lee una cadena desde el monitor serie y transforma en datos
if (Serial.available()) { //para el ajuste del reloj
char set_time[14];
size_t count = Serial.readBytesUntil('\n', set_time, 14);
String dt = set_time;
int i_day = (dt.substring(0, 2)).toInt();
int i_month = (dt.substring(2, 4)).toInt();
int i_year = (dt.substring(4, 8)).toInt();
int i_hour = (dt.substring(8, 10)).toInt();
int i_minute = (dt.substring(10, 12)).toInt();
if (check_valid_data(i_day, i_month, i_year, i_hour, i_minute)) {
rtc.adjust(DateTime(i_year, i_month, i_day, i_hour, i_minute, 0)); //Inicia el RTC con los datos de ajuste
} else {
show_invalid_data();
}
process_date();
process_time();
}
}
int read_buttons_updown() { //Comprueba si el botĂłn UP o DOWN han sido pulsados
if (button_pressed (pin_button_clock_up)) {
return 1;
} else if (button_pressed(pin_button_clock_down)) {
return -1;
} else {
return 0;
}
}
void service_set_clock_time () { //Procedimiento de ajuste de fecha y hora por botones
DateTime dt_utc = rtc.now();
int time_offset = calc_time_offset(dt_utc);
DateTime dt_local = dt_utc.unixtime() + time_offset;
int i_year = dt_local.year();
int i_month = dt_local.month();
int i_day = dt_local.day();
int i_hour = dt_local.hour();
int i_minute = dt_local.minute();
int now_mode = mode_year;
String s_mode = "YEAR";
int i_dat = dt_local.year();
int buttons_updown = 0;
clear_clock_display();
show_settings_label(s_mode);
show_settings_data(i_dat);
show_set_date_time(i_year, i_month, i_day, i_hour, i_minute);
while (cm_mode != mode_normal) {
if (button_pressed(pin_button_clock_mode)) {
switch_clock_mode();
} else {
buttons_updown = read_buttons_updown ();
}
switch(cm_mode) {
case mode_year:
i_year += buttons_updown;
i_dat = i_year;
s_mode = "YEAR";
break;
case mode_month:
i_month += buttons_updown;
i_month = month_bounds(i_month);
i_dat = i_month;
s_mode = "MONTH";
break;
case mode_day:
i_day += buttons_updown;
i_day = day_bounds(i_year, i_month, i_day);
i_dat = i_day;
s_mode = "DAY";
break;
case mode_hour:
i_hour = hour_bounds(i_hour += buttons_updown);
i_dat = i_hour;
s_mode = "HOUR";
break;
case mode_minute:
i_minute = minute_bounds(i_minute += buttons_updown);
i_dat = i_minute;
s_mode = "MINUTE";
break;
case mode_end_of_process:
show_end_of_process_display ();
if (buttons_updown != 0) {
if (buttons_updown == 1) {
rtc.adjust(DateTime(i_year, i_month, i_day, i_hour, i_minute, 0));
}
cm_mode = mode_normal;
}
break;
}
if (now_mode != cm_mode) {
show_settings_label(s_mode);
show_settings_data(i_dat);
now_mode = cm_mode;
}
if (buttons_updown != 0) {
show_settings_data(i_dat);
show_set_date_time(i_year, i_month, i_day, i_hour, i_minute);
}
}
clear_clock_display();
process_date();
}
void process_date() { //Procesa los datos de fecha y los saca a pantalla
DateTime dt_utc = rtc.now();
int time_offset = calc_time_offset(dt_utc);
DateTime dt_local = dt_utc.unixtime() + time_offset;
byte col_max = 20;
byte col_init = 0;
byte row_date = 0;
byte row_day_of_the_week = 1;
String s_month = name_of_month(dt_local.month());
String s_day_of_the_week = name_of_the_day_of_the_week(dt_local.dayOfTheWeek());
String s_date = String(dt_local.day());
s_date.concat(" * ");
s_date.concat(s_month);
s_date.concat(" * " );
s_date.concat(dt_local.year());
lcd.setCursor(col_init, row_date);
lcd.print(" ");
lcd.setCursor(((col_max - s_date.length()) / 2), row_date);
lcd.print(s_date);
lcd.setCursor(col_init, row_day_of_the_week);
lcd.print(" ");
lcd.setCursor(((col_max - s_day_of_the_week.length()) / 2), row_day_of_the_week);
lcd.print(s_day_of_the_week);
}
void process_time() { //Procesa los datos de hora y los muestra en pantalla
DateTime dt_utc = rtc.now();
int time_offset = calc_time_offset(dt_utc);
DateTime dt_local = dt_utc.unixtime() + time_offset;
char buf_local[] = "hh:mm:ss";
char buf_utc[] = "hh:mm";
byte col_local = 0;
byte col_utc = 11;
byte row_hour = 2;
lcd.setCursor(col_local, row_hour);
lcd.print(dt_local.toString(buf_local));
lcd.setCursor(col_utc, row_hour);
lcd.print("UTC=");
lcd.print(dt_utc.toString(buf_utc));
}
/*
* Procedimientos y funciones del conmutador de bandas
*/
bands decode_band(float r_band) { //r_band es la lectura de la entrada analĂłgica de bandas
if (r_band <= 100.0) {
return b30;
} else if (r_band > 228.0 && r_band <= 268.0) { //raw = 248, 1,212V
return b6;
} else if (r_band > 274.0 && r_band <= 314.0) { //raw = 294, 1,437V
return b10;
} else if (r_band > 373.0 && r_band <= 473.0) { //raw = 423, 2,067V
return b15;
} else if (r_band > 481.0 && r_band <= 591.0) { //raw = 541, 2,644V
return b20;
} else if (r_band > 624.0 && r_band <= 724.0) { //raw = 674, 3,294V
return b40;
} else if (r_band > 757.0 && r_band <= 857.0) { //raw = 897, 3,944V
return b80;
} else if (r_band > 886.0) { //raw = 936, 4,819V
return b160;
} else {
return b0;
}
}
String name_of_band() {
switch(active_band) {
case b0: return "NULL";
case b6: return "6m";
case b10: return "10m12m";
case b15: return "15m17m";
case b20: return "20m";
case b30: return "30m";
case b40: return "40m";
case b80: return "80m";
case b160: return "160m";
}
}
float read_analog_io (int pin) { //Lectura (100 lecturas) de una entrada analĂłgica y deviuelve el promedio
float raw = 0.0;
for (int i = 1; i <= 100; i++) {
raw += analogRead(pin);
}
return raw / 100.0;
}
void check_active_rig () { //Detecta si el Icom está encendido
float raw_power = read_analog_io (power_input);
if (raw_power > 400) {
active_rig = power_on;
} else {
active_rig = power_off;
}
}
void check_active_band () { //active_band es una variable global que contiene la banda activa
float raw_band = read_analog_io (bands_input);
active_band = decode_band (raw_band);
}
void active_relays_antennas (bool hex, bool ape) { //Conmuta los relés de antenas
digitalWrite(pin_relay_hexbeam, hex); //hex y ape tienen dos estados HIGH y LOW
digitalWrite(pin_relay_aperiodic, ape);
}
void check_active_antenna () { //Detecta la antena activa y la almacena en la variable global active_antenna
antennas old_antenna = active_antenna;
bool relay_hexbeam;
bool relay_aperiodic;
if (active_band == b6 || active_band == b10 || active_band == b15 || active_band == b20) {
active_antenna = hexbeam;
relay_hexbeam = true;
relay_aperiodic = false;
} else if (active_band == b30 || active_band == b40 || active_band == b80 || active_band == b160) {
active_antenna = aperiodic;
relay_hexbeam = false;
relay_aperiodic = true;
} else {
active_antenna = none;
relay_hexbeam = false;
relay_aperiodic = false;
}
active_relays_antennas (relay_hexbeam, relay_aperiodic);
}
void switch_antennas_modes () { //Conmuta secuencialmente los modos (automático y manual) del conmutador
switch (antenna_mode) {
case automatic:
antenna_mode = manual_hexbeam;
active_antenna = hexbeam;
active_relays_antennas (HIGH, LOW);
break;
case manual_hexbeam:
antenna_mode = manual_aperiodic;
active_antenna = aperiodic;
active_relays_antennas (LOW, HIGH);
break;
case manual_aperiodic:
antenna_mode = automatic;
check_active_antenna ();
break;
}
show_active_antenna ();
show_active_band ();
}
void show_active_band () { //Muestra en pantalla la banda activa
lcd.setCursor(0, 3);
if (antenna_mode == automatic) {
lcd.print("BAND= ");
lcd.setCursor(5, 3);
lcd.print(name_of_band());
} else {
lcd.print("MANUAL ");
}
}
void show_active_antenna () { //Muestra en pantalla la antena activa (o el modo)
int col_init = 11;
String ant = "APERIODIC";
if (active_antenna == hexbeam) {
col_init = 13;
ant = "HEXBEAM";
}
lcd.setCursor(11, 3);
lcd.print(" ");
lcd.setCursor(col_init, 3);
lcd.print(ant);
}
void show_rig_off (){
lcd.setCursor(0, 3);
lcd.print("TRANSCEPTOR APAGADO ");
}
void service_rig () { //Procesa el estado del Icom (Âżse ha encendido o apagado?
power old_status = active_rig;
check_active_rig ();
if (old_status != active_rig) {
if (active_rig == power_on) {
check_active_band ();
check_active_antenna ();
show_active_band ();
show_active_antenna ();
} else {
show_rig_off ();
}
}
}
void service_bands () { //Procesa la banda (ÂżHa habido canbio de banda?)
bands old_band = active_band;
antennas old_antenna = active_antenna;
check_active_band ();
if (old_band != active_band) {
show_active_band ();
check_active_antenna ();
Serial.print("Hexbeam = ");
Serial.println(digitalRead(pin_relay_hexbeam));
Serial.print("Aperiodic = ");
Serial.println(digitalRead(pin_relay_aperiodic));
if (old_antenna != active_antenna) {
show_active_antenna ();
}
}
}
void setup() {
Serial.begin(9600);
Serial.setTimeout(50);
rtc.begin();
lcd.init();
lcd.backlight();
lcd.clear();
pinMode(pin_button_clock_up, INPUT_PULLUP);
pinMode(pin_button_clock_mode, INPUT_PULLUP);
pinMode(pin_button_clock_down, INPUT_PULLUP);
pinMode(pin_button_antennas_mode, INPUT_PULLUP);
pinMode(pin_relay_hexbeam, OUTPUT);
pinMode(pin_relay_aperiodic, OUTPUT);
digitalWrite(pin_relay_hexbeam, LOW);
digitalWrite(pin_relay_aperiodic, LOW);
check_active_rig ();
check_active_band ();
check_active_antenna ();
if (active_rig == power_on) {
show_active_band ();
show_active_antenna ();
Serial.print("Hexbeam = ");
Serial.println(digitalRead(pin_relay_hexbeam));
Serial.print("Aperiodic = ");
Serial.println(digitalRead(pin_relay_aperiodic));
} else {
active_relays_antennas (LOW, LOW);
show_rig_off ();
}
process_date();
}
void loop() {
service_rig ();
if (active_rig == power_on && antenna_mode == automatic) {
service_bands ();
}
if (button_pressed(pin_button_antennas_mode)) {
switch_antennas_modes ();
}
service_clock_set_serial();
if (button_pressed(pin_button_clock_mode) && cm_mode == mode_normal) {
cm_mode = mode_year;
service_set_clock_time();
}
if (cm_mode == mode_normal) {
if (check_next_day()) {
process_date();
}
process_time();
}
} or paste code here
#define pin_button_clock_mode 15
#define pin_button_clock_up 11
#define pin_button_clock_down 9
#define pin_button_antennas_mode 40 //Esta para modificar porque el botón está en corto
#define pin_relay_hexbeam 44
#define pin_relay_aperiodic 42
#define power_input A5
#define bands_input A1
//#define LANGUAGE_ENGLISH
#define LANGUAGE_SPANISH
//#define LANGUAGE_EUSKERA
//#define LANGUAGE_CATALAN
#ifdef LANGUAGE_SPANISH
#define week_1 "LUNES"
#define week_2 "MARTES"
#define week_3 "MIERCOLES"
#define week_4 "JUEVES"
#define week_5 "VIERNES"
#define week_6 "SABADO"
#define week_7 "DOMINGO"
#define month_01 "ENERO"
#define month_02 "FEBRERO"
#define month_03 "MARZO"
#define month_04 "ABRIL"
#define month_05 "MAYO"
#define month_06 "JUNIO"
#define month_07 "JULIO"
#define month_08 "AGOSTO"
#define month_09 "SEPTIEMBRE"
#define month_10 "OCTUBRE"
#define month_11 "NOVIEMBRE"
#define month_12 "DICIEMBRE"
#endif //LANGUAGE_SPANISH
#ifdef LANGUAGE_ENGLISH
#define week_1 "MONDAY"
#define week_2 "TUESDAY"
#define week_3 "WEDNESDAY"
#define week_4 "THURSDAY"
#define week_5 "FRIDAY"
#define week_6 "SATURDAY"
#define week_7 "SUNDAY"
#define month_01 "JANUARY"
#define month_02 "FEBRUARY"
#define month_03 "MARS"
#define month_04 "APRIL"
#define month_05 "MAY"
#define month_06 "JUNE"
#define month_07 "JULY"
#define month_08 "AUGUST"
#define month_09 "SEPTEMBER"
#define month_10 "OCTOBER"
#define month_11 "NOVEMBER"
#define month_12 "DECEMBER"
#endif //LANGUAGE_ENGLISH
#ifdef LANGUAGE_EUSKERA
#define week_1 "ASTELENA"
#define week_2 "ASTEARTEA"
#define week_3 "ASTEASKENA"
#define week_4 "OSTEGUNA"
#define week_5 "OSTIRALA"
#define week_6 "LARUNBATA"
#define week_7 "IGANDEA"
#define month_01 "URTARRILA"
#define month_02 "OTSAILA"
#define month_03 "MARTXOA"
#define month_04 "APIRILA"
#define month_05 "MAIATZA"
#define month_06 "EKAINA"
#define month_07 "UTZAILA"
#define month_08 "ABUZTUA"
#define month_09 "IRAILA"
#define month_10 "URRIA"
#define month_11 "AZAROA"
#define month_12 "ABENDUA"
#endif //LANGUAGE_EUSKERA
#ifdef LANGUAGE_CATALAN
#define week_1 "DILLUNS"
#define week_2 "DIMARTS"
#define week_3 "DIMECRES"
#define week_4 "DIJOUS"
#define week_5 "DIVENDRES"
#define week_6 "DISSABTE"
#define week_7 "DIUMENGE"
#define month_01 "GENER"
#define month_02 "FEBRER"
#define month_03 "MARÇ"
#define month_04 "ABRIL"
#define month_05 "MAIG"
#define month_06 "JUNY"
#define month_07 "JULIOL"
#define month_08 "AGOST"
#define month_09 "SETEMBRE"
#define month_10 "OCTUBRE"
#define month_11 "NOVEMBRE"
#define month_12 "DESEMBRE"
#endif //LANGUAGE_CATALAN
enum power {
power_off,
power_on};
enum bands {
b0,
b6,
b10,
b15,
b20,
b30,
b40,
b80,
b160};
enum antennas_modes {
automatic,
manual_hexbeam,
manual_aperiodic};
enum antennas {
none,
hexbeam,
aperiodic};
power active_rig;
bands active_band;
antennas active_antenna;
antennas_modes antenna_mode = automatic;
enum month_name {
january = 1,
february,
march,
april,
may,
june,
july,
august,
september,
october,
november,
december};
enum dow_name {
sunday,
monday,
tuesday,
wednesday,
thusday,
friday,
saturday};
enum clock_mode {
mode_normal,
mode_year,
mode_month,
mode_day,
mode_hour,
mode_minute,
mode_end_of_process};
month_name mn_month;
dow_name dn_dow;
clock_mode cm_mode = mode_normal;
LiquidCrystal_I2C lcd(0x27, 20, 4);
RTC_DS3231 rtc; or paste code here