Sensor de color TCS3472 con conexión I2C

publicado en: Portada | 2

El TCS3472, de la compañía AMS, es un sensor de color formado por una matriz de 4×3 fotodiodos nueve de los cuales están dotados de filtros de color capaces de detectar la luz que incide en ellos separándola conforme a un modelo de color RGB y la iluminación sin filtrar en el caso de los tres restantes.

TCS3472 color sensor I2C módulo Arduino IC detalleTCS3472 color sensor I2C módulo Arduino detalle RGB

Su funcionamiento es similar en muchos aspectos al funcionamiento de la familia de sensores de color TCS330 y TCS341 por lo que puede tomarse como referencia lo que se explicó en el artículo sobre el sensor de color I2C TCS3414. Aunque el TCS3472 tiene una matriz de 12 fotodiodos es un dispositivo más avanzado que el TCS3414 con una matriz de 16 fotodiodos, por ejemplo, el margen dinámico del TCS3414 es de 1M:1 mientras que el del TCS3472 es de 3,8M:1, casi cuatro veces mayor. Por lo demás, comparten una resolución de 16 bits por canal, un bus I2C rápido, generación de una señal de interrupción o protección contra interferencias eléctricas y parpadeo de la iluminación. A diferencia del TCS3414, el TCS3472 no tiene entrada de señal SYNC.

esquema sensor color I2C TCS3472 pinout diagramasensor color I2C TCS3472 respuesta normalizada comparativa sensibilidad humana colores

Aunque con un rango dinámico mayor, la sensibilidad relativa al color del TCS3472 en función de la longitud de onda es similar a la del TCS3414: en general situada en la zona del espectro visible por el ojo humano, poco sensible a la luz ultravioleta y casi no detectan luz infrarroja gracias a un filtro que la atenúa y que, en realidad empieza en la parte visible, entorno a los 650 nm, como puede verse en la imagen anterior. Especialmente en el color rojo, la distribución de la sensibilidad no es totalmente proporcional a la humana; por eso y por la importante influencia de la iluminación con la que se realiza la medida será necesario realizar una especie de calibrado en el que se establezcan las condiciones iniciales de medida para establecer una posible corrección de los valores obtenidos.

Muchos de los módulos que existen en el mercado con los que realizar pruebas disponen de iluminación LED que se puede controlar desde del MCU, activándola o determinando su intensidad con PWM. En el segundo caso es importante sincronizar con los tiempos de medida ya que la protección contra parpadeos del TCS3472 está pensado para corregir la fluctuación de la corriente alterna y un pulso arbitrario podría falsear la medida de la iluminación en función de su distribución.

TCS3472 color sensor I2C módulo Arduino

Aunque la iluminación LED de los módulos es muy práctica para las pruebas, es importante realizar el calibrado en las condiciones de lumínicas del montaje definitivo tanto en temperatura de color (longitud de onda) como en intensidad o disponer mandos hardware o software para poder calibrar in situ y en tiempo de ejecución el dispositivo.

La integración del TCS3472 en un circuito es muy sencilla, casi no necesita otros componentes. En caso de que existan importantes interferencias se puede disponer el clásico filtro de 10 µF y 100 nF en la alimentación, aunque normalmente no es necesario ya que, como se ha dicho, el TCS3472 incluye una protección interna. El bus I2C y la señal de interrupción necesitan sus correspondientes resistencias pull-up de, por ejemplo, 10 KΩ.

Actualmente, los sensores de la familia TCS3472 se fabrican en dos versiones: los TCS34725, que se alimentan a 3V3 y los TCS34727, que se alimentan a 1V8. Para simplificar su conexión a la mayoría de los microcontroladores, los módulos que lo integran, como el de la foto de arriba, incluyen regulación de tensión para poder conectarlos directamente también a 5 V. El antiguo TCS34721 corresponde con el actual TCS34725 y el TCS34723 con el TCS34727.

sensor color I2C TCS3472 circuito de aplicación

Software para controlar el TCS3472 por I2C

Utilizar el TCS3472 es muy sencillo, basta con acceder a sus registros, usando el bus I2C, para almacenar la configuración conforme a la que se desea que funcione o para leer los valores de color medidos. Aunque en diferentes direcciones, la configuración de los registros es similar a la de los sensores de color I2C de la familia TCS34 que se puede tomar como referencia.

Para repasar la forma de acceder al TCS3472 por medio del bus I2C desde Arduino tomemos como ejemplo el siguiente código que lee el identificador que se encuentra en la dirección 0x12.

Como puede verse en las directivas #define del principio del código anterior, el TCS3472 (un TCS34725 en mi caso) se encuentra en la dirección I2C 0x29. El registro de configuración está en la dirección 0x12 y devuelve uno de dos valores: 0x44 para el TCS34721 y el TCS34725 o 0x4D para el TCS34723 y el TCS34727.

El «registro» de operación (que no tiene dirección) tiene el bit más significativo a nivel alto para indicar que se trata de una orden. Para que sea más sencillo leerlo, se hace una operación OR con la orden que se solicita al TCS3472 y el valor del «registro» de operación, que en este caso solo usa el bit número 7.

Como he conectado un TCS34725 al bus I2C de un Arduino Leonardo, la salida que muestra en la consola serie el programa anterior corresponde con la captura de pantalla de abajo.

TCS3472 Lectura identificador dirección 0x29

El procedimiento para acceder al TCS3472 es el habitual cuando se usa el bus I2C:

  1. Incluir la librería en el código con #include <Wire.h>
  2. Inicializar la librería con Wire.begin();
  3. Acceder al TCS3472 pasando la dirección 0x29 a Wire.beginTransmission
  4. Enviar los códigos de operación con Wire.write
  5. Si se van a leer datos desde el TCS3472 se usa Wire.requestFrom pasando como primer argumento la dirección del dispositivo y como segundo el número de bytes
  6. Si se esperan datos, Wire.available() informa de los que hay disponibles
  7. Los datos se leen con Wire.read()
  8. Aunque no sea imprescindible, es una buena práctica liberar el bus con Wire.endTransmission(); y vaciar la cola de datos cuando termine una operación. Después habrá que restablecer las comunicaciones con Wire.beginTransmission. De esta forma se puede acceder a otros dispositivos que usen el mismo bus I2C. En el código anterior se podrían haber eliminado las líneas 17 y 18 pero se han incluido como ejemplo para ilustrar esta recomendación.

El dato del identificador (un byte) se ha leído directamente con Wire.read() después de solicitarlo con Wire.requestFrom. Esta fórmula seguramente funcione sin problemas en buena parte de las ocasiones pero lo más correcto es esperar, consultando con Wire.available(), a que estén disponibles los datos que se han solicitado. Para evitar que un error produzca una espera infinita debe imponerse también un tiempo de espera (timeout) máximo.

En el código anterior se han resaltado las líneas con las que se implementa la espera de datos desde el bus I2C. En la línea 8 se define una constante para la espera máxima, en la 12 un cronómetro para calcular, usando millis() en la 24, el tiempo que ha transcurrido y en la línea 25 se detiene el programa hasta que llegue el byte que se esperan. Para verificar que se ha salido del bucle de espera porque han llegado los datos, en la línea 26 se vuelven a comprobar y se muestra el resultado o un mensaje de error entre las líneas 43 a 46 según la cantidad de datos sea correcta o no.

La otra alternativa es iniciar la solicitud de datos con Wire.requestFrom() y realizar la lectura a la llegada de la información con una función que se habrá configurado con Wire.onReceive(). Es este caso, para no encerrar en la interrupción el código, lo aconsejable es utilizar una variable indicador que se active a la llegada de datos; cuando esta variable esté activada el programa leerá los datos.

Medida básica de color con el sensor TCS3472

La forma más sencilla, y más usada, de obtener el color con el sensor TCS3472 consiste, simplemente, en configurar el dispositivo y leer las dos direcciones de los dos registros que almacenan cada canal. La forma de hacerlo es muy parecida a lo que se explicó en el artículo sobre el sensor de color I2C TCS3432 que puede tomarse como referencia.

La preparación mínima antes de realizar la lectura debe incluir la activación del dispositivo y la activación de la conversión analógica-digital. En principio, después de solicitar la lectura de los registros de color, hay que esperar el tiempo de integración que corresponda aunque, en función de cómo sea el programa que realiza la lectura, es muy probable que ese tiempo quede incluido en otras operaciones y podrá sustituirse por una verificación de que ha transcurrido o un cálculo para asegurarse de que la parte del código que se ejecuta en la circunstancia más favorable incluye al menos el tiempo de integración.

Para simplificar la lectura, el siguiente código para Arduino omite la configuración y usa un valor de integración muy alto. Cuando el programa que rige el microcontrolador se limita a leer el sensor es admisible usar delay para forzar la espera pero si hay otras tareas que ejecutar lo correcto será verificar que el tiempo de integración ha transcurrido en lugar de detener el programa. En la mayoría de los casos el programa estará funcionando hasta que un evento (la muestra ha llegado de forma estable al sensor) indique que debe empezar la lectura y si hay intervención humana, debe implementarse algún tipo de aviso (como un sonido o un indicador luminoso) para avisar de que se ha terminado la lectura o proceder, quizá solamente esperar, con la siguiente lectura.

En la línea 25 del código anterior se activa el dispositivo y la integración enviando como código el resultado de una operación OR de los bis de ambas operaciones. Como se vio en el primer ejemplo, para enviar una orden al TCS3472 hay que usar el registro correspondiente con el bit del modo operación activo, como en la línea 24 del ejemplo.

En la línea 36 del código anterior se solicita al TCS3472 el valor de un canal. Como los canales están ordenados, solamente es necesario conocer la dirección del primero y bastará con ir incrementándola en dos bytes (cada color se expresa como un valor de 16  bits)

Antes de solicitar los dos bytes del valor del canal en la línea 40, se debe esperar (línea 38) el tiempo que se haya configurado para la integración. Para calcular el valor del color con los dos bytes de cada canal basta con rotar el del segundo byte (el más significativo) los 8 bits que corresponden a su posición en el entero sin signo, como puede verse en las líneas 45 y 46 del código de arriba.

Configuración del sensor TCS3472

Del sensor de color TCS3472, dicho a grandes rasgos, los parámetros que se pueden configurar son la ganancia, el tiempo de integración y los valores de interrupción. Para aclarar un poco más estos conceptos y no alargar demasiado este texto, se puede consultar, como he recomendado antes, el artículo sobre la familia de sensores de color I2C TCS340 y TCS341, que puede servir como referencia al ser su funcionamiento muy parecido al del TCS3472.

Para configurar la ganancia se utilizan los dos bits menos significativos del registro de control, que se encuentra en la dirección 0x0F del TCS3472. Los cuatro posibles multiplicadores para la ganancia que se pueden elegir son 1, 4, 16 y 60 que corresponden, por ese orden, con los cuatro valores que los dos bits pueden representar.

Como es lógico, para elegir la ganancia adecuada habrá que conocer el contexto en el que se realiza la medida, para lo que será necesario realizar pruebas (una especie de calibración) con la iluminación y los patrones de color máximo y mínimo que se muestrean, añadiendo, además, unos márgenes de seguridad en los valores para no recortar los más extremos. Con esa misma «calibración» se podrán establecer coeficientes para corregir posibles errores producidos, principalmente, por el color de la iluminación.

El registro para configurar el tiempo de integración se encuentra en la dirección 0x01 y se establece determinando los ciclos de integración a intervalos de 2,4 ms. El valor que se almacena en el registro se resta de 256 y se multiplica por 2,4. Por ejemplo, si se almacena 246 el tiempo resultante sería 256-246=10 ciclos de integración que, multiplicados por 2,4 ms resultan 24 ms.

El TCS3472 puede generar una interrupción para avisar de dos tipos de eventos: que la lectura de la iluminación se sale de un rango máximo y mínimo o que el ciclo de lectura ha terminado. Esta segunda opción permite muestrear el valor solamente cuando la integración haya terminado y evita que el programa tenga que esperar deteniéndose.

Para configurar la interrupción se utiliza el registro de activación, en la dirección 0x00, cuyo bit número uno controla la generación de una interrupción al concluir la conversión analógica-digital y el registro de persistencia, en la dirección 0x0C. El segundo registro, cuando vale cero, utiliza la interrupción para avisar del fin de la integración o para establecer el número de veces que debe rebasarse el rango de iluminación. Los valores máximos y mínimos del umbral de iluminación se almacena en los registros que hay en las direcciones 0x04-0x05 y 0x06-0x07.

Lectura del sensor de color TCS3472 usando las interrupciones

La función del programa que se llama cuando se genera la interrupción debe contener el mínimo de código necesario para realizar la lectura por lo que lo habitual, como decía al principio, es cambiar el estado de una variable indicador de estado (flag) y ceder a alguna parte del bucle principal la gestión (por supuesto, a su vez, podrá delegarla a otras funciones).

Es importante desactivar las interrupciones mientras se realiza la lectura o, en general, hasta que el programa esté listo para gestionar la siguiente interrupción. Por claridad y para ilustrar la forma habitual de hacerlo, en el siguiente código de ejemplo se utiliza el método genérico, detachInterrupt(), aunque no es imprescindible, ya el sensor de color TCS3472 no generará una nueva interrupción. Para que se vuelvan a generar interrupciones habrá que borrar la actual usando el registro de comando con los bits de tipo (5 y 6) y los de modo de borrado (1 y 2) activos.

En la primera parte del código del ejemplo anterior se definen las direcciones de los registros y de las configuraciones de los bits correspondientes. De esta forma es más sencillo comprender la finalidad de cada operación que se realiza con ellos.

Después de dar nombre a los registros y a los bits de sus distintas configuraciones, se carga la librería Wire de Arduino con la que se gestionan las comunicaciones I2C con el sensor de color TCS3472.

Entre las líneas 24 y 30 se declaran y, en su caso, se inicializan las variables. Respecto del código del apartado anterior, en este ejemplo se ha añadido una variable que almacena el número de interrupción calculado a partir del pin al que se conecta. Otra diferencia de este programa es el cronómetro que se utiliza para monitorizar (solo para verificar) cuánto tarda en realizarse la integración.

En el bloque setup() se activa el dispositivo y la integración y posteriormente la interrupción. Para asegurar que la segunda operación se realiza cuando la primera se ha concluido se espera un intervalo arbitrario. En principio bastaría con un ciclo de 2,4 ms pero, como se ejecuta solo una vez y por seguridad, se usa un valor sobradamente alto (50 ms). Aunque solamente es imprescindible esperar a esa operación, se ha añadido una espera a cada cambio de configuración ya que supone poco retraso y se produce una única vez en el programa y da seguridad de que el cambio de configuración ha tenido efecto.

También en el bloque setup(), se ha configurado el tiempo de integración más alto posible para que se pueda apreciar en las medidas, que se toman en milisegundos, y así verificar que está funcionando en el rango previsto. Como ejemplo, también se ha configurado un valor para la ganancia de 4X que sirve para ver que el valor incrementa sensiblemente.

La principal diferencia que se ha introducido en el bloque loop() es realizar la lectura solo si la interrupción ha activado el indicador lectura_disponible. Como se decía al principio, mientras se procesa la lectura se desactiva la interrupción con detachInterrupt() (aunque no sea necesario en este caso) y se vuelve a establecer al terminar la lectura. Para reiniciar las interrupciones del TCS3472, y esto sí es imprescindible, se restablece el registro de persistencia en la dirección 0x0C como explicaba en el apartado anterior.

Salida de la consola de la lectura de color con interrupción del TCS3472 y configuración de ganancia y tiempo de integración

Víctor Ventura

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

Más entradas - Página web

Sígueme:
TwitterLinkedIn

Seguir Víctor Ventura:

Programador multimedia y web + IoT. Mejor con software libre.

Desarrollando aplicaciones para la web conocí el potencial de internet de las cosas, encontré la excusa perfecta para satisfacer la inquietud de aprender electrónica que había tenido desde siempre. Ahora puedo darme el gusto de programar las cosas que yo mismo diseño y fabrico.

2 Respuestas

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *