viernes, 18 de noviembre de 2016

Programa principal (el .ino)

En esta publicación vamos  estructurar el .ino de nuestra programación. Debemos tener en cuenta que:

  1. Queremos hacer varias cosas, es decir, no nos vale con quedarnos en un while y esperar a que llegue algo.
  2. Queremos poder gestionar la plataforma.
  3. La placa MEGA tiene varios temporizadores.
Bueno, todo esto nos lleva al uso de las interrupciones. El micro de la placa MEGA (ATMega2560 http://www.atmel.com/Images/Atmel-2549-8-bit-AVR-Microcontroller-ATmega640-1280-1281-2560-2561_datasheet.pdf) tiene 3 temporizadores. Curiosenado un poco por internet he encontrado una librería (esta es la potencia de arduino) que encapsula el uso de éstos. La librería es la TimerThree https://www.pjrc.com/teensy/td_libs_TimerOne.html funciona bien para lo que yo la he utilizado.

He generado un fichero "Definiciones.h" que irá englobando todas las definiciones que vamos a meter en compilador (es decir, no gestionables externamente). Básicamente, para no volvernos locos buscando las constantes y demás.

// 

//     Fichero: Definiciones.h
// Version: 2.0
//     Autor: Raul Hermosa
// Fecha: 20 de julio de 2016
// Descripcion: Fichero que define los parámetros fundamentales del sistema
//
#ifndef _DEFINICIONES_h

#define _DEFINICIONES_h

#define VEL_PUERTO_SERIE 115200


// define el pin CS para la SD, funciona mediante bus SPI
#define CS_SD 53

// definicion de tiempos
#define TEMPO_POLL_SENS 30 // Cada 30 segundos
#define TEMPO_POLL_PROGS 10 // Cada 10 segundos
#define TEMPO_REINI_CONFIG 2  // Cada 2 segundos
#define TEMPO_POLL_MAN_DISP 0.2  // Cada 200 milisegundos
#define TEMPO_POLL_PET_REMOTA 0.3  // Cada 300 mseg

#define NUM_POLLS_CHECK_WIFI 500 // cada 500 veces que se cheque la conf, se chequea
// el servidor WIFI

#define TEMPO_TICK 10000 // define el tiempo de interrup (tick) en microseg en Timer3
#define USEGS_EN_SEG 1000000 // microsegs de 1 segundo
//definiciones de los numeros de ticks
#define NUM_TICKS_SEG USEGS_EN_SEG/TEMPO_TICK // Ticks cada 1 segundo
#define NUM_TICKS_SENS TEMPO_POLL_SENS*NUM_TICKS_SEG
#define NUM_TICKS_PROGS TEMPO_POLL_PROGS*NUM_TICKS_SEG
#define NUM_TICKS_CONFIG TEMPO_REINI_CONFIG*NUM_TICKS_SEG
#define NUM_TICKS_MAN_DISP TEMPO_POLL_MAN_DISP*NUM_TICKS_SEG
#define NUM_TICKS_PET_REMOTA TEMPO_POLL_PET_REMOTA*NUM_TICKS_SEG

#endif //_DEFINICIONES_h_


Bueno, la realidad es que nuestro .ino es de lo más sencillo. Sólo programa una serie de temporizadores y pone un flag para que se ejecuten diferentes métodos.


//

// Fichero: ControlDomoPlat.ino
// Version: 2.0
//     Autor: Raul Hermosa
// Fecha: 20 de julio de 2016
// Descripcion: Fichero principal de ejecucion de plataforma IoT
//

#include <TimerThree.h>

#include "GestorConfiguracion.h"
#include "Definiciones.h"

// Crea el Gestor de Configuracion para que habilite la configuracion del sistema
GestorConfiguracionClass _config;

// Variables locales
int num_ticks_seg;
int num_ticks_sens;
int num_ticks_progs;
int num_ticks_config;
int num_ticks_man_disp;
int num_ticks_pet_remota;

bool chequea_tick_seg;
bool chequea_tick_sens;
bool chequea_tick_progs;
bool chequea_tick_config;
bool chequea_tick_man_disp;
bool chequea_tick_pet_remota;

void setup()
{
Serial.begin(VEL_PUERTO_SERIE);
delay(200);

Serial.println(F("\n\nPUERTO SERIE INICIADO"));
_config.init();
Serial.println(F("\n\nINICIANDO TEMPOS"));
Timer3.initialize(TEMPO_TICK);
Timer3.attachInterrupt(ISR_tick);
// Configuro el temporizador para controlar los ticks donde controlar las tareas periodicas
num_ticks_seg = 0;
num_ticks_sens = 0;
num_ticks_config = 0;
num_ticks_man_disp = 0;
num_ticks_pet_remota = 0;

chequea_tick_seg = false;
chequea_tick_sens = false;
        chequea_tick_progs = false;
chequea_tick_config = false;
chequea_tick_man_disp = false;
chequea_tick_pet_remota = false;
}

void loop()
{
if (chequea_tick_sens)
{
_config.escribe_sensor_log();
chequea_tick_sens = false;
}
if (chequea_tick_config)
{
_config.configura_sistema();
chequea_tick_config = false;
}

if (chequea_tick_man_disp)
{
// TODO: ivocar un metodo de chequeo de peticion manual
// _config.chequea_pet_manual();
chequea_tick_man_disp = false;
}

if (chequea_tick_pet_remota)
{
//Serial.println(F("Chequeo peticiones web"));
//_config.chequea_peticion_remota();
chequea_tick_pet_remota = false;
}

if (chequea_tick_progs)
{
//Serial.print(F("Chequeando PROGS: ")); Serial.println(_rtc.getData().toString());
//_config.chequea_tempos();
chequea_tick_progs = false;
}
}

void ISR_tick()
{
if (num_ticks_seg++ >= NUM_TICKS_SEG)
{
chequea_tick_seg = true;
num_ticks_seg = 0;
}
else if (num_ticks_sens++ >= NUM_TICKS_SENS)
{
chequea_tick_sens = true;
num_ticks_sens = 0;
}
else if (num_ticks_config++ >= NUM_TICKS_CONFIG)
{
chequea_tick_config = true;
num_ticks_config = 0;
}
else if (num_ticks_progs++ >= NUM_TICKS_PROGS)
{
chequea_tick_progs = true;
num_ticks_progs = 0;
}
else if (num_ticks_man_disp++ >= NUM_TICKS_MAN_DISP)
{
chequea_tick_man_disp = true;
num_ticks_man_disp = 0;
}
else if (num_ticks_pet_remota++ >= NUM_TICKS_PET_REMOTA)
{
chequea_tick_pet_remota = true;
num_ticks_pet_remota = 0;
}
}


Como puede verse, al final lo que he hecho es utilizar un temporizador del micro para generar los temporizadores que a mi me interesan. Defino una serie de tiempos en Definiciones.h (lo he hecho para configurar en segundos y dar claridad), pongo unos contadores, configuro el tempo 3 y cada vez que salta la interrupción (invoca la rutina ISR_tick) controlo con los contadores si es el timeout de cada uno. Como siempre, en esa rutina no conviene hacer nada (evita comprometer datos), sólo pongo un flag y reinicio los contadores. En el loop es donde invoco los métodos que me interesan a través de un obejto de clase GestorConfiguracion, de la que todavía no hemos hablado.

Como puede verse todo muy fácil, cada vez que acabemos de hacer una cosa, esperamos a que nos avise el flag de qué toca revisar. De esta forma evitamos quedarnos enganchados con cosas como delay() o while (xx.available()), que sirven para otros propósitos.

Ahora ya podemos complicarnos la vida en los métodos invocados, si se quiere hacer pruebas, activar el monitor serie y lo podéis ir viendo, a efectos de prueba no hace falta la clase GestorConfiguracion, se puede imprimir algo y ya está.

Aunque es muy evidente, espero que os sirva para esto o para otros proyectos.

No hay comentarios:

Publicar un comentario

Datos personales