Sensor de Temperatura y programa final con la Raspberry Pi:

MANEJO SENSOR TC74:

El sensor tiene un encapsulado tipo TO220:

sensor

Con los pines correspondiente a la comunicación I2C:

  • SDA: datos
  • SCL: reloj
  • GND: tierra
  • VDD: alimentación (3,3 V)
  • NC: No conectado

Comunicación I2C:

El bus I2C, es un estándar que facilita la comunicación entre microcontroladores, memorias y otros dispositivos con cierto nivel de “inteligencia”, que requiere de dos líneas, una de señal y otra de masa.

La metodología de comunicación de datos del bus I2C es en serie y síncrona. Una de las señales del bus marca el tiempo (pulsos de reloj) y la otra se utiliza para intercambiar datos.

Descripción de las señales

    • SCL (System Clock) es la línea de los pulsos de reloj que sincronizan el sistema.
    • SDA (System Data) es la línea por la que se mueven los datos entre los dispositivos.
    • GND (Masa) común de la interconexión entre todos los dispositivos “enganchados” al bus.

Las líneas SDA y SCL son del tipo Open Drain, es decir, un estado similar al de colector abierto, pero asociadas a un transistor de efecto de campo (o FET). Se deben polarizar en estado alto (conectando a la alimentación por medio de resistencias de “pull-up”) lo que permite conectar en paralelo múltiples entradas y salidas.

Protocolo de comunicación del bus I2C:

Habiendo varios dispositivos conectados al bus, es lógico que para establecer una comunicación a través de él se deba respetar un protocolo. Para ello clasificamos los dispositivos conectados al bus en dos tipos:

  • maestros
  • esclavos

Sólo los dispositivos maestros pueden iniciar una comunicación.

La condición inicial, de bus libre, es cuando ambas señales están en estado lógico alto. En este estado cualquier dispositivo maestro puede ocuparlo, estableciendo la condición de inicio (start). Esta condición se presenta cuando un dispositivo maestro pone en estado bajo la línea de datos (SDA), pero dejando en alto la línea de reloj (SCL).

El primer byte que se transmite luego de la condición de inicio contiene siete bits que componen la dirección del dispositivo que se desea seleccionar, y un octavo bit que corresponde a la operación que se quiere realizar con él (lectura o escritura).

I2C

Si el bit de lectura/escritura (R/W) se pone a nivel lógico bajo (escritura), el dispositivo maestro envía datos al dispositivo esclavo. Esto se mantiene mientras continúe recibiendo señales de reconocimiento (ACK), y la conexión concluye cuando se hayan transmitido todos los datos.

El dispositivo maestro puede dejar libre el bus generando una condición de parada (stop).

Configurar Buildroot para poder usar la comunicación I2C:

Para poder usar conexiones I2C, el sistema embebido debe tenerlo activado, y tener las librerías o herramientas necesarias para manejarlo, por tanto, rehacemos la configuración del Buildroot que hicimos, y le indicamos en la parte de Hardware Handling, que nos añada la librería de i2c-tools, como aparece en la siguiente imagen:

Buildroot

Y guardamos los cambios, a continuación escribimos el comando make linux-menuconfig y habilitamos lo relativo a los drivers y al bus de comunicación I2C, como aparece en la  siguiente imagen:

linux kernel

Una vez hechos los cambios anteriores, volvemos a escribir el comando make, para que se queden aplicados.

configtxt

Ya tenemos listo todo lo relacionado con el i2c y el sensor, por lo que lo conectamos, y comprobamos con los siguientes comandos que recibimos la temperatura medida correctamente:

Primero escribimos el comando i2cdetect –l

Y nos lista todos los dispositivos i2c conectados.

En nuestro caso el que nos interesa es el i2c-1

(Ese 1 puesto que por defecto en la versión B de la Raspberry Pi es el que se le asigna), y si todo ha ido bien debemos recibir una respuesta como la siguiente:

i2cdetect

Donde el 0x4d representa la dirección de nuestro dispositivo i2c, la que se le asigna a  nuestro sensor, y el 1 mencionado anteriormente corresponde al busI2C a utilizar.

Ahora que sabemos dicha dirección mandamos el comando 0x00 a nuestro sensor, que es el que le indica que haga una lectura.

Comando: i2cset 1 0x4d 0x00

i2cget

Tras confirmar con una Y la pregunta que se nos formula, sobre si queremos escribir en el fichero /dev/i2c-1,  escribimos el siguiente comando: i2cget 1 0x4d
que nos devuelve la temperatura medida por el sensor en grados C, volvemos a confirmar con Y a la pregunta de si queremos leer del fichero /dev/i2c-1sobre el que escribe el sensor.

i2cset

Ahora pasamos a hacer esta misma función de leer la temperatura pero con un programa en C realizado desde Eclipse y compilado de manera cruzada para poder ejecutarlo en la Raspberry Pi.

En el programa además en el main añadimos un while(1) para que se esté ejecutando continuamente y cada vez que se lea una medida, el proceso se duerma (sleep(1)) durante los segundos que queramos, en este caso 1, y tras despertarse vuelva a realizar otra medida.

A continuación os dejamos el código fuente del programa:

test1

test2

PONER EN HORA LA RASPBERRY PI:

Para configurar correctamente la hora de la Raspberry Pi, una vez que la tenemos conectada con el ordenador, escribimos en un terminal el siguiente comando:

date –help

Y nos aparecerán las distintas opciones que tiene el comando date:

hora1

Por tanto vemos que utilizando el comando date –s seguido de la fecha y hora que queremos pasarle a la Raspberry Pi en el formato YYYY.MM.DD-hh:mm, conseguimos darle la hora y fecha correctas:

hora2

INTEGRACIÓN DEL SENSOR I2C CON LA PANTALLA TÁCTIL EN LA RPI:

Usando de nuevo el programa de Workshop4 de 4DSystems hacemos dos interfaces para la pantalla, a estas interfaces se les llama Form0 y Form1. Para ello en la barra de objetos seleccionamos la opción indicada:

workshop1

En la pantalla Form0 añadimos los objetos:

  • Angularmeter0: Se utiliza para mostrar la temperatura medida en el sensor. Para ello la RPI lee la temperatura del sensor y se lo envía al Angularmeter.
  • Leddigits0: Muestra el umbral de temperatura seleccionado con el Knob0, y envía este umbral a la RPI. Para ello tenemos que configurar el evento a “Report Message”.
  • workshop2
  • Userled0: Se ilumina cuando la temperature medida supere el umbral seleccionado.
  • Knob0: Es el dial utilizado para seleccionar el umbral y lo envía al Leddigits0 para que lo muestre. Para ello hay que configurar el evento para que cuando cambie su valor, envíe dicho valor al objeto Leddigits0.
  • workshop3
  • 4DButton0: Con este botón se cambia a la otra pantalla. Para ello se configura el evento de la siguiente forma:

workshop4

  • Statictext0: Se utiliza para dar nombre al indicador Userled0.

workshop5

Para la pantalla Form1 se añaden los siguientes objetos:

  • Leddigits1: Muestra la hora y los minutos que le envía la RPI.
  • Leddigits2: Muestra los segundos que recibe de la RPI.
  • Strings0: Muestra en formato texto la temperatura medida del sensor.
  • 4DButton1: Cambia a la pantalla Form0. Para ello se configura el evento de la siguiente forma:

workshop6

workshop7

Con esto se termina de programar la pantalla, ahora vamos con el programa en C, que se ejecutará en el sistema embebido de la RPI.

app_sensor1

app_sensor2

app_sensor3

app_sensor4

app_sensor5

En el programa en C, añadimos entre otras, la librería correspondiente a la pantalla, y una librería que nos permita manejar y crear hilos (threads):

app_sensor6

A continuación definimos las siguientes variables globales:

  • Temperatura, de tipo entero que almacenará el dato recibido del sensor TC74
  • umbral: de tipo entero también, almacenará el valor recibido del dial manejado desde la pantalla táctil. Si la temperatura medida es mayor a este umbral, saltará la alarma.
  • t: es una estructura de tipo time_t, estructura ya definida en time.h y que almacena los valores de tiempo del sistema, estos valores se devuelven desde la función time().
  • msgtemp[50]: Es un array de tipo de char de 50 elementos, que nos permite almacenar la variable temperatura (que era un entero) en una cadena de char, para poder mostrarla en formato texto por la pantalla táctil
  • timestr: es un puntero a un char que nos permite llamando a la función ctime() convertir a una cadena de caracteres los datos temporales vistos antes, y así mostrarlos por los objetos leddigits de la pantalla.

Una vez definidas las variables globales, y añadidas las cabeceras necesarias al programa, declaramos varias funciones:

  • void get_temp_sensor(void):

Nos permite actualizar la temperatura medida del sensor, y guardar el resultado en la variable temperatura, para ello, necesitamos saber la dirección i2c donde está conectado el sensor, (en nuestro caso la 0x4d, como ya se explicó y demostró en puntos anteriores de este documento).

Además necesitamos acceder al fichero /dev/i2c-1, como también se explicó anteriormente, puesto que es donde escribe el sensor, y por tanto de donde obtenemos la medida de temperatura. Por tanto en esta función abriremos el archivo, y gestionaremos los errores que puedan producirse en este paso:

app_sensor7

Y a continuación leemos del fichero el dato que nos interesa y convirtiéndolo a un entero, lo almacenamos en la variable temperatura, mientras no se produzcan errores al leer del bus i2c:

app_sensor8

Después escribimos el comando 0x00 en el buffer que mandamos por el bus i2c. Este comando es el que le manda al sensor i2c que realice una medida:

app_sensor9

  • static void *handleAngularMeter(void *data):

Es la función del controlador del angularMeter de la pantalla

touchscreen1

La primera línea de esta función es un for(;;), es decir un bucle infinito, para que esté funcionando continuamente, pero para que no consuma todos los recursos de la cpu, dormimos durante medio segundo a dicha función con un usleep(500000), que aparece al final de esta función.

En cuanto a las acciones principales de esta función, llama a la función anterior get_temp_sensor(), para obtener la temperatura, y mediante la función genieWriteObj (…) que proporciona la cabecera geniePi.h, conseguimos representar en el angularMeter de la pantalla, la temperatura pasándole a dicha función como argumentos, el objeto sobre el que queremos escribir, en nuestro caso GENIE_OBJ_ANGULAR_METER, el índice de dicho objeto, para nosotros 0x00, pues solo tenemos un angularMeter, y el dato que queremos representar, en nuestro caso la variable temperatura.

touchscreen2

Después comprobamos si la temperatura medida ha superado el umbral, pues en caso afirmativo, actualizamos también de la misma manera, es decir con la función genieWriteObj y los argumentos correspondientes, el led de la alarma, o en caso de que estuviera encendida, y ya estemos por debajo del umbral, apagamos la alarma:

touchscreen3

Ahora pasamos la temperatura a formato texto, para escribirla en el objeto Strings0 de la segunda pantalla, para ello usaremos la función genieWriteStr(…), y como argumentos le pasamos el índice de dicho string, en nuestro caso el 0x00, y el texto a mostrar en nuestro caso la cadena msgtemp ya comentada antes, y dormimos la función durante medio segundo:

touchscreen4

  • static void *handleTime(void *data):

La siguiente función es el controlador del reloj, que comienza y termina de la misma manera que la anterior, porque también necesitamos que esté funcionando continuamente (for(;;)) pero que acaparé todos los recursos de la cpu, por lo que tenemos que dormirla (usleep(500000)) una vez que actualicemos lo que nos interese.

Para obtener la hora del sistema, utilizamos la funcion localtime(), y para pasarla a formato texto, la función ctime(), que nos almacena la fecha actualizada en la cadena de caracteres timestr con el siguiente formato:

touchscreen5

Donde www corresponde a las primeras letras en inglés del día de la semana correspondiente, mmm, son las primeras letras en inglés del mes correspondiente, dd es el día del mes, así como hh es la hora en formato 24 horas, mm, los minutos, ss los segundos, y yyyy el año correspondiente.

Por tanto, y teniendo en cuenta que el índice de los arrays empieza en 0, accediendo a las posiciones 11 y 12, de timestr, obtenemos las dos cifras de la hora, y con las posiciones 14 y 15 las de los minutos.

Sin embargo, y puesto que necesitamos que dichos caracteres ASCII se visualicen como números decimales en los dígitos, le restamos 48 a cada uno de los caracteres, como el número de posiciones entre el símbolo ASCII correspondiente, y el valor decimal con el que coincide.

ascii

Después tenemos que multiplicar la cifra de las decenas de la hora, por 1000 puesto que tenemos que desplazarla tantas posiciones como 0´s de ese 1000 a lo largo de las cifras de los dígitos de los leds, y así sucesivamente con el resto de cifras.

codigo1

Lo mismo ocurre con los segundos, solo que ahora es sobre el objeto leddigits2 sobre el que debemos escribirlos y no sobre el 1.

codigo2

  • void handleGenieEvents(struct genieReplyStruct * reply):

Es la función encargada de controlar los eventos que se producen en los demás objetos de la pantalla, por tanto tiene que estar continuamente comprobando si se ha reportado algún evento, y si es así debe comprobar si el evento ha sido que se ha girado el dial que seleccionaba la temperatura umbral, es decir, comprueba si ha sido el objeto Knob0 el que ha generado el evento, y si es así guarda el dato reportado en la variable umbral.

En caso de que se produzca un error, informa de ello.

codigo3

  • main():

Es la función principal del programa, donde declaramos la estructura reportada en la función anterior, así como creamos los dos hilos que manejarán el controlador del AngularMeter, y el del reloj, por lo que irán asociados con las correspondientes funciones de handleAngularMeter, y handleTime, respectivamente y de manera que parezca que el programa funciona de forma concurrente, es decir “simultáneamente” para el usuario.

A continuación y una vez arrancado el programa informa por el monitor de que el programa está funcionando y que se pulse Ctrl + C para salir.

Después configura la velocidad de transmisión con la pantalla, dándole un baudrate de 115200, que debe coincidir por tanto con el que indicásemos al configurar la pantalla con el programa workshop4DSystems.

codigo4

Por último y de manera continua, chequea si se producen eventos en los distintos objetos de la pantalla,  en cuyo caso llama a la función handleGenieEvent() que los gestiona, y se duerme durante 10 ms.

codigo5

Con esto acaba el programa, una vez que lo compilamos de manera cruzada para la arquitectura arm correspondiente a la Raspberry Pi, ya explicado en puntos anteriores de este documento, copiamos los ficheros del proyecto a la tarjeta SD que introduciremos en la Raspberry Pi, y desde la que con el comando ./ seguido del nombre de nuestro ejecutable del programa conseguiremos arrancarlo, y obtener el programa funcionando como aparece en las siguientes imagenes:

running

final

final2

Bibliografía:

http://es.wikipedia.org/wiki/Sistema_embebido

http://es.wikipedia.org/wiki/I%C2%B2C

http://www.4dsystems.com.au/product/4D_Workshop_4_IDE/

http://www.raspberrypi.org/quick-start-guide

http://www.raspberrypi.org/faqs

http://www.raspberrypi.org/

Datasheet sensor:

http://ww1.microchip.com/downloads/en/DeviceDoc/21462D.pdf

Comunicación I2C:

http://elinux.org/Interfacing_with_I2C_Devices

http://robots-argentina.com.ar/Comunicacion_busI2C.htm

Programa final:

http://es.wikipedia.org/wiki/Time_t

http://www.cplusplus.com/reference/ctime/tm/

http://www.cplusplus.com/reference/ctime/ctime/

Anuncios

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 )

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 )

Google+ photo

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

Conectando a %s