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.

No hay comentarios: