Medidor de ROE digital con arduino (III)

El programa

En esta tercera entrega vamos a analizar el código del programa que permitirá leer los datos del sensor bidireccional de RF, hacer los cálculos y presentarlos en pantalla. También leerá la información del módulo del reloj RTC DS3231 y mostrará la fecha y las horas local y UTC en la misma pantalla. Un programa de Arduino se conoce como “sketch” y tiene la extensión *.ino. En este proyecto, el sketch es swr_meter.ino y se puede descargar del repositorio de GitHub. http://tiny.cc/qfp04y

El lenguaje de programación de Arduino

Está basado en C++. Como la mayoría de los lenguajes, su estudio se divide en tres partes principales: estructura, valores (variables y constantes) y funciones.

La programación de una placa de Arduino está orientada al manejo de dispositivos digitales que puedan interactuar con objetos del mundo real. Está considerado un lenguaje de nivel medio, accesible a la capacidad cognitiva humana.

Dentro de la estructura del sketch, es obligatorio declarar dos partes o funciones: setup() y loop(). La primera se ejecuta cada vez que se enciende o reinicia la placa para recoger la configuración. La segunda, es un bucle que se repite de forma cíclica para leer las entradas o activar las salidas.

El sketch del proyecto

El objetivo de este trabajo es analizar el código del sketch que controla un instrumento para el cuarto de la radio que incluye un monitor de ROE y potencia y un reloj-calendario. En especial, las formas eficientes de programar las instrucciones. Se trata de un proyecto abierto al que se puede añadir en el futuro otras prestaciones. Para profundizar en los conceptos básicos del lenguaje, existe numerosa bibliografía que se puede consultar fácilmente en Internet tanto en castellano como en inglés.

En este programa, he seguido un criterio básico para crear un código legible: todo el flujo del proceso se encuentra en el bucle loop().

Las funciones que leen los datos, realizan los cálculos y controlan las salidas a pantalla, se encuentran en el cuerpo del programa, antes de las funciones setup() y loop(). No he utilizado en ningún momento la función delay() para manejar los tiempos. En su lugar he añadido una clase, Cronometro(), que calcula y gestiona las pausas.

Se trata de un pequeño proyecto que consume pocos recursos del Arduino UNO o NANO:

  • El sketch utiliza el 39% del espacio de almacenamiento.
  • Las variables globales 36% de la memoria dinámica.
  • Quedan 1.296 bytes para las variables locales.

Como al procesador le sobra capacidad para ejecutar el programa, he dado preferencia a la claridad y a la facilidad para el mantenimiento y modificación de datos. Por ejemplo: declarando como constantes todos los valores de las variables que no se van a modificar en tiempo de ejecución del programa. Aunque reservan memoria dinámica, facilitan la comprensión y el mantenimiento del programa y permite identificar fácilmente algunos parámetros cuyo valor depende del sensor de RF utilizado o de la incorporación de un divisor de tensión en las entradas analógicas

Antes de comenzar a escribir las instrucciones de un programa (código), con el PC apagado, es necesario tener una idea de lo que queremos que nos resuelva y los pasos necesarios para hacerlo:

  • Leer la tensión directa y reflejada de una línea de transmisión.
  • Calcular la potencia de RF que entrega el TX.
  • Calcular la ROE.
  • Leer el tiempo actual del Reloj de Tiempo Real (RTC).
  • Extraer la hora y la fecha.
  • Informar los datos mediante una Interfaz Maquina Persona (Human Machine Interface – HMI).

Las librerías

Son programas complementarios destinados a ejecutar funciones específicas. El proyecto Arduino dispone de múltiples librerías externas de uso abierto. Muchas de las librerías necesarias se encuentran en la biblioteca del entorno de programación IDE. Otras las facilitan los fabricantes de los módulos y otras más están escritas por programadores independientes. En este proyecto vamos a utilizar:

  • <Wire.h> que se incluye en el IDE y que contiene funciones para la comunicación con el puerto serie.
  • <LiquidCrystal_I2C.h> (Frank de Brabander v1.1.2) que contiene instrucciones para la comunicación a través del puerto I2C de la placa, necesarias para la programación del
  • display con el conversor del puerto paralelo a I2C. Si se utiliza el puerto paralelo de los displays se deberá incluir la librería LiquidCrystal.h que se encuentra en la biblioteca por defecto en el IDE.
  • <RTClib.h> que contiene instrucciones para la interpretación de la información del tiempo transcurrido entre una fecha y la actual en segundos. Las instrucciones de la librería permiten identificar la hora (horas, minutos y segundos), día, día de la semana, el mes y el año. También existe una instrucción para poner en hora el reloj.

Puesta en hora del reloj

El sketch incluye una función, inhabilitada por dos barras laterales, para poner al día la fecha y el reloj en hora: //AdjustTime();

La llamada a la función de ajuste está situada en la función setup(). Para poner en hora es necesario desmarcarla (borrar las barras a la izquierda), y poner la fecha y la hora deseada en las variables correspondientes situadas en la propia función. El programa realiza los cálculos basándose en el Tiempo Universal Coordinado (UTC), por lo que es necesario iniciar el reloj con este dato. Además, es necesario tener en cuenta que la hora definida en las variables de la función se graban en la memoria del RTC al ejecutar el programa, después de compilar y subir el sketch, por lo que se produce un retraso de unos 8 a 12 segundos.

La librería incluye una función que detecta si el RTC ha estado sin alimentación y captura la hora del PC al compilar el código. Esta función puede automatizar el proceso, pero introduce siempre el retraso. Hay otros métodos más exactos para mantener en hora el reloj, entre ellos la incorporación de un GPS o de un NTP vía ethernet, pero su complejidad no justifica el beneficio, al menos para este proyecto.

El diagrama de flujo

Nos describe la lógica, principalmente el comportamiento secuencial del bucle loop().

Diagrama de flujo

Las funciones

Las subrutinas y funciones de usuario se crean para resolver necesidades específicas que no se pueden realizar con las funciones básicas. En programación, un problema complejo se resuelve a base de fraccionar en problemas simples.

Funciones de cálculo:

  • Int ReadSamples(int pin);
  • float CalcVolts(int raw);
  • float CalcSwr(float fwd, float rev) ;
  • void AdjustTime();

Funciones de pantalla:

  • void InitialScreen();
  • void InitialDate();
  • void DisplayData(float data, int pos, int line, nt width, int decimals);
  • void DisplayDate(DateTime t);
  • void DisplayHour(DateTime t);
  • void RfMask(int type);
  • void PrintBar(float swr);

Funciones auxiliares de pantalla:

  • void PrintPosition(int line, int mode, String text);
  • void PrintLine(int fila, char c);
  • String TextMonth(uint8_t mes);
  • String DayOfWeek(int dia);

CLASE Chronometer() – Métodos:

  • void tick();
  • void reset() ;
  • boolean havePassed(const int seconds);

Las funciones, conocidas también en la programación clásica como subrutinas o procedimientos, son conjuntos de líneas de código que ejecutan una tarea específica. Algunas devuelven el tipo de valor que está definido en el enunciado y otras no devuelven ningún valor. (void)

Cálculo de la tensión de RF

Todas las funciones están documentadas en el código de forma que no es necesario ocupar espacio en volver a describirlas excepto la función que recibe la lectura de las entradas de tensión analógica y devuelve la tensión rms de la línea. Esta función hace el recorrido inverso de las transformaciones que sufre la tensión directa y reflejada desde que es captada por el sensor hasta que llega a la entrada analógica del Arduino:

La lectura analógica en voltios es la relación entre la tensión máxima de la entrada (5 V) y la tensión real dividida en 1.023 segmentos digitales que proporciona el ADC de 10 bit. Para convertir este dato en voltios se ejecuta la fórmula:

float voltsPeak = (((raw * m axVOLTS) / rawSTEPS) / voltsDivider) + dropDIODE;

donde,

  • dropDIODE = caída de tensión en el diodo Schottky 1N5711, 0,3V,
  • raw = lectura de la tensión en la entrada analógica transformada en digital,
  • maxVOLTS = tensión máxima en la entrada analógica,
  • rawSTIPS = número de segmentos digitales que corresponden a la tensión máxima,
  • voltsDivider = razón del divisor de tensión resistivo, R2 / (R1 + R2),
  • trsFACTOR = razón de espiras entre el primario y secundario de T1 y T2,
  • rmsFACTOR = razón de la tensión de pico y rms, Vrms = raíz(2).

La función devuelve la tensión de pico (voltsPeak), multiplicada por la razón de espiras de los transformadores y el factor de conversión de la tensión de pico a rms. Las pruebas que he realizado evidencian una precisión de datos equiparable a la de instrumentos comerciales analógicos.

El instrumento aporta el valor añadido de la lectura digital y el reloj. El costo de los materiales es inferior al costo de la mayoría de los instrumentos comerciales analógicos.

Deseo agradecer a mi hijo Guille que de alumno ha pasado a ser profesor y que me ha puesto al día sobre las corrientes actuales de programación ágil que postulan un código claro y accesible para facilitar la comprensión y el mantenimiento.

Referencias:

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s