[Proteus versión 8.1]
Ahora que ya hemos visto en la anterior lección la base teórica de la utilización del bus i2c, estamos en condiciones de ver un ejemplo práctico de utilización de un dispositivo i2c para medir temperaturas desde nuestro equipo Arduino. Esta selección tiene un evidente caracter pedagógico. Este dispositivo es configurable por software a través del bus i2c y devuelve el dato de la temperatura medida. Así podremos practicar una secuencia completa de escrituras y lecturas a través del bus i2c.
Nuestra primera tarea consiste en seleccionar el dispositivo i2c más adecuado y comprobar sus características para aprender a utilizarlo en nuestro proyecto. En este caso, deseamos medir temperaturas. Así que vamos a utilizar el termómetro digital de la casa MAXIM (Dallas Semiconductor) referencia DS1621 que tiene un precio inferior a los 6,00€. Podemos encontrar fácilmente la información completa de este dispositivo en internet en la dirección: http://pdfserv.maximintegrated.com/en/ds/DS1621.pdf De todas formas, como internet es un 'animal vivo' donde los enlaces pueden variar con el tiempo, si no estuviera disponible en el momento de leer esta lección, podemos también realizar una búsqueda de este dispositivo con google que nos ayudará a encontrar la información de este dispositivo. Además, este componente tiene una ventaja adicional muy interesante para nosotros. Proteus incluye entre sus librerías un modelo completo de simulación para este elemento que nos permite ir fijando en tiempo real diversas temperaturas con ayuda de unos botones y de esa manera simular su funcionamiento real.
Como se puede observar en la imagen, el modelo nos permite ver en pantalla la temperatura actual y modificarla a nuestro antojo con los botones con las flechas arriba y abajo.
El segundo paso consiste en conectar nuestro dispositivo a nuestro Arduino a través del bus i2c. Para hacerlo, conviene recordar que el bus i2c se compone de dos hilos cada uno de ellos conectado a VCC a través de sendas resistencias de pull-up. El esquema completo de conexionado se muestra a continuación.
Hemos conectado el bus (a la línea del reloj representada por el rótulo SCL y a la línea de datos representada por el rótulo SDA) el dispositivo DS1621, el depurador del bus i2c y nuestro equipo Arduino. Observe que para conectar el Arduino al bus hemos unido el terminal AD5 a la línea SCL y el AD4 a la línea SDA. Además, hemos conectado un terminal virtual a los terminales TXD y RXD para poder enviar datos a la consola durante la ejecución de nuestro programa. En otro lugar de nuestro esquema el terminal TXD está unido al pin IO1 de nuestro arduino y el terminal RXD al pin IO0. Este es el mismo procedimiento que hemos utilizado en lecciones anteriores para usar el terminal virtual. De todas formas, a continuación, mostraremos el esquema completo para que no existan dudas.
Una vez realizadas las conexiones del hardware, tenemos que direccionar correctamente nuestro termómetro digital. El DS1621 se direcciona de la siguiente manera (se puede consultar sus datos para comprobarlo). Como todo dispositivo i2c, utiliza siete bits para fijar su dirección. Los cuatro primeros bits adoptan siempre el valor fijo 1001. Los tres útlimos bits se confguran utilizando los pines A0, A1 y A2. Si el pin está conectado a VCC tomará el valor 1 y si está conectado a GND el valor 0. Por lo tanto la dirección del dispositivo será la siguiente: 1 0 0 1 A2 A1 A0. En nuestro caso el proyecto sólo utiliza un dispositivo DS1621, así que hemos conectado los tres pines a GND y la dirección resultante es: 1001000 (0x48 en hexadecimal y 72 en decimal).
Ya podemos escribir nuestro primer programa.
Lo hemos hecho expresamente corto, para ir siguiendo paso a paso todo el proceso y poder desgranarlo y comprenderlo perfectamente. El programa contiene una sentencia include para enlazar con la librería de Arduino que nos ayuda a gestionar el uso del bus i2c. Luego declaramos tres variables, una para almacenar el valor de la temperatura en grados centígrados, otra para guardarla en grados Farenheit y una tercera con la dirección de nuestro dispositivo i2c (acabamos de ver que su dirección es 0x48 en hexadecimal).
En la sección de configuración, inicializamos el puerto serie donde conectamos nuestro terminal virtual para usarlo a una velocidad de 9600 baudios. Inicializamos también el bus i2c con la función wire.begin() de la librería wire.h.
A continuación hacemos una cosa extraña, pero que la llevamos a cabo para que el lector pueda ver el uso del depurador del bus i2c paso a paso. Sólo utilizamos las funciones beginTransmission() y endTransmission(). A la primera le pasamos como parámetro la dirección de nuestro termómetro digital. Con esto logramos enviar un único telegrama a través de nuestro bus i2c. Un telegrama que básicamente es una orden de direccionamiento del maestro y que debe ser contestada por nuestro esclavo con un bit de reconocimiento (ACK).
Ejecutemos la simulación y obtendremos lo siguiente:
Cómo espérabamos en nuestro depurador se puede observar el único telegrama que hemos puesto en el bus: S 90 A P. Es decir, un bit de arranque (S). El byte de valor 0x90 que se corresponde con la dirección de nuestro dispositivo (0x48 = 100 1000) más un bit 0 a su derecha que indica que el telegrama es para escribir (1001 0000 = 0x90). Un bit de reconocimiento del esclavo (A). Y, por último, un bit de parada (P).
Con esto hemos comprobado que todo funciona bien y que nuestro esclavo está direccionado según nosotros creemos.
Cambiemos nuestro programa y sustituyamos el valor de la variable dirección por 0x49. Compilemos y arranquemos la simulación. Nuestro depurador del bus i2c mostrará el siguiente telegrama.
Se puede ver que el bit de reconocimiento (A) se ha sustituido por un bit de no reconocimiento (N). Eso significa que hemos mandado un telegrama por el bus dirigido a un dispositivo con una dirección que nadie reconoce. De esta manera tenemos una forma sencilla de comprobar que el direccionamiento de los dispositivos que hemos puesto en nuestro proyecto se corresponde con el que nosotros esperábamos. Volvamos a dejar nuestro programa con la dirección correcta.
Nuestro termómetro digital es susceptible, como ya dijimos, de ser configurado a través del bus i2c. Esto se logra mediante la escritura de una serie de comandos (se puede ver la lista completa de los comandos disponibles en la documentación del dispositivo). En nuestro caso nos interesa programar nuestro DS1621 para que esté realizando de forma continua lecturas de temperatura. Para hacerlo modificaremos nuestra función de configuración de la siguiente manera.
Como es nuestra costumbre, añadimos unos comentarios para entender cada uno de los pasos que estamos dando. El comando 0xAC le indica al DS1621 que deseamos escribir en su configuración y el byte que enviamos a continuación es el valor de configuración que deseamos escribir. En este caso 0x02 siginifica que deseamos que el dispositivo esté leyendo las temperaturas de forma continuada.
A continuación volvemos a utilizar la función beginTransmission() para hacer un inicio reiterado y poder mandar un segundo comando. En este caso el comando es el 0xEE que ordena a nuestro dispositivo que comience con las lecturas de temperaturas. Por último finalizamos el telegrama.
Si compilamos y ejecutamos la simulación, el resultado debe ser.
A estas alturas ya tenemos que ser capaces de reconocer perfectamente lo que aparece en el depurador i2c.
Todavía no estamos leyendo datos a través del bus. Sólo hemos escrito la configuración. Nuestro siguiente paso, será recibir las lecturas de temperatura y mostrarlas en el terminal virtual. Para ello modificaremos la función del bucle continuo de nuestro arduino.
En este caso enviamos un nuevo telegrama de escritura en el esclavo para enviar el comando que fuerza la lectura de la temperatura. Para ello utilizamos la funciones beginTransmission, write y endTransmission de la librería wire.
A continuación mandamos un nuevo telegrama para que el esclavo nos devuelva el valor de temperatura leído. Lo llevamos a cabo con la funcion requestFrom. El resultado de la lectura recogido por la funcion read, lo guardamos en la variable tempC. Para obtener el valor en grados Faranheit, utilizamos una sencilla fórmula matématica y el resultado lo guardamos en la variable tempF.
El resto del programa es para enviar los resultados por el puerto serie hacia el terminal virtual.
Si compilamos y arrancamos la simulación podremos ver en el terminal virtual las temperaturas léidas. Podemos cambiar la temperatura a leer con los botones de subir y bajar del dispositivo DS1621.
También podemos observar en el depurador del bus i2c, los diferentes telegramas que se envían.
El primero es el que se utiliza para escribir la configuración. Los otros van en parejas. Uno es de escritura (por eso la dirección es 0x90 para que el último bit sea 0) y el otro el de lectura (la dirección es 0x91 porque el último bit es 1).
El valor leído dependerá de lo que hayamos introducido en nuestro dispositivo DS1621 con los botones. En nuestro caso se corresponde con una lectura de temperatura de 18ºC (0x12 en hexadecimal es 18 en decimal).
Nuestro programa tiene un defecto. Si seleccionamos una lectura negativa (grados bajo cero) observar que lectura recibimos. Os dejamos como tarea para investigar, la solución de este problema.
Además os invitamos a un nuevo reto. El DS1621 puede activar su pin 3 (TOUT) cuando la temperatura se encuentra entre un determinado rango de valores configurables. Esta función se llama termostato en contraposición a la función termómetro que hemos utilizado nosotros en este ejemplo. ¿Se anima el lector a intentar poner en marcha esta función para comprobar sus conocimientos sobre el dispositivo y la utilización del bus i2c?
El curso se vuelve un poco más interactivo para hacerlo más interesante. Los que tengan la solución a nuestros dos problemas, las pueden compartir en nuestra página de facebook:
https://www.facebook.com/pages/Hubor-Proteus/294446180592964?ref=hl