Introducción al I²C-bus. (Actualizada)
Hablar del I2C bus, en nuestros días es, poco menos que arriesgado, hay que afinar mucho en lo que se dice, ya que cualquiera ha realizado su descripción y creo realmente que hay muy buenas descripciones y de esas, se bebe el conocimiento, por parte de muchos aficionados a la electrónica, cuando tiene que utilizar esta técnica de transmisión de datos como es el I2C-bus. I2C es un acrónimo de «Inter-Integrated Circuit». En esta ocasión, espero exponer mi puntual experiencia y dar un poco de luz a los que estén interesados en conocer los pasos a seguir para utilizar con éxito esta técnica de transmisión I2C.
Hace ya muchos años cuando tuve conocimiento del sistema I2C bus, en aquellos momentos mi trabajo estaba relacionado directamente con la electrónica más puntera de la época, lo que se conocía como, «la cresta de la ola». Ciertamente que no estaba en mi camino el hacer prácticas (por motivos que no vienen al caso) de esta novedosa técnica que, presentó la firma «Philips Semiconductors» (ahora NXP) a principios de los 80s, sin embargo, si puse en manos de bastantes ingenieros de la época y las Universidades de la zona, la extensa información que proveía la mencionada empresa.
Los ingenieros de «Philips» vieron la necesidad de la simplificación y normalización de las líneas de datos que viajan entre los diversos circuitos integrados en sus productos. Su solución fue el bus I2C. Esto redujo el número de cables a dos (SDA – los datos, y SCL – reloj).
Esta documentación, nace sabiendo que existen otras muchas más profundas, solamente pretende explicar desde mi punto de vista que es y como se comporta superficialmente una red I²C, por si alguien necesita un detalle diferente.
Se supone que usted, domina el sistema binario, decimal codificado y hexadecimal, esto le servirá para una mejor comprensión.
Un motivo para usar el I2C
Es sabido que el playgrund de Arduino tiene una descripción sobre el I2C – TWI (Two-Wire Interface), se trata del I2C. En dicho documento, se habla del I2C y se refiere a enlaces relevantes, para los que tengan interés en el tema.
Por mi parte, he de decir que, hasta hace algún tiempo, no había puesto ningún empeño en ampliar mis conocimientos sobre la transmisión de datos, tal vez por que no había tenido la necesidad. Sin embargo hace poco más de un año cuando empecé a utilizar en mis ratos libres el Arduino, descubrí que disponía de dos patillas que están dotadas de este protocolo o sistema de transmisión y bueno, mi interés no paso de la curiosidad del momento, por lo que no entre en detalle.
Por aquellos días, tuve un encuentro casual con un amigo que, me propuso realizar un sistema de acceso a una empresa. En el proyecto por denominarlo de algún modo, se debía controlar los vehículos que entraban y salían de la empresa, por puertas de entrada y salida, el sistema debía enviar datos a un PC central, en el cual se encuentran los permisos de los vehículos autorizados… En cierto momento del proyecto, se presentó la necesidad de utilizar el sistema del bus I²C, para economizar en las E/S del Arduino y ese es el momento en el que surge la necesidad de conocer más a fondo el modo en que se basa y como trabaja el mencionado protocolo.
Mis primeros paso fueron la adquisición de datos, aquellos libros de Philips que guarde, ahora serían vitales, además de información que, extraje de varios documentos de dominio público que, se encuentran en la red y otros libros actuales que lo relacionan con Arduino.
Entre la documentación de TWI (Two-Wire Interface) que es incompleta y no explica cada función, como corresponde a una función I²C, los ejemplos de código que son anticuados y de vez en cuando incorrectos, mi carencia de familiaridad con I²C en general, además, no teniendo un circuito I²C en funcionamiento como referencia y desde luego mis despistes y mis muchos errores, esto puso por un momento a relucir una falta de experiencia desconcertante por mi parte. Esto fue un reto.
Después, me procuré una serie de circuitos integrados que tuvieran este protocolo entre sus cualidades, encontré bastantes dispositivos basados en este protocolo del I²C y ya sólo tenía que poner manos a la obra, practicar y practicar, buscar la forma de servirme de aquellas posibilidades y adaptarlas a mis necesidades. No pasó mucho tiempo para tener el éxito esperado, al principio estuvo el tema de direccionar cada dispositivo, todos los dispositivos diseñados para funcionar en este bus poseen su propia y única dirección de acceso, preestablecida por el fabricante. Poder leer una dirección, ni que decir, de escribir en una dirección, recomiendo leer las HD del fabricante para conocer dicha dirección. Esto ya pasó, con esto quiero decir a los interesados que, no es tan difícil aprender y aplicar el protocolo del bus I²C.
QUÉ ES EL I²C-BUS?
El I²C bus, no tan sólo son dos cables, usados para realizar una transmisión bidireccional de datos entre distintos sistemas gobernados por microcontroladores de forma eficaz. Veremos, cómo podemos controlar un importante número de dispositivos con nuestro Arduino, aunque, no es fácil de dominar. Se trata de, un bus bidireccional que utiliza dos líneas, una de datos serie (SDA) y otra de reloj serie (SCL), que requiere resistencias de polarización a positivo (RPA). SCL es la línea de reloj, se utiliza para sincronizar todos los datos SDA de las transferencias durante I²C bus. SDA es la línea de datos.
Las líneas SCL y SDA están conectadas a todos los dispositivos en el I²C bus. Ambas líneas SCL y SDA son del tipo drenador abierto asociados a un transistor de efecto de campo (o FET), es decir, un estado similar al de colector abierto. Esto significa que el chip puede manejar su salida a BAJO, pero no puede manejar a ALTO. Para que la línea pueda ir a ALTO, se deben proporcionar resistencias de polarización a 5V. Necesita de una resistencia de la línea SCL a la línea de 5V y otra de la línea SDA a la línea de 5V. Sólo necesita un conjunto de resistencias de RPA (pull-up) para todo el I²C bus, no son necesarias para cada dispositivo. La alimentación del sistema, debe tener una masa común, también puede haber una alimentación compartida que, se distribuye entre los distintos dispositivos.
Los dispositivos en el I²C bus son maestros o esclavos. El maestro, es siempre el dispositivo que maneja la línea de reloj SCL. Los esclavos, son los dispositivos que responden al maestro. Un esclavo no puede iniciar una transferencia a través del I²C bus, sólo un maestro puede hacer esa función. Generalmente son, varios esclavos en el I²C bus, sin embargo, normalmente hay un solo maestro. Es posible tener varios maestros, pero es inusual y no se comentará aquí. Los esclavos, nunca inician una transferencia. Tanto el maestro, como el esclavo puede transferir datos a través del I²C bus, pero la transferencia siempre es controlada por el maestro.
Todas las direcciones I²C bus son de 7 bits o 10 bits. Esto significa que, se pueden tener hasta 128 dispositivos en el bus I²C, ya que un número de 7bit puede estar de 0 a 127. El I²C tiene un diseño de espacio de referencia de 7 bits de direcciones, reservado con 16 direcciones, de modo que finalmente, pueden comunicarse en el mismo bus un máximo de 112 nodos. El número máximo de nodos está limitado por el espacio de direcciones y también por la capacidad total de los buses de 400 pF, lo que restringe la práctica de comunicación, a distancias de unos pocos metros.
Cuando se envía la dirección de 7 bits, siempre seguimos enviando 8 bits. El bit extra (bit 8º) se usa para informar al esclavo si el maestro está escribiendo o leyendo de él. Si el bit 8º es 0, el maestro está escribiendo al esclavo. Si el bit 8º es 1, el maestro esta en la lectura del esclavo. Existen disposiciones en la norma de I²C para entornos multi-master, así como de 10 bits frente a la más simple y la más comúnmente usada, es la configuración de un solo maestro, de 7 bits de direccionamiento.
Yo se que, la localización de la dirección de 7 bits en la parte superior del byte, es una fuente de confusión para los recién llegados, pero intentaré hacer un esfuerzo para dejar lo más claro posible este punto. No debería haber ningún problema en que, los tres bits A0, A1 y A2 correspondientes a los pines 1, 2 y 3 seleccionan la dirección del dispositivo, del P0 al P7 son los puertos de E/S e INT, es una salida de interrupción que no lo usaremos. De modo que, para poner en servicio un PDF8574, son necesarias dos cosas, la dirección del dispositivo (b0100000) y un byte de datos para el pin de salida que se necesita.
De modo que, si ponemos los pines A0 ~ A2 a masa o GND, la dirección de nuestro dispositivo en el sistema binario será 0100000, o 0x20 en formato hexadecimal. Y con los bytes de datos, haremos lo mismo, configurando así los pines de salida, por ejemplo: si queremos poner todos a Alto (H), enviamos 0 en binario que, en hexadecimal es 0, o bien para poner los cuatro primeros a H y los segundos cuatro a L. Se utiliza 00001111 en binario que, en hexadecimal es 0x0F.
¿Se ha dado cuenta? Por qué razón estos datos parecen estar al revés de lo que se ha comentado. Y ¿por qué enviamos un cero, convirtiendo todos los pines a H? El motivo es, que las E/S del PCH8574 son sumideros de corriente, esto quiere decir que, las corrientes circulan desde los +5V, a través de las cargas hacia los pines de E/S del dispositivo. No olvidemos que estamos configurando los datos del segundo byte y siguientes. Tratamos con las entradas/salidas. Por dicho motivo, los valores de E/S que establezcamos, se verán complementados en nuestra instrucción.
Además, en la instrucción, no hay que olvidar el bit0 (R/W), el de menor peso LSB (o Least Significant Bit, en inglés) que le indica al bus I2C, la función del maestro, según su valor (0 para leer y 1 para escribir).
Nota: El ‘octavo bit’ (LSB) es el que indica si la operación es, de lectura o escritura y es añadido automáticamente por el Arduino, por ese motivo, las direcciones I2C deben ser de 7 bits.
Por ejemplo, para escribir en la dirección 0x21, realmente se tiene que enviar 0x42, que es el 21 desplazado 1 bit a la izquierda, para insertar el bit de lectura/escritura (R/W) en el byte (recuerde 8bits). Veamos:
1 2 3 |
Bits 76543210 b 00100001 = 21 h; b00100001 x 10 = b01000010; b 01000010 = 42 h |
Esto es la base del protocolo I²C-bus, el bus tiene dos funciones para los nodos: maestro y esclavo. El resultado de este sistema produce un anillo compuesto por dos vías (hilos) para el desarrollo de la función de comunicarse entre sí, los dispositivos interconectados a las mencionadas vías, esto permite comunicarse entre ellos mismos con un protocolo que, consiste en que en cada momento hay un MAESTRO y el resto son ESCLAVOS. Un símil sería que, –mientras uno habla, el resto escuchan-, es decir, uno escribe y el resto leen.
En la figura anterior se puede apreciar que, la condición START está definida, cuando la señal de reloj SCL permanece estable ALTO (H) además, el nivel de la señal de «no reconocimiento», debe ser también ALTA (H), si en ese preciso instante se produce un descenso (flanco de bajada) en la señal de datos, automáticamente se produce la condición de START (inicio) de la transmisión y el dispositivo que la produjo se convierte en MAESTRO, dando comienzo a la transmisión. El pulso de reconocer o reconocimiento, conocido como ACK (del inglés Acknowledge), se logra colocando la línea de datos a un nivel lógico bajo, durante el transcurso del noveno pulso de reloj. Yo se, que esta parte, es mas compleja de lo que parece, debe observar con atención los pasos que sigue el inicio de una transmisión en la figura que sigue.
Yo se, que esta parte, es mas compleja de lo que parece. Es muy importante, debe observar con atención, los cuatro pasos que sigue el inicio de una transmisión, son los 4 bytes de inicio, vea la figura anterior
- En el primer paso, el byte que se envía es START, después de la condición de Bit inicio (START) se envía un byte que, contiene siete bits que componen la dirección del dispositivo que se quiere seleccionar y un octavo bit R/W (que corresponde a la operación que se quiere realizar con él, lectura o escritura).
- El segundo paso, este byte, contiene la dirección del registro que se desea leer/escribir. Puede realizarse un reinicio como se muestra en la figura.
- El tercer paso, aquí se escribe la dirección con el bit menos significativo LSB a nivel 1, para indicar que se lee.
- El cuarto paso y siguientes continúan la misma función de lectura, no tiene por qué ser sólo uno.
A cada byte transferido al bus, le sigue un noveno pulso de reloj durante el cual, el dispositivo receptor, debe generar un pulso de reconocimiento.
Para pasar a la función de escritura en el mismo dispositivo, puede realizarse, enviando un bit de STOP o de reinicio, considerado como parada e inicio. El paso que sigue es, escribir el byte que contiene siete bits que componen la dirección del dispositivo que se quiere seleccionar y un octavo bit a 0 que corresponde a la operación que se quiere realizar con él, ahora escritura. Y los pasos siguientes pueden ser como en el caso anterior.
Dicho esto, se debe resaltar que en el I²C-bus se definen tres tipos básicos de mensajes, cada uno de los cuales comienza con un START y se termina con una STOP.
1 2 3 4 |
a) Simple mensaje, donde un maestro escribe datos a un esclavo. b) Simple mensaje, donde un maestro lee datos de un esclavo. c) Mensajes combinados, donde un maestro publica y al menos dos leen/escriben a uno o varios esclavos. |
En un mensaje combinado, cada uno, sea de lectura o escritura comienza con un START y la dirección de esclavo. Después del primer START, también se pueden hacer llamados repetidos bits de START, esto confirma que repetidos bits START no vienen precedidos por bits de STOP, que es como los esclavos conocen la próxima transferencia que, es parte del mismo mensaje. Todo esclavo puede sólo responder a mensajes particulares, tal como se define por su documentación de producto.
Cuando el maestro ha terminado de escribir todos los datos en el esclavo, se envía una secuencia de parada que completa la transacción. Así que para escribir en un dispositivo esclavo:
1 2 3 4 5 6 7 8 |
1. Enviar una secuencia de inicio (START). 2. Enviar la dirección I2C del esclavo más el bit bajo <strong>R</strong>/<strong>W</strong>.(0xC0 = b1100 000<strong>0</strong>) 3. Enviar el número de registro interno al que se quiere escribir.(ej. 0x00 = b0000 0000) 4. Enviar el byte de datos. (0x01 = b 0000 0001) 5. [Opcionalmente, envíe algunos otros bytes de datos]. 6. Enviar la secuencia de parada (STOP). |
Para lograr este propósito, se parte de una palabra de dirección, un byte, en los que debemos distinguir: el bit START, con dirección del esclavo al que interrogará. Esta dirección está formada por 4 bits de código de control más tres bits (A0..A2) de selección de dispositivo y el bit de escritura /lectura (R/W), por último se envía el bit ACK (reconocer) por que es el maestro el que está transmitiendo.
FUNCIÓN ESCRITURA.
Cuando un dispositivo quiere «decir algo» se dirige al dispositivo con el que quiere hablar, envía una señal START (inicio) condicional y se procede al envío de un byte con los siete bits que componen la dirección del dispositivo esclavo con el que se quiere comunicar, mas un octavo bit de menor peso que corresponde con la operación deseada (E/L), escritura = 0 (enviar al esclavo) y lectura = 1 (recibir del esclavo), seguido del bit reconocer ACK.
La dirección enviada es comparada por cada uno de los esclavos del bus con su propia dirección, si ambas coinciden, el esclavo se considera direccionado como esclavo-receptor o esclavo-transmisor dependiendo del bit de menor peso E/L. El esclavo responde enviando un bit de reconocer ACK que le indica al dispositivo maestro que el esclavo reconoce la solicitud y está en condiciones de comunicarse. Y comienza el intercambio de información entre ambos dispositivos.
El maestro envía la dirección del registro interno del dispositivo, en el que se desea leer o escribir, el esclavo responde con otro bit de reconocer, ahora el maestro puede empezar a leer o escribir bytes de datos. Todos los bytes de datos deben constar de 8 bits, el número máximo de bytes que pueden ser enviados en una transmisión no está restringido, siendo el esclavo quien fija esta cantidad dependiendo de sus características. Esto se consigue por que cada byte leído/escrito por el maestro debe ser obligatoriamente reconocido por un bit de reconocer por el dispositivo maestro/esclavo.
Es conveniente recordar estos puntos que, el número de bytes de datos transferidos entre las condiciones de inicio y parada del transmisor al receptor no esta limitado. Cada byte de ocho bits es seguido por un bit reconocer (ver Fig. 6). El bit reconocer es un nivel ALTO puesto en el bus por el transmisor mientras que el maestro genera un pulso de reloj extra reconocer relacionado.
Un receptor esclavo cuando es direccionado debe generar un reconocer después de la recepción de cada byte. También un maestro debe generar un reconocer después de la recepción de cada byte que ha sido registrado desde el esclavo transmisor. El dispositivo que reconoce tiene que poner a BAJO la línea SDA durante el pulso de reloj reconocer, por lo que la línea SDA es estable BAJO, durante el período ALTO del pulso de reloj reconocer relacionado, los tiempos de configuración y mantenimiento deben ser tenidos en cuenta.
A pesar de que el maestro normalmente controla el estado de la línea de reloj SCL , puede que un esclavo de baja velocidad o que un esclavo deba detener la transferencia de datos mientras efectúa otra función, podría forzar la línea SCL a nivel bajo. Esto haría que el maestro entrase en un estado de espera, durante el cual, no transmitirá información esperando a que el esclavo esté listo para continuar la transferencia en el punto donde había sido detenida. Cuando finaliza la comunicación, el maestro transmite una condición de «stop» para dejar libre el bus.
La figura que sigue corresponde al registro en el modo lectura. Siga las señales de la figura para comprender su funcionamiento.
Esto es para comunicaciones simples I²C casi todo, pero hay una complicación más. Cuando el maestro lee del esclavo, es el esclavo el que coloca los datos sobre la línea SDA, pero es el maestro quien controla el reloj. ¿Qué pasa si el esclavo no está listo para enviar los datos? Con dispositivos tales como memorias EEPROM esto no es un problema, pero cuando el dispositivo esclavo es en realidad un microprocesador con otras cosas que hacer, puede ser un problema.
El microprocesador del dispositivo esclavo tendrá que ir a una rutina de interrupción, guardará sus registros de trabajo, averiguará de que dirección quiere leer el maestro, para obtener los datos y colocarlos en su registro de transmisión. Esto puede tomar muchos uS para que ocurra, mientras que el maestro está felizmente enviando pulsos de reloj por la línea SCL que, el esclavo no puede responder.
El protocolo I²C proporciona una solución a esto: el esclavo está autorizado a mantener la línea SCL baja. Esto se llama reloj de estiramiento. Cuando el esclavo recibe la orden de lectura del maestro, este mantiene la línea de reloj baja. El microprocesador obtiene los datos solicitados, los coloca en el registro de transmisión y libera la línea de reloj que habilita la resistencia RPA para finalmente dejarla a alto.
Desde el punto de vista de los maestros, se emitirá el primer pulso de reloj de lectura, haciendo SCL ALTO y luego verificará si realmente se ha ido a ALTO. Si es todavía BAJO, entonces es el esclavo quien lo mantendrá BAJO y el maestro debería esperar hasta que este vaya ALTO antes de continuar. Por suerte, los puertos de hardware I2C en la mayoría de los microprocesadores se encargará de forma automática.
NOTA.
Como se ha visto, el dispositivo maestro, para el caso de lectura, enviará el primer pulso de reloj para la lectura de datos del esclavo, liberando la línea SCL para que pase a ALTO, pero antes de continuar comprobará que SCL realmente haya ido al nivel lógico 1, si la línea SCL permanece en BAJO, el dispositivo maestro interpreta que el esclavo la mantiene así y espera a que SCL vaya a ALTO antes de continuar. Cuando el maestro está leyendo desde el esclavo, es el dispositivo esclavo quien pone los datos en la línea SDA del bus y el maestro es el que controla el pulso de reloj.
Esto es lo que ocurre normalmente, sin embargo, que ocurre si el esclavo no está listo para enviar un dato. Con dispositivos como una EEPROMs esto no sería problema, ya que son esclavos de otro dispositivo. Cuando el dispositivo «esclavo» se trata de un microprocesador, el cual se supone que tiene otras tareas que atender, aquí es donde surge el problema. Dicho microprocesador, para atender la llamada del dispositivo maestro, deberá utilizar una interrupción, guardando el estado de sus registros de trabajo en ese momento, determinar la dirección que desea leer el maestro, tomar el dato y ponerlo en el registro de transmisión.
En el tiempo que transcurre (micro segundos) con esta transacción, el dispositivo maestro estaría enviando pulsos de reloj ciegamente por la línea SCL, sin que el dispositivo esclavo le respondiera. Para este caso, el protocolo I²C ofrece una solución; el esclavo puede mantener la línea SCL en BAJO, a esto se le llama estiramiento del reloj. Por este motivo, cuando el esclavo recibe el comando de lectura, lo primero que hace es poner la línea de reloj en BAJO, hasta que obtiene el dato solicitado, entonces lo pone en el registro de transmisión e inmediatamente libera la línea de reloj, que pasará de inmediato a ALTO debido al nivel que aporta la resistencia de polarización.
Mi experiencia personal en el uso del I²C bus, evidentemente debe mejorar con la práctica, del mismo modo que ocurrirá con la del lector interesado, si sigue realizando proyectos y practicando con el sistema de transmisión de datos entre dispositivos con micro-controladores. La práctica ha ido mejorando mis conocimientos sobre el I2C y algunas muestras se encuentran en este sitio. Para una mayor información refiérase a las indicaciones del fabricante en especificaciones del I²C de Philips.
El I²C-bus con Arduino.
Actualmente existen muchas aplicaciones, para aplicar con la placa Arduino; como un reloj en tiempo real, potenciómetros digitales, sensores de temperatura, brújulas digitales, chips de memoria, servos, circuitos de radio FM, E/S expansores, controladores de LCD, amplificadores, etc. Y además usted puede tener más de una idea para aplicar este bus, en cualquier momento, como se ha dicho, el número máximo de dispositivos I²C utiliza en un momento dado es de 112 nodos.
Debe tenerse muy en cuenta el Arduino que está utilizando, si es un Arduino Mega, el pin SDA, es pin 20 y el SCL, es el pin 21, así que, tenga en cuenta que en los escudos con I²C, necesitan ser específicamente para el Mega. Si usted tiene otro tipo de tarjeta, revise la hoja de datos o consulte la página web de pruebas de hardware de Arduino. Y por último, si usted está usando un microcontrolador ATMega328 base DIP-PU, deberá a utilizar para SDA el pin 27 y SCL el pin 28.
Si sólo está utilizando un dispositivo I²C, las resistencias RPA, no son necesarias ya que el microcontrolador ATMega328 en nuestro Arduino las ha incorporado. Sin embargo, si está empleando una serie de dispositivos, utilice dos resistencias de 4k7 ohmios. Como todo, algunas pruebas en un circuito protoboard o prototipo determinará su necesidad. La longitud máxima de un bus I²C es de alrededor de un metro y es una función de la capacidad del bus. Esta distancia se puede ampliar con el uso de un circuito especial que no examinaremos en el presente capítulo.
Cada dispositivo se puede conectar al bus en cualquier orden y como ya se ha mencionado, los dispositivos pueden ser maestros o esclavos. En nuestra aplicación el IDE Arduino, es el maestro y los dispositivos que «colguemos» en el bus I²C son los esclavos. Podemos escribir datos en un dispositivo o leer datos de un dispositivo. A estas alturas ya no debe tener la duda «¿cómo podemos diferenciar cada dispositivo en el bus?» Más arriba, ya se ha documentado. Cada dispositivo tiene una dirección única. Nosotros usaremos esa dirección en las funciones descritas más adelante, para dirigir nuestras peticiones de lectura o escritura al dispositivo correcto.
Al igual que en la mayoría de dispositivos, hacemos uso de una librería Arduino, en este caso <wire.h>. A continuación, utilice la Wire.begin function(); dentro de la configuración del voíd setup(); y estamos listos para empezar.
ENVÍO de datos (sending), desde nuestro Arduino a los dispositivos I²C depende de dos cosas: la dirección única del dispositivo (que necesitamos esté en hexadecimal) y al menos un byte de datos a enviar. (Como ya se ha descrito arriba).
Por ejemplo; la dirección del dispositivo en el ejemplo (de abajo) es 00101111 (binario), que es 0x2F en hexadecimal.
Entonces debemos establecer el valor del puntero, que es un valor entre 0 y 127, o sea 0×00 y 0x7F en hexadecimal. Así que para establecer el puntero a cero, usaríamos las funciones siguientes:
Wire.beginTransmission(0x68); // dirección única 0x68 del ds1307
Esto envía la dirección del dispositivo por la línea del bus SDA (datos). Viaja a lo largo del bus, y «avisa» al dispositivo correspondiente que tiene algunos datos que vienen …
Wire.send(0x00); // inicia el puntero de la memoria del ds1307 (es el byte)
Esto envía el byte de datos en el dispositivo – en el registro del dispositivo (o la memoria de todo tipo), que está esperando con los brazos abiertos. Cualquier otro dispositivo en el bus pasará por alto esto. Tenga en cuenta que sólo puede realizar una operación I²C a la vez! Luego, cuando haya terminado de enviar datos al dispositivo, queda «la transmisión final». Esto le dice al dispositivo que hemos terminado, y libera el bus I²C para la siguiente operación:
Wire.endTransmission(); // termina la transmisión
Algunos dispositivos pueden tener más de un registro y por lo tanto requieren más bytes de datos en cada transmisión. Por ejemplo, el DS1307 reloj en tiempo real tiene ocho registros para almacenar los datos de tiempo, cada uno requiere ocho bits de datos (un byte), o puede ser una RAM o una E2PROM.
Sin embargo, con el DS1307 – como requiere ocho bits de datos, enviar la totalidad del lote necesita volverlo a reescribir cada vez. Así que, en este caso, será necesario utilizar ocho funciones de wire.send (), cada vez. Cada dispositivo interpreta los bytes de datos enviados al mismo, por lo que se necesita la hoja de datos del dispositivo, para entender cómo usarlo.
Recepción de datos (Receiving) desde un dispositivo I²C con nuestro Arduino, requiere dos cosas: la dirección única del dispositivo (que necesitamos esté en hexadecimal) y el número de bytes de datos a aceptar desde el dispositivo. La recepción de datos en este momento es un proceso que consta de dos etapas. Si revisamos el cuadro anterior de la hoja de datos del DS1307, tengamos en cuenta que hay ocho registros o bytes de datos allí. Lo primero que tenemos que hacer es tener el inicio del dispositivo I²C leer el primer registro, que se realiza mediante el envío de un cero en el dispositivo:
1 2 3 |
<span style="color: #339966;"> <span style="color: #008080;">Wire.beginTransmission(device_address);</span></span> <span style="color: #339966;"> <span style="color: #008080;">Wire.send(0);</span></span> <span style="color: #339966;"> <span style="color: #008080;">Wire.endTransmission();</span></span> |
Ahora, el dispositivo I2C enviará los datos del primer registro cuando se le solicite. Ahora, necesitamos pedir al dispositivo los datos y la cantidad de bytes que queremos. Por ejemplo, si un dispositivo necesita tres bytes de datos, le pedimos para tres y, almacenar cada byte en su propia variable (por ejemplo, tenemos tres variables de tipo byte: a, b y c. La primera función a ejecutar es la siguiente:
1 |
<span style="color: #008080;">Wire.requestFrom(device_address, 3); <span style="color: #339966;">//</span></span><span style="color: #339966;">device_address, es la variable del dispositivo</span> |
Que le dice al dispositivo, «envía tres bytes de datos de vuelta» al Arduino. A continuación, inmediatamente después de esto con:
1 2 3 4 5 |
<span style="color: #339966;"> <span style="color: #008080;">*a = Wire.receive();</span></span> <span style="color: #008080;">*b = Wire.receive();</span> <span style="color: #008080;">*c = Wire.receive();</span> |
No es necesario utilizar Wire.endTransmission() al leer los datos. Ahora que los datos solicitados se encuentran en sus respectivas variables, se pueden tratar como cualquier otra variable de bytes ordinaria.
Para una explicación más detallada del bus I2C, lea el documento explicativo u hojas de datos. Ahora vamos a utilizar nuestro conocimiento I2C mediante el control de una amplia gama de dispositivos …
Esta es una utilidad que le puede ayudar a conocer la dirección del dispositivo que usted ha adquirido, en el caso de disponer de varias unidades, lea este simple artículo.
Buen documento
estoy migrando a procesador arduino
para aplicaciones a personas con capacidades diferentes
por lo que estoy trabajando con sesores acelerómetros gyroscopios para controlar el ratón y ejecutar aplicaciones con movimientos de ojos, cara y ondas cerebrales así mismo cntrolar motores para manejar sillas de ruedas para diferentes discapacidades
felicidades .. buena la aportación
ánimo
Gracias por tus palabras. Espero te sirva esta información. Estoy a tu entera disposición.
Saludos.
Muy buen aporte, la verdad que es lo que necesitaba, estoy aprendiendo todo el mundo arduino y haciendo proyectos pequeños de forma de aprender y esto me viene de maravillas. Siempre estube interesado en aprender el protocolo I2C y con esto voy a veri si logro hacer algo.
Muchas gracias por poner tus conocieminetos al alcance de todos.
buen día, leí el aporte y me gusto mucho, solo una pregunta, que tal ves ya hicieron, ¿cual es la distancia maxima entre el esclavo y maestro usando el protocolo TWI en los avr?, de antemano gracias por la respuesta
Hola, emilio.
En un principio te diré que el protocolo I2C se creó para la intercomunicación entre distintos dispositivos que componían un mismo equipo como puede ser un TVC de los años 80′, lo cual puede darnos una idea de las distancias, ahora bien, esto no quiere decir que no podamos extender estas referidas distancias mediante métodos y medios adecuados.
Sin embargo, se debe tener presente dotar de sistemas anti-interferencias que se va a incrementar exponencialmente con la distancia a cubrir por los dispositivos implicados en la transmisión.
En otras palabras, y dado que las ITV (interferencias), son inherentes al lugar donde se aplique el dispositivo, estas no se pueden cuantificar por anticipado y siempre se aplicarán los filtros adecuados a cada situación.
En definitiva, una distancia de unas decenas de metros tal vez no te den demasiados problemas. Deberás hacer pruebas y utilizar cable apantallado o cable trenzado, como digo, depende del lugar y las radiaciones que hayan alrededor.
Lamento no tener mejor respuesta.
Gracias por el aporte. Ya estoy trabajando con un convertidor AD que usa I2C y he logrado ponerlo a funcionar en modo estándar (100khz para scl). Sin embargo, convertidor indica que puede operar en modo rápido (400khz) y modo ultra rápido (3.4mhz), pero no logro que funcione a estas velocidades. En las especificaciones técnicas aparece un procedimiento para hacerlo funcionar en modo ultra rápido, pero esto es a partir del modo rápido. Lo que me intriga es que no hay procedimiento para hacerlo funcionar en modo rápido. Así que yo asumí que solo era cuestión de usar 400khz en vez de 100khz para el scl, pero cuando lo pongo en 400khz, no me funciona. Solo me trabaja con 100khz. ¿Tendrás alguna idea que me pueda ayudar?
Hola Dan.
Personalmente no hice aplicación alguna que necesitara estas velocidades. He revisado el tema y he buscado una respuesta en el fabricante, y he encontrado una información que puede que te sirva de ayuda, la puedes encontrar en:
https://www.nxp.com/docs/en/user-guide/UM10204.pdf
En el apartado, 5. Bus speeds y siguientes, espero te sirva.
Saludos.
Gracias por el aporte, saludos.
Buenos días, primero quiero felicitarte por tu aporte que me parece muy valioso e importante ya que es un tema trascendental para quienes trabajamos con micros y sistemas que trabajan con este protocolo de comunicación, en segundo aspecto quería pedirte el favor de darme alguna luz o indicación ya que estoy tratando de hacer funcionar un modulo TCS34725 que es un modulo que reconoce colores,(RGB Sensor) y lo he hecho funcionar con Arduino nano y arduino Mega, pero he querido hacerlo funcionar con un microcontrolador 16f883 de Microchip y no le he dado en el clavo para hacerlo funcionar ya que trato de basarme en otros dispositivos y nada que funciona y queria preguntarte como se podria configurar para leer los datos de este sensor y si se puee hacer un programa que solo pueda leer datos solamente, te agradezco tu informacion a ver si veo la luz con este sensor
Buenos dias
Tengo un equipo analizador de gases de combustion y en la pantalla muestra error I2C, q podria ser ?
Muchas gracias por colaboracion
Hola Ricardo correa zamora.
Con los datos que indicas, es difícil hacer un diagnóstico acertado. De todas formas parece evidente que está fallando el sensor inteligente que tiene la opción del I2C.
Seguramente se trata de un montaje en SMD y te resulte complicado encontrar una pieza de recambio, pero, siempre cabe la posibilidad de que puedas encontrar y en ese caso tendrás que sustituir una por otra, cosa nada sencilla si no dispones de herramientas adecuadas.
Espero haber dado respuesta adecuada a tu consulta. Saludos.