Reedición

Ya he presentado la memoria y, tras hacer público el blog, queda adecentar un poco las entradas. Estas irán saliendo en breve. También falta subir el código fuente de las aplicaciones el cual se subirá una vez reeditado el blog.

PCB bloque maestro

Comprobado el funcionamiento del módulo maestro en la placa de prototipos, he procedido a la realización de la placa de circuito impreso o PCB. Como requisitos, se intentará trazar todas las pistas por una sola capa y se intentará compactar para permitir el encapsulado en una caja si se desease.

Esquemático

El esquemático se ha modificado ligeramente, el final es el siguiente:

Se han cambiado algunos pines de conexión entre el transceptor y el microcontrolador para facilitar el trazado de pistas. Estos cambios se han verificado en la placa de prototipado previamente.

Layout

Para realizar el layout se ha tenido que crear el footprint para el cristal de cuarzo (Y1) y se han reutilizado los footprints de los condensadores de 1µF cerámicos, de los LED y del transceptor diseñados previamente.

La distribución de elementos se ha realizado de forma que el conector del USB, el transceptor y el conector del programador no estén en el mismo lado del rectángulo que forma la PCB (que no compartan lado). De este modo se facilita la conexión y el acceso a los conectores desde los lados. El transceptor se ha situado con la antena hacia el exterior para poder emplear un zócalo en el microcontrolador, pues el microcontrolador con el zócalo es más alto que el transceptor. Los indicadores luminosos LED se han situado dependiendo de su finción; los indicadores del estado de la conexión USB se ha situado próximos al conector (comparten lado con él) y los de notificaciones se han situado en el lado libre de la PCB. El cristal de cuarzo se ha aproximado lo máximo posible al microcontrolador al igual que los condensadores de desacoplo a sus respectivos. En cuanto al regulador, se ha aproximado al conector USB y a los condensadores de 1µF.

Respecto a las pistas y conexiones, dado que la corriente que circulará por ellas no es elevada, se han diseñado con un ancho de 0.8mm; tamaño cómodo para la soldadura. El cobre sobrante se ha utilizado como plano de masa, de este modo se reduce su impedancia. También hay que destacar que ha sido necesario el empleo de 3 puentes para asegurar el trazado por una sola cara.

A continuación se muestra una captura del layout.

Fabricación y montaje

Tras la fabricación, la PCB resultante se muestra a continuación:

Se puede observar que durante la fabricación los PAD del conector del transceptor han desaparecido. Esto es debido a la tolerancia del taladro pero no suponen ningún obstáculo para su soldado.

También se puede observar que el plano de masa parece interrumpido al pasar entre el footprint del regulador. Se ha comprobado la conectividad entre ambos puntos y es correcta.

Una vez ensamblados y soldados todos los componentes, la PCB resultante se muestra a continuación.

Comprobación

Para verificar el diseño de la PCB realizada, se han realizado distintas comprobaciones.

Se ha comprobado que las soldaduras realizadas no puedan producir errores. Una vez comprobado esto, se ha programado el microcontrolador.Verificada la programación, se ha conectado al PC mediante el cable USB. Se han verificado las tenisones de 5V en el conector del USB y de 3.3V en el resto del dispositivo. Se ha verificado el funcionamiento del pulsador de reset y de la comunicación con el PC. Por último, se ha conectado el transceptor y se ha verificado la comunicación con el sensor.

Comunicación: El protocolo

Para la comunicación inalámbrica, el objetivo principal es el bajo consumo por lo que el protocolo se debe adaptar a él además las interferencias del canal hacen necesario incluir elementos de varificación de datos.

Configuración de la comunicación

El transceptor permite configurar diversos aspectos de la comunicación.

Se trabajará en modo ShockBurst dadas sus ventajas (ver la entrada del transceptor). En este modo, la velocidad de la comunicación se puede configurar de 1Mbps o de 250Kbps. Puesto que la velocidad no es crítica en la aplicación, se ha decidido establecerla a 250Kbps dado que su consumo en transmisión y en recepción es algo menor y la sensibilidad es -10dBm mayor.

Protocolo de comunicación

El protocolo se puede dividir en dos partes, el inicio de conexión y la comunicación.

El inicio de conexión es la parte del protocolo que define el mecanismo de la unión de un sensor a la red. Se parte de que cada nodo sensor dispone de una dirección única establecida durante la programación. Este mecanismo se inicia cuando el sensor envía un paquete de inicio de conexión al nodo de adquisición. Una vez el paquete es enviado, el sensor entra en modo de recepción, escucha del canal, esperando un paquete de confirmación de la conexión por parte del nodo de adquisición. Una vez el nodo sensor ha recibido este paquete, se considera que está conectado.

Puesto que los nodos sensores son autónomos y requieren un bajo consumo son los que fijan el protocolo de comunicación. El transceptor es el componente que supone un mayor consumo, es por esto que se debe intentar que esté activo el menor tiempo posible.

Tal y como se ha descrito en entradas anteriores, la comunicación la fija el funcionamiento del nodo sensor; el nodo de adquisición se encuentra siempre a la escucha y es tras una medida del nodo sensor cuando el nodo de adquisición tiene un breve espacio de tiempo para enviarle un comando al sensor. Este funcionamiento supone que el nodo de adquisición no podrá enviar un comando al nodo sensor hasta que este le envíe una medida. Hay que tener en cuenta que el tiempo entre medidas es configurable entre 5 segundos y 21 minutos.

Topología de los paquetes o tramas

Tal y como se ha comentado, el paquete en el modo Shockburst se puede dividir en tres partes; la dirección, los datos y el CRC. En total el tamaño del paquete no debe superar los 256 bits (32 bytes) puediendo tener la dirección un tamaño de hasta 40 bits (5 bytes) y el CRC un tamaño de 8 o 16 bits (1 o 2 bytes).

Actualmente la banda ISM es muy utilizada, es por esto que el sistema se encontrará con multitud de interferencias. Para hacer más robusta la comunicación y evitar la recepción de paquetes erróneos, se ha tomado una dirección y un CRC de 2 bytes, 65536 combinaciones posibles.

Para definir la longitud de los datos se debe tener en cuenta los elementos que forman la trama de datos. Estos elementos son la identificación, los comandos y los argumentos.

  • La identificación

    Cuando el sensor se comunica con el nodo de adquisición, el sensor debe indicar su dirección o algún dato que lo identifique ya que el paquete no incluye ninguna información acerca del origen del mismo. Se podría pensar en incluir la totalidad de la dirección del enviante pero esto supondría incluir 2 bytes a los datos con el consiguiente aumento del tiempo en el aire, y por tanto consumo, que esto supone. Por ello se emplea el siguiente modo que reduce la información de la dirección a un único byte al que he nombrado identificación o ID.

    Básicamente lo que se hace es repetir la información; se divide la dirección en dos, obteniéndose un byte de mayor peso (MSB, most significative byte) y un byte menor peso (LSB, least significative byte). Se establece que el byte de mayor peso es el byte de menor peso negado, la figura siguiente muestra un ejemplo.

    De este modo, con un solo byte se puede obtener la dirección completa negándolo bit a bit. Al haber un solo byte único, el de menor peso, el sistema permitiría introducir hasta 256 sensores lo cual es excesivo para el propósito del proyecto.Por ello, este byte de menor peso a su vez se divide en dos, teniéndose por un lado los 4 bits más significativos (MSb) y los 4 bits menos significativos (LSb). De este modo son los cuatro bits menos significativos los que realmente contienen un número único que identifica cada sensor. Los 4 bits más significativos pueden contener cualquier valor y se utilizan para evitar direcciones poco robustas como por ejemplo 0xFF00. Se deduce entonces que la red podrá disponer de hasta 16 sensores (24), valor óptimo para el propósito del proyecto.

    Se concluye entonces que el tamaño de la identificación es de un byte.

  • Los comandos y los argumentos

    Los comandos son identificadores únicos que indican una acción a realizar al nodo destino. Algunos comandos pueden necesitar de argumentos que son datos que lo complementan.

    Los comandos se han diseñado de modo que se pueda realizar una verificación del mismo rápida. De este modo al recibir un comando incorrecto se detendrá el procesado y se continuará con el funcionamiento normal.

    Dado que las necesidades de comunicación no son extensas, se ha decidido que se puedan definir hasta 16 comandos. Esto es debido a que el mecanismo de verificación empleado consiste en que los comandos son de un byte y que los cuatro bits más significativos son los cuatro bits menos significativos negados. Por lo tanto, para comprobar el comando se ha implementado la función siguiente.

       
    unsigned char verify_cmd(unsigned char command)
    {
            return((command&0x0F)==((~command)&0xF0)>>4);
    }

Los comandos y los argumentos establecen en gran medida la trama de los datos, se pueden distinguir las siguientes tramas.

  • Trama de envío de medidas.

    Esta trama la utilizan únicamente los nodos sensores. Es la trama más importante al ser la más utilizada. Es por esto que es la que fija la longitud máxima de la trama de datos. A máxima resolución, las medidas suponen 12 bits para la HR y 14 bits para la temperatura que, para simplificar el procesado, se envían en 16 bits de modo que ambas medidas suponen 4 bytes.

  • Trama de inicio de conexión.

    Esta trama la utilizan únicamente los nodos sensores. Se puede observar que la trama incluye toda la información posible acerca del sensor para que el nodo de adquisición conozca el estado del sensor. Es decir, se incluye la dirección completa del nodo sensor (de este modo se verifica la trama), los dos bytes de configuración del transceptor (uno contiene el canal y el otro la potencia de transmisión) y el byte de configuración del sensor (contiene la resolución a la que opera, el estado del calentador y el estado de la batería). Esta trama no contiene identificación ya que esta la fija el nodo de adquisición.

  • Trama de confirmación de la conexión.

    Esta trama la utiliza únicamente el nodo de adquisición. Mediante esta trama se confirma la conexión a la red y se establece la identificación.

  • Trama de configuración

    Esta trama puede ser utilizada por ambos tipos de nodos y permite el envío de dos comandos a la vez. Se observa que la longitud máxima de cada argumento es de un byte. Esto es así debido a que los argumentos de la mayoría de los comandos, que precisan de argumentos, son de este tamaño.

Las necesidades de comunicación entre el nodo sensor y el nodo de adquisición no son las mismas que entre el nodo de adquisición y el sensor, es por esto que se definen dos listados de comandos.

  • Nodo sensor → nodo de adquisición

    • CMD_MEAS_DATA 0xF0. Indica que los argumentos son las medidas realizadas.
    • CMD_MY_NAME_IS 0xE1. Pide la
  • Nodo de adquisición → nodo sensor

Software de representación de datos: Comunicación con el puerto serie

Java por defecto no incluye ninguna biblioteca para la comunicación por el puerto serie. No obstante existen diferentes bibliotecas que lo permiten, como la Java Communications 3.0 API, implementada por la propia SUN, la cual tiene como inconveniente que sólo funciona bajo Solaris SPARC y x86, y Linux x86. Es decir, usando esta biblioteca se pierde la característica más interesante de Java: la independencia de la plataforma en la que se trabaje. Además, el desarrollo de dicha biblioteca ha sido abandonado por SUN.

Por este motivo existe la biblioteca RXTXComm, de licencia libre LGPL, la cual provee de comunicación mediante el puerto serie y el paralelo al kit de desarrollo de Java (JDK, Java Development Toolkit). Esta biblioteca suple con creces el defecto de la anterior ya que se ha portado a un gran número de arquitecturas entre ellas las principales GNU/Linux, MacOSX y MSWindows.

Uso

En el wiki de la biblioteca hay diversos ejemplos muy claros acerca del uso de la misma. En concreto los ejemplos "Two way communcation with the serial port" y "Discovering comm ports" representan la funcionalidad requerida para el proyecto por lo que son de especial interés.

Instalación

Para la instalación de la biblioteca se recomienda leer el archivo INSTALL que se incluye con las mismas o, de forma más detallada, mirar el wiki.

Software de representación de datos: Obtención de los datos transmitidos para el procesado

Ya se ha visto que la comunicación con Java vía el puerto serie se traduce en un "stream" de bits que se obtienen en forma de vector de bytes. Los bytes enviados por el Maestro son sin signo y comprenden, en decimal, un número de entre 0 y 255. Sin embargo, en Java la naturaleza de los tipos es con signo y no existe ningún modificador para hacerlos sin signo (no existe el unsigned de C o C++). Esto implica que una conversión directa de el tipo byte a entero dará lugar a un número comprendido, en decimal, entre -128 y 127. Es por esto que la obtención para el procesado de los datos recibidos no es trivial.

Una solución para obtener el dato sin signo es realizar un cambio de tipos de manera que el valor recibido positivo se pueda expresar (esté contenido) en otro tipo. En nuestro caso, el tipo obtenido es un byte (255 como máximo) el cual se puede contener en un short ya que su longitud es de 2bytes por lo que comprende valores entre -32,768 y 32,767. De este modo, obtener un byte sin signo consiste en hacer una transformación de tipos con un enmascaramiento para no convertir el signo.

Entonces el código es el siguiente:

 
short UnsignedByte[] = new short[posicionNula];
        for (i=0;i<posicionNula;i++)
        {
            UnsignedByte[i]=(short)(0x00FF & mensaje[i]);
            PosMensaje=PosMensaje+(char)UnsignedByte[i];
        }

Donde

  • mensaje es el vector de bytes recibido.
  • posicionNula contiene la longitud del vector de bytes mensaje.
  • PosMensaje es mensaje representado como una cadena de caracteres o String. De este modo se puede representar en la consola.

Esta conversión de tipos es indeseable ya que se desperdicia espacio del reservado para cada tipo. No obstante es la mejor entre las posibles.1

Notas
1

En esta página muestran el mismo método de forma algo diferente. Además convierten distintos tipos a unsigned.

Referencias

SUN Microsystems The Java Tutorials.

SÁNCHEZ LÓPEZ M.; ALONSO BARBERÁN V. El lenguaje de programación Java.
Valencia: Servicio de publicaciones de la Universidad Politécnica de Valencia, 2003. 354 p.
ISBN:9788477215264

Bloque sensor: Software final

Una vez verificado el funcionamiento de los módulos diseñados, he procedido a diseñar el software del módulo sensor.

Tal y como se ha definido, el funcionamiento a grandes trazos se muestra en el siguiente diagrama de flujo.

Es decir, ante una señal de reset o ante el encendido del microcontrolador el microcontrolador realiza una inicialización del sistema.

Inicialización

Esta inicialización, en primer lugar, inicializa el microcontrolador; establece la frecuencia de funcionamiento del reloj interno, las interrupciones y el estado y la dirección de las líneas, haciendo especial hincapié en el bajo consumo.

Una vez inicializado el microcontrolador, se inicializa el sensor a su configuración por defecto de medidas de 14bits para la temperatura y 12bits para la humedad relativa y no recargar la memoria de calibración. No obstante, antes de configurar el sensor se realiza una medida para cargar al menos una vez la memoria de calibración.

El siguiente dispositivo a inicializar es el transceptor. El transceptor se configura con los 15bytes de configuración inicial. Esta palabra de configuración establece lo comentado acerca de la comunicación.

Barrido de canales

Una vez inicializado el sistema, se realiza un barrido de canales hasta lograr la conexión.

El transceptor se ha inicializado con el canal 0. Para implementar la conexión en "caliente", al resetear o encender el módulo sensor, éste realiza un barrido de canales buscando establecer conexión con el módulo maestro. Este barrido se ha implementado como muestra el diagrama de flujo siguiente.

Si no se ha establecido conexión con el módulo maestro, el dispositivo envía el comando de inicio de conexión a la dirección del maestro por el canal inicial. Ante este comando el maestro debe responder con el paquete de respuesta, por lo que se entra en modo recepción durante un tiempo ajustado de respuesta del maestro.

Si pasado dicho tiempo no se ha recibido el paquete de respuesta o se ha recibido un paquete no válido, se comprueba si se está trabajando en el canal máximo, es decir, el canal 124. De no ser así, se incrementa el canal, se configura el transceptor y se repite el proceso. Si se está operando en el canal máximo, se comprueba si se está trabajando también a la máxima potencia, esto es 0dBm. De no ser así, se configura el transceptor con el canal inicial 0, se incrementa la potencia y se repite el proceso. Si se está operando a la máxima potencia, significa que tras realizar los barridos de canales para todo el rango de potencias no se ha logrado establecer comunicación, es decir el sensor se encuentra fuera de rango o no hay ningún nodo maestro a la escucha. Esto lo indica al usuario mediante el LED de estado y detiene el barrido hasta una señal de reset.

En caso de recibir el paquete de respuesta, se establece conexión y se continúa con el funcionamiento normal del sistema.

Medidas y envío

Una vez establecida la conexión, se procede a realizar las medidas. Primero se realiza la medida de humedad relativa y después la de temperatura. Estas medidas se realizan mediante la función de S_measure implementada en el módulo sensor.c/.h .

Una vez se dispone de los datos de las medidas. Éstos se envían, sin procesar, como un único paquete al nodo maestro. Tal y como se ha definido la comunicación, cuando el nodo maestro recibe un paquete de medidas, éste puede enviar algún comando al sensor. Entonces, una vez enviado el paquete, se configura en modo recepción el transceptor durante un tiempo ajustado.

Recepción y procesado

Si durante el tiempo de recepción se recibe un comando del maestro, el comando debe ser procesado.

El procesado se encarga de interpretar el comando recibido y actuar en consecuencia. El funcionamiento del procesado se muestra en el siguiente diagrama de flujo.

En primer lugar se procede a la verificación del dato. Tal y como se ha comentado, la estructura del comando hace que sea facilmente verificable, es decir, es fácil discernir entre un comando incorrecto y uno correcto. De este modo, al realizar la verificación antes de evaluar el comando, se evita seguir con el procesado ahorrándose tiempo y reduciendo el consumo.

Si el comando es correcto, se procede a su evaluación. Se busca que coincida con

Si durante el tiempo de recepción no se ha recibido ningún comando del maestro, se espera a la medida siguiente.

Tiempo entre medidas

El watchdog del microcontrolador, al disponer de la combinación de dos prescalers, permite un rango muy ámplio de tiempo de desbordamiento, en conreto permite desde 1.24ms a 325.36s. Estos tiempos son incómodos al no ser enteros, por lo que se utilizará el tiempo más exacto como base de tiempos. Para cierta configuración de ambos prescalers, se puede lograr un tiempo de 5,08366 segundos el cual es muy interesante como base de tiempos ya que se pueden lograr valores redondos como 60s (12x5), 120s (24x5).

El número que multiplica a la base, múltiplo de la base de tiempos, es de tipo byte por lo que se puede obtener un tiempo entre medidas de hasta 1270 segundos que son aproximadamente 21 minutos, claramente suficiente.

La forma de realizar el tiempo entre medidas se describe en el diagrama siguiente.

Se utiliza una variable, t_count, para contabilizar el número de desbordamientos producidos. Esta variable se inicializa a cero antes de activar el watchdog. El watchdog se configura con un tiempo de desbordamiento de 5.08 segundos (prescaler del registro OPTION 001 y el del watchdog WDTCON 1011) y se activa el watchdog.

Una vez activado el watchdog, se entra en modo de bajo consumo esperando el desbordamiento del watchdog. Una vez esto ocurre, se resetea el contador del watchdog, se incrementa la variable t_count, pues se ha producido un desbordamiento, y si esta variable, el número de desbordamientos producidos, es menor o igual al múltiplo de la base de tiempos establecido, es porque no se ha alcanzado el número de desbordamientos deseados por lo que se vuelve a entrar en modo de bajo consumo. Si se ha alcanzado el número de desbordamientos deseados, la variable t_count es mayor que el múltiplo establecido, se desactiva el watchdog y se continúa con el programa principal.

Bloque sensor: Diseño Software para bajo consumo.

El microcontrolador tiene líneas que pueden configurarse como entradas analógicas o como entradas/salidas digitales. Hay que tener en cuenta las señales que se aplican a estos pines ya que pueden suponer un consumo de corriente elevado.

Una línea de entrada digital consume la mayor cantidad de corriente cuando la tensión de entrada está entre la tensión de alimentación y la referencia. Esto es debido a que si la tensión de entrada está próxima al punto medio entre la alimentación y la referencia, los transistores que forman el buffer de entrada se polarizan en la región lineal lo que introduce un consumo de corriente considerable. Esto se puede evitar si cada línea puede configurarse como una entrada analógica, ya que este buffer se desconecta reduciendo así la corriente de la línea. Esto es debido a que las entradas analógicas tienen una impedancia de entrada muy elevada por lo que su consumo es mínimo.

Es por esto que si una línea no se utiliza, puede dejarse desconectada y configurada como línea de salida con un nivel lógico definido o se puede configurar como una entrada fija, externamente, a un nivel lógico definido.

También se debe tener en cuenta a la hora de inicializar un puerto, que tras un Power-on Reset, reset al alimentar al dispositivo, algunos registros como los PORT, los registros que contienen el valor de la línea, tienen un valor desconocido. Si los registros TRIS, los registros que configuran la dirección de la línea, se configuran antes que los PORT, es posible que se generen pulsos de corriente durante la inicialización del puerto. Por ejemplo, una forma segura de inicializar un puerto es primero borrar el contenido del registro PORT y luego configurar las líneas del puerto como salidas.

Referencias

Microchip Low Power solutions: Tips'n'Tricks.

Bloque sensor: Software, módulos principales

Seleccionadas las herramientas, he procedido a realizar el programa del sensor.

Antes de programar la funcionalidad completa del módulo sensor, se ha realizado la programación de los módulos de comunicación con el transceptor y con el sensor. De este modo, se puede verificar su funcionamiento independientemente. Así se reducen los problemas de depurado.

Comunicación con el transceptor

Tal y como se comentó en la entrada del transceptor, el protocolo de comunicación utiliza una línea de reloj y otra de datos, a parte de las líneas de configuración. Donde la frecuencia de la línea de reloj no podía ser superior a 1Mbps, es decir la duración mínima de cada bit debe ser de 1µs. Para reducir el tiempo de comunicación durante el cual el microcontrolador y el transceptor están activos, es decir suponen un consumo de corriente, se intentará operar a la frecuencia máxima.

Revisando la entrada del transceptor, se deduce que este módulo necesitará de, como mínimo, las siguientes funciones:

  • Enviar un paquete de datos a una dirección.
  • Entrar en modo recepción durante un tiempo y obtener el paquete recibido si es el caso.
  • Configurar el transceptor. Ya sea configurar la palabra completa (15bytes) o sólo una parte.

Donde se observa que a la función de enviar se le manda un paquete de datos y la de recibir lo devuelve. Este paquete que se enviará consiste en una serie de bytes que contienen la dirección y el dato. Para realizar un código más inteligible, se ha realizado una estructura que contiene un vector de bytes para la dirección y otro para los datos:

 
struct package
{
        unsigned char address[LEN_ADDR];
        unsigned char data[LEN_DATA];
};

Donde LEN_ADDR y LEN_DATA son macros que contienen la longitud de la dirección y de los datos respectivamente.

Tal y como se observa en la figura siguiente, el módulo dispone de tres funciones de uso interno o privadas (con fondo gris) cuya función se muestra a continuación. Son de alcance privado porque implementan una funcionalidad que se utiliza en más de una ocasión.

  • void RF_putByte(unsigned char databyte)

    Esta función le pasa bit a bit el byte al transceptor. Para ello, se le aplica al byte una máscara de un bit que se va desplazando.

  • void RF_configTx(void) y void RF_configRx(void)

    Estos métodos configuran al transceptor con un único bit el cual fija el modo de operación; en transmisión o en recepción.

Entonces, a la función enviar (RF_send) se le pasa la estructura package que contiene la dirección y los datos a enviar. Esta función configura el transceptor en modo transmisión (usa el método RF_configTx) y le pasa los datos del paquete al transceptor (mediante la función RF_putByte).

La función recibir (RF_receive) se le pasa un puntero con la estructura package donde almacenará los datos recibidos y un byte el cual fija el tiempo durante el cual el transceptor estará recibiendo. Durante este tiempo el microcontrolador está en modo de bajo consumo y es despertado por el perro guardián. Entonces el byte que hace configurable el tiempo fija el valor del prescaler del perro guardián. Al igual que para la función enviar, esta función hace uso de las funciones RF_putByte y RF_configRx.

Para configurar el transceptor está la función RF_configure, a la cual se le pasa un vector de bytes con los bytes de configuración y un byte que indica la longitud del vector. De este modo, se pueden configurar el número de bytes que se desee, 15 como máximo, teniendo en cuenta que el primer byte, posición 0 del vector, deberá ser el más significativo. Esta función hace uso de la función RF_putByte.

Para configurar de forma más cómoda los 15bytes del transceptor, se han creado una serie de macros o etiquetas que se encuentran en el fichero de cabecera transceiver.h. Se muestra un ejemplo a continuación.

 
const unsigned char transceiver_config[15]={DATA2_W,DATA1_W,ADDR2_4,ADDR2_3,ADDR2_2,ADDR2_1,
ADDR2_0,ADDR1_4,ADDR1_3,ADDR1_2,MY_ADDRESS_H,MY_ADDRESS_L,ADDR_W_16b|CRC_16b|CRC_EN_ENABLE,
RX2_EN_DISABLE|CM_SHOCKBURST|RFDR_SB_250KB|XO_F16MHZ|RF_PWR_20,RF_CH|RXEN_TX};

Comunicación con el sensor

La comunicación con el sensor se realiza mediante dos líneas, una de reloj y otra de datos. Como se ha visto, el sensor dispone de un registro de estado de un byte, que puede ser leído y escrito, y de una serie de comandos que permiten escritura/lectura de el registro de estado, realizar una medida de temperatura/humedad relativa y realizar un reset "suave".

Las funciones implementadas se muestran en la figura siguiente. Las de fondo gris son de uso interno o privadas. Su funcionalidad es la siguiente:

  • void S_putByte(const unsigned char databyte)

    Esta función gestiona la línea de datos y la de reloj enviándole al sensor el byte bit a bit. Para ello hace uso de una máscara con la que se obtiene el contenido del byte bit a bit.

  • unsigned char S_getByte(const unsigned char ack)

    Realiza el proceso inverso de la función anterior. Se comprueba la línea de datos y se va desplazando una máscara de un bit cada flanco de la línea de reloj. De este modo, cuando la línea de datos tenga el nivel lógico 1, su posición en el byte a obtener viene indicada por la máscara. El parámetro ack indica si se debe confirmar o no la recepción del byte. Mediante este parámetro se puede controlar el leer o no el CRC al confirmar o no la recepción del dato completo.

  • void S_transStart(void)

    Es un método que realiza la secuencia de inicio de transmisión. Esta secuencia se realiza cada vez que se desea comunicarse con el sensor.

De la figura se observa que existen dos métodos accesibles por el programador, el método S_resetConnection y S_softReset. Ambos realizan un reset del sensor con la diferencia de que el método S_resetConnection resetea únicamente la comunicación, y el método S_softReset resetea la comunicación y el registro de estado.

En cuanto a las funciones, la función S_read_status obtiene el registro de estado del sensor ( un byte). La función S_write_status envía al sensor el registro de estado que se le indica. Para facilitar la escritura del registro de estado, el fichero de cabecera sensor.h dispone de diversas macros. A continuación se muestra un ejemplo de su uso.

 
S_write_status(HEATER_OFF|OTP_NO_RELOAD|T14b_HR12b);    //Sensor wont reload OTP mem

La función más importante es S_measure, la encargada de realizar las medidas. Se le pasan como argumentos un puntero a una estructura del tipo measures, que se describe a continuación, y un parámetro que indica el tipo de medida; de humedad relativa o de temperatura. Para este último argumento se han definido dos macros, TEMP y RHUM, los cuales facilitan su uso. Respecto a la estructura del tipo measures se trata de una estructura que contiene un vector de dos bytes. Esto se ha realizado de este modo, para hacer más eficiente la función al operar con un puntero. A continuación se muestra la definición de la estructura measures.

 
struct measures
{
        unsigned char data[2]; //2 bytes because the maximum measure resolution is 14bits
};

Tal y como se comentó en la entrada del sensor, éste tarda un tiempo considerable en realizar las medidas. Es por esto que ese tiempo, para reducir el consumo, el microcontrolador se encuentra en modo de bajo consumo. Para sacar del modo de bajo consumo al microcontrolador una vez la medida esté disponible, se utiliza la interrupción ante un cambio de nivel (InterruptOnChange) que implementan las líneas del puerto A del microcontrolador. Este cambio de nivel es realizado por el sensor sobre la línea de datos; cuando la medida ha finalizado, pone la línea de datos a nivel bajo tal y como se comentó en la entrada del sensor.

Comunicación: Tipos y necesidades

Tal y como se mostró en la entrada de descripción del proyecto, el sistema precisa de dos tipos de comunicaciones bidireccionales, una inalámbrica y otra por cable. Al ser bidireccionales, cada tipo de comunicación se puede dividir en dos comunicaciones unidireccionales entre dos implicados. Es decir:

  • Comunicación inalámbrica: Sensor ↔ Maestro

    • Sensor → Maestro

    • Maestro → Sensor

  • Comunicación por cable: Maestro ↔ PC

    • Maestro → PC

    • PC → Maestro

De este modo cada parte de la división se puede simplificar como una comunicación unidireccional que suple unas necesidades de comunicación:

  • Comunicación inalámbrica: Sensor ↔ Maestro

    • Sensor → Maestro

      • Medidas de Humedad relativa y de Tª. Contiene las medidas realizadas sin procesar, es decir en "ticks".
      • Palabra de configuración del sensor. El maestro lo utilizará para verificar cambios realizados sobre la configuración del sensor.
      • Penúltima palabra de configuración del transceptor. Contiene la potencia de transmisión. El maestro lo utilizará para verificar cambios.
      • Inicio de transmisión. Contiene la dirección del sensor, la configuración del transceptor y del sensor. De este modo el maestro conoce el sensor y le asigna una ID.
      • Dato recibido correctamente.
      • Batería baja.
      • Errores.

    • Maestro → Sensor

      • Respuesta al comando inicio de transmisión.
      • Cambia la potencia de transmisión.
      • Cambia la configuración del sensor.
      • Cambia de canal.
      • Ajuste del tiempo entre medidas.
      • ¿Cuál es tu potencia de transmisión?.
      • ¿Cuál es la configuración del sensor?.
      • Duerme durante X tiempo.
      • Entra en modo test.
      • Apágate.

  • Comunicación por cable: Maestro ↔ PC

    • Maestro → PC

      • He recibido la siguiente medida de tal sensor.
      • Tal sensor tiene la siguiente configuración del sensor.
      • Tal sensor tiene la siguiente configuración del transceptor.
      • Tal sensor indica batería baja.
      • Esta es la dirección de tal sensor.
      • Se ha conectado un nuevo sensor.

    • PC → Maestro

      • Dime la configuración del sensor de tal sensor.
      • Dime la configuración del transceptor de tal sensor.
      • Dime la dirección de tal sensor.
      • Duerme al sensor tal durante tanto tiempo.
      • Ajusta el tiempo entre medidas del sensor tal a este valor.
      • Cambia el canal de los sensores en lista.
      • Cambia la potencia de transmisión de tal sensor.
      • Apaga tal sensor.
      • Modo test.

Estas necesidades forman el protocolo ya que el protocolo debe ser capaz de suplirlas todas.

Funcionamiento global

Antes de empezar a programar he pensado que es conveniente definir completamente la comunicación inalámbrica ya que es el punto central del proyecto y al ser nexo entre maestro y esclavo condiciona totalmente el funcionamiento de estos. Es por esto que esta entrada define en esencia el funcionamiento tanto del sensor como del transceptor y en algunos casos detalles del software de representación de datos.

Comunicación inalámbrica

Para reducir el consumo la comunicación debe evitar largos periodos de "polling" en el canal. Es por esto que se ha decidido que la comunicación se realizará acorde al funcionamiento del sensor.

El funcionamiento básico consiste en que el sensor realiza una medida cada periodo configurable (este periodo es muy prolongado respecto a la velocidad de funcionamiento de los microcontroladores por lo que la mayor parte de ese tiempo el microcontrolador se encuentra en modo de bajo consumo) ,envía el dato medido y entra en modo de bajo consumo esperando a realizar otra medida. Lógicamente este funcionamiento descrito muestra un tipo de comunicación unidireccional, el sensor no puede recibir datos. Por supuesto se necesita una comunicación bidireccional por lo que se debe añadir al funcionamiento del sensor la acción de ver si le han enviado algo, recibirlo y procesarlo.

No es eficiente dedicar el tiempo entre medidas al "muestreo" (polling) del canal debido al elevado consumo que introduciría. Es por esto que se ha decidido que el polling del canal se realizará durante un instante de tiempo cuya duración sea la necesaria para que el tiempo de procesado y respuesta del maestro permita la recepción del paquete. Para advertir al maestro de cuándo podrá realizar el envío de los datos, el polling se realizará tras enviar las medidas el sensor, es decir, el sensor enviará las medidas y dejara un tiempo ajustado para recibir datos.

De este modo, la dinámica de la comunicación consistirá en el envío de las medidas al maestro por parte del sensor; el sensor se mantendrá un tiempo a la escucha, tiempo que el maestro aprovechará para enviar los comandos oportunos al sensor. Una vez el sensor recibe los datos, inmediatamente deja de estar a la escucha, procesa los datos y entra en modo de bajo consumo esperando la medida siguiente. Esto se aprecia en la tabla siguiente.

Mapa de funcionamiento y consumo.
Estado t medida HR t medida Tª envio datos t en el aire t espera recepción espera medida
Micro duerme lee duerme lee envía duerme pon RX duerme
Transceptor duerme carga datos transmite duerme recibe apagado
Sensor mide mide duerme

Esta tabla muestra gráficamente la función de cada dispositivo del sensor en cada estado resaltando las funciones a razón del consumo que suponen. El consumo se muestra en forma de gradiente, siendo el azul el de menor consumo y el rojo más oscuro el de mayor.

Tal y como se aprecia, para reducir el consumo estático del nodo, se ha decidido desconectar el transceptor durante el tiempo entre medidas ya que su consumo estático, en modo reposo 12µA, es elevado en proporción al resto.

Iniciar la conexión inalámbrica:

Se debe permitir la conexión en caliente por lo que el proceso de conexión de un nuevo sensor a la red se muestra a continuación.

El maestro está escuchando (polling) contínuamente por el canal en el que esté trabajando. El sensor se sitúa junto al maestro y se enciende. Una vez encendido, el sensor envía el paquete de "conexión inicial" el cual contiene su dirección y la configuración de su sensor y de su transceptor.

Cuando el maestro recibe dicho paquete, actúa asignando a la dirección recibida, la del sensor, un número de identificación (ID) de menor tamaño que la dirección y posteriormente se la envía al sensor. A partir de ahora la comunicación del sensor con el maestro contendrá la ID que le indicará al maestro quién le está enviando el paquete. En el caso en el que el sensor no reciba respuesta del maestro, cambiará de canal y lo volverá a intentar. Si esto tampoco funcionase, se podría intentar hacer un cambio de potencia y volver a realizar el barrido de canales. Si todo esto falla, el sensor entrará en reposo y lo indicará con su indicador luminoso LED.

Una vez el maestro ha recibido el dato MY_NAME_IS del sensor y le ha respondido, manda la configuración, la dirección y la ID asignada al sensor al PC para ser procesada y mostrada por el software de representación.

Cuando el software de representación recibe los datos del sensor enviados por el maestro, este crea una nueva clase que contiene los paneles que se mostrarán para cada sensor pasándole los datos recibidos al constructor. Esto produce una ventana la cual contiene una gráfica donde se muestran los datos de HR y Tª y una serie de etiquetas y botones que permiten mostrar los datos del sensor y configurar el sensor.

Configurar el sensor:

Una vez establecida la conexión, para configurar el sensor el usuario interactúa mediante el software de representación. El software envía un comando que contiene la ID del sensor a modificar al maestro, el cual almacena en el "buffer FIFO" de la ID el comando a enviar para que el sensor actúe como se ha pedido. El "buffer" consiste en un array donde se van almacenando los comandos que se le quieren enviar a una ID (sensor) determinada; esto es así debido a la naturaleza de la comunicación.

Cuando un dato del sensor es recibido por el maestro, el maestro mira si el buffer correspondiente está vacío, en caso contrario, manda todos los comandos posibles (cada paquete puede contener hasta dos comandos) contenidos en el buffer.

Cuando el sensor recibe el dato, actúa en consecuencia y envía un paquete de respuesta el cual es interpretado por el maestro como cambio realizado correctamente y es comunicado al software de representación.

Una vez el sensor ha contestado, continúa con el funcionamiento normal. Esto supone una modificación del tiempo entre lecturas.