Dividir un sketch en archivos

Estoy trabajando en un proyecto algo complicado que realiza varias funciones diferentes:

  • Reloj con la hora local y UTC
  • Control de frecuencia de transmisión de un transceptor.
  • Cambio de antena automático.
  • Medición de potencia y ROE.

Todas y cada una de las funciones han sido probadas y funcionan, pero a la hora de generar un sketch único es complicado y aunque he revisado algún vídeo y buscado un tutorial accesible para dividir los archivos no he podido encontrar información útil o no he sido capaz comprender la información que he encontrado.

Agradecería infinito si algún amable colega me indicara dónde puedo encontrar un tutorial que me ayuda a comprender cómo se debe fraccionar el código o un libro que trate en profundidad el tema.

Muchas gracias por la ayuda.

Enio, EA2HW

Hola EA2HW, una manera de separar tu código es usar funciones de usuario.

void setup(){
   ...
}
void loop(){
   ...
   funcion();
   ...
}
void funcion(){
   ...
}

En todo caso debes cuidar la cantidad de SRAM usada. Eso implica pasar algunas variables de SRAM a FLASH.

const byte pin = 5;

Muchas gracias por la contestación Kike_GL. Ya tengo en cuenta la memoria que utilizo y aunque tengo que trabajar con la clase String creo que el NANO me da suficiente y siempre tengo de desbrozar el código para ahorrar memoria y en último caso utilizar un MEGA aunque el espacio en el hardware del proyecto también es importante.

Claro que utilizo funciones de usuario e intento seguir las reglas de encapsulación aunque mi experiencia viene de programar en lenguaje procedural intento entender y aplicar los principios de la POO.

Soy autodidacta lo que me pone a veces frente a un muro con algún problema básico como el de dividir el código.

Lo que necesito es orientación para encontrar bibliografía en castellano preferentemente o en inglés. Muchas gracias, adjunto el código, lo que pretendo es dividir el código en módulos por cada función, hasta ahora he incluido solo el reloj, pero me faltan un par más.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
 
#define pinBAND 0
#define pinREVERSE 1
#define pinFORWARD 2
#define pinBANDS 6
#define pinPOWER 7
#define pinANTENNA_AEF 8
#define pinANTENNA_HEX 7

unsigned long timeFOR_ACTION = 0;
int initialDAY;

enum Antenna {antennaHEX = 0, antennaAEF = 1};
enum Bands {b6 = 1, b10 = 2, b15 = 3, b20 = 4, b30 = 5, b40 = 6, b80 = 7, b160 = 8};

LiquidCrystal_I2C lcd(0x3f, 20, 4);
RTC_DS3231 rtc;

/* RELOJ
 */
 String nameOfMonth (int m) {
  switch (m) {
    case 1: return "ENE";
    case 2: return "FEB";
    case 3: return "MAR";
    case 4: return "ABR";
    case 5: return "MAY";
    case 6: return "JUN";
    case 7: return "JUL";
    case 8: return "AGO";
    case 9: return "SEP";
    case 10: return "OCT";
    case 11: return "NOV";
    case 12: return "DIC";
  }
}

String nameOfTheDayOfTheWeek (int d) {
  switch (d) {
    case 0: return "DOMINGO";
    case 1: return "LUNES";
    case 2: return "MARtES";
    case 3: return "MIERCOLES";
    case 4: return "JUEVES";
    case 5: return "VIERNES";
    case 6: return "SABADO";
  }
}

int calcUtcOffset (DateTime t) { 
  if ((t.month() > 3 || (t.month() == 3 && t.day() >= 25)) &&
    (t.month() < 10 || (t.month() == 10 && t.day() <= 25))) {
      return -2;
    } else {
      return -1;
    }
}

void setTimeClock () {
  int initYear = 2019;
  int initMonth = 10;
  int initDay = 3;
  int initHour = 18;
  int initMinute = 20;
  rtc.adjust(DateTime(initYear, initMonth, initDay, initHour, initMinute, 0));
}

void showDate (DateTime t) {
  String t_date = String(t.day());
  t_date.concat(" ");
  t_date.concat(nameOfMonth(t.month()));
  t_date.concat(" * " );
  t_date.concat(nameOfTheDayOfTheWeek(t.dayOfTheWeek()));

  int colPosition = int((20 - t_date.length()) / 2);
  lcd.setCursor(colPosition, 0);
  lcd.print(t_date);
}

void showTime (DateTime t) {
  int utcOffset = calcUtcOffset(t);
  
  char buf_time_local[9];
  snprintf(buf_time_local, sizeof(buf_time_local), "%02d:%02d:%02d",
    t.hour(), t.minute(), t.second());

char buf_time_utc[6];
  snprintf(buf_time_utc, sizeof(buf_time_utc), "%02d:%02d",
    t.hour() + utcOffset, t.minute());

  lcd.setCursor(0, 1);
  lcd.print(buf_time_local);
  lcd.print(" ");
  lcd.print(buf_time_utc);
  lcd.print(" (UTC)");
}

//setTimeClock();

/* CONTROL DE ANTENAS
 */
    
void setup() {
  Serial.begin(9600);
  Serial.flush();

  lcd.init();
  lcd.backlight();
  lcd.clear();
  rtc.begin();

  DateTime nowTime = rtc.now();
  initialDAY = nowTime.day();
  showDate(nowTime);
  showTime(nowTime);
}

void loop() {
  int delaySeconds = 1;
  if (millis() > timeFOR_ACTION) {
    timeFOR_ACTION = millis() + delaySeconds;
    DateTime nowTime = rtc.now();
    if (nowTime.day() != initialDAY) {
      showDate(nowTime); 
    }
    showTime(nowTime);
   
    int rawPower = analogRead(pinPOWER);
    if (rawPower > 100) {
      int rawBand = analogRead(pinBAND);
    }   
  }  
}

Siguiendo un tutorial en vídeo, he añadido pestaña control_auxiliar.cpp y he migrado todas las funciones, he añadido otras pestaña control_auxiliar.h y he incluido todas las cabeceras de las funciones y el

#include "control_auxiliar.h" en la cabecera.

al compilar el código me aparecen errores :

'DateTime' was not declared in this scope

a pesar de en la cabecera he iniciado la (o eso creo) la clase rtc

Las funciones de control_auxiliar.cpp "no ven" las variables globales definidas en las cabaceras, por otra parte los contructores

LiquidCrystal_I2C lcd(0x3f, 20, 4);
RTC_DS3231 rtc;

no pueden estar más que en la cabecera del sketch (antes de setup()).

Supongo que se trata de un error muy primario pero no encuentro ejemplos ni literatura específica.

Agradecería cualquier tipo de ayuda.

El error que te da es que dateTime no se conoce en control_auxiliar.h, mete el .h que hace falta, igual que lo has metido en el .ino.

En general, la filosofía es la siguiente:

  • Agrupas las funciones en un cpp, por ejemplo funciones.cpp
  • Crea funciones.h y aqui metes las macros y el prototipado de las funciones que hay en funciones.cpp.
  • Envuelve el código de funciones.h como se ve abajo, para evitar que se incluya mas de una vez:
#ifndef __FUNCIONES__
#define __FUNCIONES__

// Prototipos funciones, macros e includes que hagan falta.

#endif

En funciones.cpp empieza incluyendo funciones.h:

#include <funciones.h>

// Y todas las funciones.

Si además usas clases pues todo quedara más ordenado...
Tienes que hacer #include <funciones.h> en en .ino y/o en los .cpp que van a usar las funciones
saludos