Tabla de contenido:

Bus I2C para ATtiny y ATmega: 8 pasos
Bus I2C para ATtiny y ATmega: 8 pasos

Video: Bus I2C para ATtiny y ATmega: 8 pasos

Video: Bus I2C para ATtiny y ATmega: 8 pasos
Video: MODULO I2C PARA PANTALLAS LCD (display 16x2) + CODIGO ARDUINO + CONEXIONES|| BIEN EXPLICADO 2024, Mes de julio
Anonim
Bus I2C para ATtiny y ATmega
Bus I2C para ATtiny y ATmega

¡Me encantan los microcontroladores Atmel AVR! Desde que construí el Ghetto Development System descrito en este Instructable, me he divertido muchísimo experimentando con el AVR ATtiny2313 y el ATmega168 en particular. Incluso fui tan lejos como para escribir un Instructable sobre el uso de interruptores como entradas y extendí el concepto del Sistema de Desarrollo Ghetto a CPLD. Durante un proyecto reciente, necesitaba varios interruptores para establecer valores de control. Los AVR no tenían suficientes pines de E / S, así que tuve que pensar en algo. Podría haber probado un sistema de entrada complejo con un teclado y una pantalla, pero el ATtiny2313 se habría quedado sin recursos. Afortunadamente, Atmel ha proporcionado una forma de solucionar este problema al incluir una interfaz que puede conectarse a chips adicionales (como memoria o puertos de E / S) con una interfaz simple de dos cables. Así es, al usar solo dos pines de E / S en un AVR podemos acceder a muchos pines de E / S adicionales y también a otros recursos. Esta interfaz de dos cables se conoce formalmente como bus de circuito interintegrado, o simplemente bus I2C y fue inventada por NXP cuando todavía era Philips Semiconductors. Si está leyendo este Instructable, probablemente haya oído hablar del bus I2C e incluso lo haya usado en un PIC u otro microcontrolador. Aunque conceptualmente es muy simple y está respaldado por recursos de hardware en los AVR, los controladores de software siguen siendo necesarios para usar el bus I2C. Atmel proporciona Notas de aplicación (consulte los Recursos más adelante en este Instructable), pero estos están incompletos y no muestran ningún ejemplo más allá de la comunicación con otro dispositivo AVR. No es el propósito de este Instructable enseñar a nadie cómo crear controladores I2C para el AVR. Más bien, proporcionaré versiones expandidas de los controladores Atmel para dispositivos ATtiny2313 y ATmega168, explicaré los requisitos y restricciones que se aplican al usarlos y le mostraré ejemplos prácticos de dispositivos I2C. Después de trabajar con este Instructable, podrá utilizar el bus I2C con éxito en sus proyectos AVR. Obviamente, puede ignorar los controladores de tiny o MEGA si solo está interesado en uno de ellos. Para aquellos interesados en aprender más sobre el bus I2C, proporcionaré enlaces al material apropiado.

Paso 1: ¿Qué es todo esto de I2C de todos modos?

¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?
¿Qué es todo esto de I2C de todos modos?

El bus I2C es una conexión simple de dos cables que puede vincular varios dispositivos y permitirles intercambiar datos. En su forma más simple, hay un dispositivo maestro que se comunica con múltiples dispositivos esclavos. Todos los dispositivos están conectados en paralelo a los dos cables del bus I2C. Los dos cables se conocen como SCL y SDA. SCL es la línea del reloj y está controlada por el dispositivo maestro. SDA es la línea de datos bidireccional. Para transferir datos, el maestro envía una dirección de esclavo combinada con un indicador de lectura / escritura de un bit. Si se desea una escritura, el maestro continuará enviando datos al esclavo direccionado. Si se solicita una lectura, el esclavo responderá con datos. Para coordinar transacciones, las líneas SCL y SDA son manipuladas por el maestro y el esclavo para señalar varias condiciones. Estos incluyen START, STOP, ACK (reconocimiento) y NAK (sin reconocimiento). Los conductores manejan los detalles de estas condiciones. Los verdaderos geeks entre ustedes pueden aprender todos los detalles en los enlaces provistos al final de este Instructable. Los requisitos eléctricos son bastante simples. El maestro y los esclavos deben usar el mismo nivel para Vcc, las tierras deben estar conectadas y las líneas SCL y SDA deben elevarse a Vcc. El valor de las resistencias pull-up se determina con precisión mediante un cálculo basado en la capacitancia total en el bus, pero prácticamente puede tener prácticamente cualquier valor entre 1.8K y 10K. Empiezo con 5.1K y uso valores más bajos hasta que funciona. Por lo general, esto no es un problema a menos que tenga muchos dispositivos o largos cables entre dispositivos. La velocidad de datos nominal en el bus I2C es de 100 Kbits / segundo. También son posibles velocidades de 400 Kbits / segundo, 1 Mbits / segundo y más, pero no son compatibles con los controladores de este Instructable. Todos los dispositivos I2C funcionarán a 100 Kbits / segundo. El ATtiny2313 y el ATmega168 implementan el bus I2C de manera diferente. ATtiny2313 utiliza el hardware de interfaz serie universal (USI), que también se puede utilizar para el bus SPI. ATmega168 tiene hardware dedicado para el bus I2C conocido como Two Wire Interface (TWI). Una vez que se escriben los controladores, estas diferencias son en su mayoría transparentes para el usuario. Una diferencia significativa está en el software: el controlador ATmega168 I2C está controlado por interrupciones, mientras que el del ATtiny2313 no. Esto significa que un programa ATmega168 no tiene que esperar a que se realicen las transferencias de datos I2C, sino que solo debe esperar antes de iniciar otra transferencia o hasta que lleguen los datos de una operación de lectura. Los ejemplos y la discusión que siguen deben dejar esto en claro. Las direcciones I2C tienen una longitud de 7 bits, por lo que pueden haber hasta 127 dispositivos en el bus si cada uno tiene una dirección única. Como se muestra en la figura, esta dirección de 7 bits se desplaza un bit a la izquierda y el bit menos significativo se usa para marcar una lectura o escritura del dispositivo en la dirección. Por tanto, la dirección esclava completa es un byte de 8 bits. La dirección real se determina parcialmente internamente en el dispositivo y no se puede cambiar (los 4 bits más significativos) y está parcialmente determinada por los bits que se pueden conectar a los pines del dispositivo (3 bits menos significativos) que se pueden vincular alto o bajo para configurar una dirección específica. Suena confuso, pero un ejemplo lo aclarará. La hoja de datos PCA8574A muestra que los cuatro bits más significativos de la dirección I2C siempre serán 0111. Los siguientes tres bits están determinados por la configuración de los pines AD0, AD1 y AD2. Estos pines se pueden conectar a tierra o al suministro de voltaje positivo (5 voltios) para representar 0 o 1 respectivamente. Entonces, el rango de direcciones posibles es de 38 a 3F hexadecimal, como se muestra en la otra figura de la hoja de datos PCA8574. Entonces, al cambiar la configuración de bits de dirección, hasta 8 PCA8574A pueden estar en el bus I2C al mismo tiempo. Cada uno responderá únicamente a su dirección esclava específica. Si se necesitan aún más puertos de E / S, se puede utilizar el PCA8574. La única diferencia entre el PCA8574 y el PCA8574A es que el rango de direcciones esclavas I2C del PCA8574 es de 20 a 27 hexadecimales. Determinar la dirección de un dispositivo dado puede ser confuso ya que algunas hojas de datos consideran que el bit de lectura / escritura es parte del Dirección. Lea atentamente la hoja de datos y tenga en cuenta que la dirección del esclavo tendrá una longitud de 7 bits. El bit de lectura / escritura debe tratarse por separado. Una vez más, un ejemplo ayudará. La hoja de datos para la EEPROM 24C16 con la que experimentaremos dice que los primeros cuatro bits (más significativos) de la dirección esclava son 1010. Los siguientes tres bits pueden ser determinados por A0, A1 y A2; pero tenga en cuenta que la hoja de datos también cubre 24C01 a 24C08, que son EEPROM de menor tamaño. La figura de la hoja de datos muestra que los ajustes de estos bits de dirección se ignoran a medida que aumenta el tamaño y se ignoran por completo para el 24C16. Es decir, los últimos tres bits no importan y el 24C16 realmente usa todas las direcciones esclavas I2C 50 a 57 hexadecimales. El rango de direcciones esclavas en realidad abordará diferentes secciones dentro del 24C16. Los primeros 256 bytes están en la dirección 50h, los siguientes 256 a las 51h, y así sucesivamente hasta los últimos 256 a las 57h, para un total de 2K bytes. Dado que la dirección de la RAM PCF8570 con la que también experimentamos está en este rango, el 24C16 y el PCF8570 no se pueden usar juntos.

Paso 2: Solicite algunos dispositivos I2C

Ahora que ya sabe un poco sobre el bus I2C y desea utilizarlo, ¿por qué no pide algunos dispositivos I2C para experimentar con ellos para que puedan estar en camino hacia usted mientras prepara el software? Los dispositivos apropiados incluyen un I / O Expansor de interfaz (mi favorito), una memoria RAM estática y una EEPROM. Hay mucho más, pero estos son un gran comienzo. Los procesadores AVR que usaremos son el ATtiny2313 y el Atmega168 (usado en Arduino). Si es nuevo en estos, eche un vistazo a este excelente Instructable para aprender sobre ellos y construir su Sistema de desarrollo Ghetto. El esquema del ATmega168 en el presente Instructable muestra cómo implementar el Ghetto Development System para este procesador. El cable del puerto paralelo es el mismo que el del ATtiny2313. (No he probado la versión USB del Ghetto Development System, así que no estoy seguro de cómo se accede al bus I2C en él. Lo mismo ocurre con Arduino). Aquí están los números de pieza de Digikey. Expansor de puerto: IC I2C I / O EXPANSOR 568-4236-5-NDRam: IC SRAM 256X8 W / I2C 568-1071-5-NDEEPROM: IC EEPROM SERIAL 16K CAT24C16LI-G-ND

Paso 3: controladores I2C

Aquí están las descripciones de las funciones del controlador para el bus I2C. Estos se desarrollaron utilizando las notas de las aplicaciones de Atmel para empezar. No podría haber hecho esto sin ellos como base sobre la que construir. El desarrollo se realizó utilizando WinAVR y el compilador gcc C. Las restricciones de frecuencia de reloj se describen a continuación para cada procesador. Como no puedo probar todas las combinaciones posibles de procesador / frecuencia de reloj, me limitaré a lo que realmente puedo probar e intentaré indicar las restricciones y limitaciones. Aquí están las funciones del controlador y cómo usarlas. Consulte los ejemplos para obtener más detalles y ver las funciones en uso en programas completos. Para el ATtiny2313: Requisito de reloj: Los controladores están diseñados para una frecuencia de reloj de 1MHz (la frecuencia predeterminada) para ATtiny2313. Si desea ejecutar a otras velocidades, tendrá que ajustar las constantes en los controladores. Envíeme un correo electrónico si necesita ayuda para hacer esto. También puede obtener algunas sugerencias de las notas de las aplicaciones de Atmel en los enlaces del paso de recursos. USI_TWI_Master_Initialise () Esta función inicializa el hardware de USI para la operación en modo I2C. Llámelo una vez al comienzo de su programa. Devuelve vacío y no hay argumentos. USI_TWI_Get_State_Info () Esta función devuelve información de error I2C y se usa si ocurrió un error durante una transacción I2C. Dado que esta función solo devuelve un código de error, utilizo la función TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) para hacer parpadear un LED de error. Los códigos de error se definen en USI_TWI_Master.h. A continuación se explica cómo llamarlo: TWI_Act_On_Failure_In_Last_Transmission (USI_TWI_Get_State_Info ()) USI_TWI_Start_Read_Write () Esta función se utiliza para leer y escribir bytes individuales en dispositivos I2C. También se utiliza para escribir varios bytes. Hay 6 pasos para usar esta función: 1) Declare un búfer de mensajes en su programa para contener la dirección del esclavo y el byte de datos que se enviarán o recibirán. unsigned char messageBuf (MESSAGEBUF_SIZE); 2) Coloque la dirección del esclavo como el primer byte en el búfer. Muévalo un bit a la izquierda y O en el bit de lectura / escritura. Tenga en cuenta que el bit de lectura / escritura será 1 para lectura y 0 para escritura. Este ejemplo es para una lectura. messageBuf (0) = (TWI_targetSlaveAddress << TWI_ADR_BITS) | (VERDADERO << TWI_READ_BIT); 3) Al hacer una escritura, coloque el byte a escribir en la siguiente ubicación en el búfer 4) Llame a la función USI_TWI_Start_Read_Write con el búfer de mensajes y el tamaño del mensaje como argumentos.temp = USI_TWI_Start_Read_Write (messageBuf, 2); 5) El El valor devuelto (temp en este caso) se puede probar para ver si ocurrió un error. Si es así, se maneja como se discutió anteriormente. Ver ejemplos en los programas.6) Si se solicitó una lectura, la lectura de bytes estará en la segunda ubicación en el búfer. Si se van a escribir varios bytes (como en un dispositivo de memoria), se puede usar esta misma rutina. Configurar el búfer y llamar a la rutina son algo diferentes. El segundo byte en el búfer será la dirección de memoria inicial en la que escribir. Los datos a escribir estarán en bytes posteriores. El tamaño del mensaje será el tamaño que incluya todos los datos válidos. Entonces, si se van a escribir 6 bytes, entonces el tamaño del mensaje será 8 (dirección esclava + dirección de memoria + 6 bytes de datos). USI_TWI_Start_Random_Read () Esta función se usa para leer varios bytes de un dispositivo I2C, por lo general solo es significativa para un recuerdo de algún tipo. El uso de esta rutina es muy similar a la rutina anterior, con dos excepciones: la configuración del bit de lectura / escritura no importa. Llamar a esta rutina siempre causará una operación de lectura. El tamaño del mensaje debe ser 2 más el número de bytes a leer. Si no ocurrieron errores, los datos estarán en el búfer comenzando en la segunda ubicación. Para el ATmega168: Requisito de reloj: El Los controladores están diseñados para una frecuencia de reloj de 4MHz para ATmega168. El código de ejemplo muestra cómo configurar esta frecuencia de reloj. Si desea ejecutar a otras velocidades, tendrá que ajustar las constantes en los controladores. Envíeme un correo electrónico si necesita hacer esto. TWI_Master_Initialise () Esta función inicializa el hardware TWI para la operación en modo I2C. Llámelo una vez al comienzo de su programa. Devuelve vacío y no hay argumentos. Asegúrese de habilitar las interrupciones llamando a swi () después de inicializar. TWI_Get_State_Info () Esta función devuelve información de error I2C y se usa si ocurrió un error durante una transacción I2C. Dado que esta función solo devuelve un código de error, utilizo la función TWI_Act_On_Failure_In_Last_Transmission (TWIerrorMsg) para hacer parpadear un LED de error. Los códigos de error se definen en TWI_Master.h, pero se modifican para señalizar en un LED de error. Consulte el código de ejemplo para obtener más detalles. A continuación se explica cómo llamarlo: TWI_Act_On_Failure_In_Last_Transmission (TWI_Get_State_Info ()) Tenga en cuenta que la verificación de errores se realiza asegurándose de que la transacción I2C esté completa (función descrita a continuación) y luego probando un bit en la palabra de estado global. dos funciones funcionan igual que las funciones correspondientes descritas anteriormente, pero con algunas excepciones. No devuelven ningún valor de error. Los datos leídos no se transfieren al búfer. Hacer esto se hará con la función que se describe a continuación. Al llamar a TWI_Start_Random_Read, messageSize debe ser el número de bytes de datos solicitados más uno, no dos. El controlador I2C para el ATmega168 está controlado por interrupciones. Es decir, las transacciones I2C se inician y luego se ejecutan de forma independiente mientras la rutina principal continúa ejecutándose. Cuando la rutina principal quiere datos de una transacción I2C que inició, debe verificar si los datos están disponibles. La situación es la misma para la verificación de errores. La rutina principal debe asegurarse de que la transacción I2C esté completa antes de verificar si hay errores. Las siguientes dos funciones se utilizan para estos propósitos. TWI_Transceiver_Busy () Llame a esta función para ver si una transacción I2C está completa antes de buscar errores. Los programas de ejemplo muestran cómo usar esto. TWI_Read_Data_From_Buffer () Llame a esta función para transferir datos desde el búfer de recepción del controlador I2C al búfer de mensajes. Esta función asegurará que la transacción I2C esté completa antes de transferir los datos. Si bien esta función devuelve un valor, considero que verificar el bit de error directamente es más confiable. He aquí cómo llamarlo. El tamaño del mensaje debe ser uno mayor que el número de bits de datos deseado. Los datos estarán en messageBuf comenzando en la segunda ubicación.temp = TWI_Read_Data_From_Buffer (messageBuf, messageSize);

Paso 4: ¡Construyamos

¡Construyamos!
¡Construyamos!
¡Construyamos!
¡Construyamos!
¡Construyamos!
¡Construyamos!
¡Construyamos!
¡Construyamos!

Comience descargando el archivo I2C Schematics.zip. Es posible que desee crear una carpeta I2C en su área de trabajo para contener los esquemas y los archivos de programa de ejemplo. Descomprima los esquemas en este directorio. Encontrará una carpeta llamada I2C Schematics. Abra el archivo llamado tiny I2C.pdf. Este esquema muestra el sistema de desarrollo ATtiny2313 Ghetto y el expansor de puerto de E / S PCA8574A (tiene un cuadro grande de líneas discontinuas a su alrededor). El circuito Port Expander está construido en una placa de pruebas. Echa un vistazo a las fotos para ver cómo son estos circuitos. Son realmente bastante simples La parte ATtiny2313 del esquema es solo el Sistema de desarrollo Ghetto con tres luces intermitentes (LED1, 2 y 3, más R4, 5 y 6) y un botón pulsador (S1) conectado a él, más uno detalle adicional. Ese detalle es la adición de puentes (JP4, 5 y 6) que se pueden quitar para permitir la conexión de las líneas SCL y SDA del bus I2C. Los puentes deben estar en su lugar para la programación, luego retirados para que SCL y SDA puedan conectarse. Las fotos muestran los puentes en su lugar y retirados. La ubicación de estos puentes depende de usted, solo tiene que colocarlos en su sistema de desarrollo Ghetto si desea utilizar el bus I2C. Se debe desconectar el bus I2C y colocar los puentes para la programación. Tenga en cuenta que solo debe preocuparse por JP4 y JP6 para el bus I2C. Ponga JP5 si cree que alguna vez querrá usar el bus SPI. El expansor de puertos de E / S PCA8574A es muy simple. Proporcione conexiones Vcc (+5 voltios) y Gnd (tierra) y conecte AD0, 1 y 2 a tierra (hace que la dirección esclava I2C sea 38 hexadecimal). Luego conecte 4 luces intermitentes y 4 interruptores DIP. (Si no tiene interruptores DIP, puede usar cables. Átelos a tierra o déjelos flotantes para encender o apagar la señal respectivamente). Finalmente, conecte las resistencias pull-up (R11 y 12) de SDA y SCL a Vcc. Estos se muestran como 3.3K, pero cualquier valor de 1.8K a 5.1K debería funcionar (tal vez hasta 10K, pero no lo he probado). Una vez que haya programado el ATtiny2313, puede quitar los puentes y conectar SDA y SCL para la prueba. Ahora para el ATmega168. El único inconveniente aquí es que es posible que no haya construido un sistema de desarrollo Ghetto para este procesador. Si ese es el caso, el esquema que proporciono (MEGA I2C.pdf) le mostrará cómo hacerlo. Esta es solo una permutación de la versión ATtiny2313. Si planifica con anticipación, puede asegurarse de que su cable de programación se ajuste a ambos sistemas. La principal diferencia es la adición de C2 y C3. Vea las imágenes para la ubicación de estos, deben estar muy cerca del chip; uno de ellos está debajo del chip. Estos ayudan a mantener el ruido fuera del convertidor de analógico a digital en particular. No necesita colocar los puentes a menos que planee usar el bus SPI, ya que no son necesarios para el bus I2C en este chip. Tenga en cuenta que la placa de pruebas PCA8754A no se modificará. ¡Simplemente conectará SDA y SCL y listo! Fácil, ¿eh?

Paso 5: ¡Codifiquemos y probemos

¡Codifiquemos y probemos!
¡Codifiquemos y probemos!
¡Codifiquemos y Probemos!
¡Codifiquemos y Probemos!
¡Codifiquemos y probemos!
¡Codifiquemos y probemos!

Es hora de crear los controladores y los programas de ejemplo. Comenzaremos con el ATtiny2313 y el protoboard PCA8574A que acabamos de construir. Descargue el archivo I2C.zip en su directorio de trabajo I2C y descomprímalo. Tendrá una nueva carpeta llamada I2C. En él encontrará USI I2C (para ATtiny2313) y TWI I2C (para ATmega168). En USI I2C, encontrará la carpeta I_O Port. Esa carpeta contiene el código de nuestro primer programa de ejemplo y los controladores USI I2C. Con WinAVR, compile y cargue el código en el ATtiny2313. Respire hondo y encienda la energía. Esto es lo que puede esperar: en el encendido, el LED 1 en el puerto PD6 del ATtiny2313 parpadea dos veces. No sucederá nada más hasta que presione el botón (S1). Cada vez que se presiona el botón, se leen los interruptores y su configuración se mostrará en los LED conectados al PCA8574A. Cambie el valor de los interruptores, presione el botón y los LED deberían cambiar. Siga haciendo esto hasta que supere la emoción de verlo funcionar. Si (¡Dios no lo quiera!) Las cosas no funcionan como se esperaba, revise cuidadosamente su cableado. Los errores de I2C se señalarán mediante parpadeos en el LED3 (PD4) y probablemente signifiquen que debe verificar que SDA y SCL estén conectados a los pines correctos y que estén colocados correctamente. Si las cosas aún no funcionan, lea el resto de esta sección para aprender sobre la depuración. Ahora regrese y echemos un vistazo al código. Abra el archivo USI_I2C_Port.c. Este es el código del programa de ejemplo. (USI_TWI_Master.cy USI_TWI_Master.h contienen los controladores; puede ignorarlos a menos que sienta curiosidad.) Utilice el ejemplo para guiar sus propias aplicaciones I2C. Principalmente, el programa le muestra cómo inicializar y usar los controladores I2C, incluida la configuración subir la dirección del esclavo y el resto del búfer de mensajes, y sacar los datos de él. También verá cómo elimino el rebote del botón y configuro el ciclo while. Hay algunos detalles del programa que vale la pena mencionar. Tenga en cuenta que los datos de los conmutadores se invierten antes de escribirse en los LED del expansor de puertos. También tenga en cuenta que los puertos de entrada en el expansor de puertos deben escribirse como Alto para que funcionen correctamente. Estos detalles se describen en la hoja de datos PCA8574A. ¡Lea siempre las hojas de datos con atención! Más interesante es el uso de la depuración condicional. Cerca del inicio del archivo de programa está la declaración // # define DEBUG y esparcidas por todo el código están las declaraciones #ifdef DEBUG. Mientras DEBUG no esté definido (las dos barras inclinadas hacen que la línea sea un comentario y evitan que se defina), el código dentro de las declaraciones #ifdef a #endif no se compilará. Pero si las cosas no funcionan como esperabas, recompila y recarga el código con #define DEBUG sin comentar. Obtendrá muchos más parpadeos en los LED que puede decodificar para seguir la ejecución de su programa y ayudarlo a encontrar exactamente dónde van mal las cosas. De hecho, te recomiendo que pruebes esto solo para ver qué sucede. Lo que verá es que el LED 2 (en PD5) parpadeará a medida que avanza la ejecución a través del programa. El valor leído de los interruptores parpadeará en el LED 1 (PD6) antes de que se muestre en los LED del expansor de puerto. Debería poder rastrear el programa mientras se ejecuta usando estos LED. Trabajaremos con el ATmega168 a continuación; omita esta sección si solo está interesado en el ATtiny2313. ¿Aún conmigo? Bueno. Vaya a la carpeta TWI_I2C, cambie su directorio de trabajo a IO_Port, y compile y cargue TWI_I2C_Port.c en ATmega168. Desconecte las líneas SDA y SCL del ATtiny2313 y conéctelas al ATmega168. Conecte la energía y la tierra, y enciéndalo. ¡La operación debería ser la misma! Juega hasta que la emoción disminuya, luego veamos el código. Abre TWI_I2C_Port.c. El código es casi idéntico excepto por el manejo de errores y acomodación de controladores impulsados por interrupciones. Aquí están las diferencias: Tenga en cuenta que el reloj debe estar configurado en 4MHz para que el bus I2C funcione correctamente. El sei (); La instrucción activa las interrupciones después de la inicialización de los controladores I2C. Para comprobar si hay errores, se prueba un bit de estado específico. Durante una lectura, se debe llamar a la función TWI_Read_Data_From_Buffer para transferir los datos leídos al búfer de mensajes. Durante una escritura, se debe usar while (TWI_Transceiver_Busy ()) para asegurarse de que la transferencia esté completa antes de verificar si hay errores. Estas dos últimas funciones se describen arriba en la descripción de los controladores. Aparte de eso, el código es prácticamente el mismo que para el ATtiny2313. DEBUG funciona igual también si quieres experimentar con eso.

Paso 6: uso de la memoria I2C

Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C
Uso de la memoria I2C

Ahora que hemos aprendido a usar el bus I2C para leer y escribir un expansor de puerto de E / S, pasemos al uso de memorias I2C, tanto RAM como EEPROM. La principal diferencia es que se pueden leer o escribir varios bytes desde las memorias con un solo comando I2C. Para prepararnos para estos experimentos, necesitamos modificar ligeramente el hardware y construir un par de circuitos nuevos en la placa de pruebas. Conserve el circuito Port Expander ya que lo usaremos para mostrar algunos valores de memoria. Retire los interruptores DIP del PCA8574A y coloque luces intermitentes en esos pines. Si no tiene suficientes luces intermitentes, mueva las de P4 a P7 a P0 a P3. (Los valores que se mostrarán son lo suficientemente pequeños.) Ahora mire el esquema I2C Ram.pdf y conecte el PCF8570 en la placa de pruebas. Echa un vistazo a la foto también. Asegúrese de atar el pin 7 a Vcc. Tienda cables para SDA y SCL desde el PCA8574A. No se requieren resistencias pull-up adicionales. Si también está interesado en la EEPROM, construya ese circuito también usando I2C EEPROM.pdf para el 24C16, pero tenga en cuenta que el ejemplo usa el ATmega168. Este circuito es realmente simple. Como se discutió anteriormente, los bits de dirección deben ignorarse. Simplemente conecte la energía y la tierra. No conecte SDA y SCL todavía, ya que no hemos terminado de experimentar con la Ram. Comenzaremos nuestros experimentos de memoria con el ATtiny2313 conectado al expansor de puerto PCA8574A y al PCF8570 Ram. El programa escribirá algunos números en la RAM, luego los leerá y los mostrará en el expansor de puertos. Cambie su directorio de trabajo a RAM en USI I2C. Utilice el archivo make para compilar y descargar USI_I2C_RAM.c. Tenga en cuenta que los archivos del controlador I2C son idénticos a los que usamos anteriormente. Conecte la alimentación y debería ver un solo parpadeo en el LED 1 (PD6). Los datos se escribirán en los primeros 4 bytes de memoria. Presione el botón y se leerán y mostrarán dos bytes. Debería ver una luz LED en el expansor de puertos (P0), una pausa de dos segundos y luego dos luces LED (P0 y P1). Otra pausa de dos segundos y los LED deberían apagarse. Presione el botón nuevamente para comenzar la secuencia de nuevo. La depuración es similar al método descrito anteriormente. Echemos un vistazo al código. Abra USI_I2C_RAM.c. Debería verse bastante similar al código anterior. Las principales diferencias son los detalles de la lectura y escritura de la memoria. Observe la forma en que se carga el búfer de mensajes antes de la llamada que realmente realiza la escritura. El primer byte es la dirección del esclavo con el bit de lectura / escritura configurado apropiadamente. Pero el siguiente byte es la dirección de memoria en la que comenzar a escribir datos. Luego vienen los bytes de datos reales que se cargarán secuencialmente en la memoria comenzando en la dirección que especificamos. Especificamos el tamaño del mensaje como 6. Entonces comenzamos a escribir en la dirección 00 y escribimos los valores 01, 03, 02 y 06 en las ubicaciones de memoria 00 a 03. Para leer los datos de la memoria debemos usar la función USI_TWI_Start_Random_Read. El búfer de mensajes obtiene la dirección del esclavo en el primer byte y la dirección inicial en el segundo byte. Luego, llame a la función con el tamaño del mensaje establecido en el número de bytes a leer más 2. Tenga en cuenta que el bit de lectura / escritura no importa, ya que la lectura se realizará independientemente. Los datos devueltos comenzarán en la segunda ubicación del búfer de mensajes. Una vez que se leen los datos, se invierten para mostrarlos en el expansor de puertos y se escriben un byte a la vez con una pausa entre los valores. Finalmente, los LED del expansor de puertos se apagan. Las escrituras en el expansor de puertos son idénticas a las que se hicieron en los ejemplos anteriores. Para divertirse, puede descomentar la declaración #define DEBUG como arriba y ver muchos LED parpadeando. Llenos de emoción después de otro experimento exitoso, pasemos al ATmega168 y una EEPROM. Cambie su directorio de trabajo a EEPROM bajo TWI I2C. Utilice el archivo make para compilar y descargar TWI_I2C_EEPROM.c. Tenga en cuenta que los archivos del controlador I2C son idénticos a los que usamos anteriormente para el PCA8574A. Para probar el programa, desconecte el ATtiny2313 y conecte el ATmega168. Deje el bus I2C conectado a la Ram y enciéndalo. Los resultados son diferentes ya que ahora estamos escribiendo y leyendo más datos. El LED 1 del PD7 debe parpadear durante la inicialización. Presione el botón y los datos se leerán de la memoria y se mostrarán. Los LED del PCA8574 deben parpadear en la siguiente secuencia: P1, P0 y P2, (todos apagados), P0 y P1, P1 y P2. Finalmente, todos los LED del puerto deberían apagarse. Presiona el botón nuevamente para repetir esto. Oh, pero espera, dices. ¿No es este programa para la EEPROM? Dado que estamos accediendo a un dispositivo de memoria en la misma dirección I2C, el mismo programa funciona tanto para la Ram como para la EEPROM. Apague y mueva SDA y SCL de la RAM a la EEPROM y ejecute el programa nuevamente. Debería funcionar exactamente igual. Tenga en cuenta que la EEPROM y la RAM no se pueden conectar al bus I2C al mismo tiempo, ya que comparten la misma dirección. (Los más inteligentes entre ustedes pueden considerar cambiar los bits de dirección programables en el Ram, pero eso aún no funcionará. El 24C16 usa todo el bloque de direcciones que se pueden programar para el Ram.) Bien, veamos este último programa. Abra TWI_I2C_EEPROM.c. Lo primero que debe notar es que he indicado cómo abordar la EEPROM 24C16 completa. Se puede acceder a él en bloques de 256 bytes en 8 direcciones esclavas I2C diferentes. Vea cómo MEMORY_ADDR se define como la dirección inicial en 50 hexadecimal; por eso funcionó el Ram. Si desea acceder a otros bloques del 24C16, utilice las otras direcciones como he indicado. Eche un vistazo a cómo configuro para escribir en la memoria. Primero, la dirección del esclavo con el bit de lectura / escritura establecido se coloca en el búfer, luego la dirección inicial de 00, luego 16 bytes de datos. Se llama a la función TWI_Start_Read_Write para escribir los datos (como antes) con el tamaño del mensaje establecido en 18. Cuando se presiona el botón, usamos TWI_Start_Random_Read y TWI_Read_Data_From_Buffer para volver a leer los datos. Cada tercer byte se muestra en los LED del expansor de puerto. Finalmente, los LED se apagan para esperar la próxima pulsación del botón. Quizás se pregunte por qué elegí escribir 16 bytes. Si lee la hoja de datos con atención, verá que el 24C16 realiza un ciclo de escritura cada vez que recibe 16 bytes, incluso si se envían más bytes. Así que parecía un buen número para usar. Si elige aumentar esto, tendrá que cambiar el tamaño de MESSAGEBUF_SIZE. También deberá cambiar el valor TWI_BUFFER_SIZE en TWI_Master.h. Esto se debe a que el controlador copia los datos del búfer de mensajes para que los utilice la rutina del servicio de interrupción. ¡Felicidades! ¡Ahora está listo para usar el bus I2C en sus propios proyectos!

Paso 7: recursos web

Aquí están los enlaces a las hojas de datos de las piezas utilizadas para los experimentos. Definitivamente debería obtener estos si no obtiene nada más. Port ExpanderRamEEPROMSiendo el creador de I2C, NXP (Philips) tiene un montón de cosas geniales. (Les gusta usar corchetes en sus URL, por lo que no puedo incluirlos correctamente aquí. Lo siento.) Para acceder al área I2C, seleccione Interfaz en la lista Productos. Podrá acceder a su sitio I2C y acceso a todas las hojas de datos y notas de aplicaciones que ofrecen. La descripción del bus I2C y los detalles técnicos en particular están aquí. Obtenga las hojas de datos de ATtiny2313 y ATmega168 (¿libros de datos?) de Atmel. Las notas de aplicación de Atmel están aquí. Consulte AVR310 y AVR315. Agarra el código también. Echa un vistazo aquí para ver muchas más cosas de I2C.

Paso 8: Notas para geeks

Para el verdadero geek que quiere conocer los detalles, aquí hay algunas cosas que debe tener en cuenta si observa las notas de las aplicaciones de Atmel y el código del controlador: - ¡El método de direccionamiento y comando de un dispositivo I2C no es parte de la especificación! Aparte de la dirección del esclavo y el bit de lectura / escritura, los comandos, modos, etc. no se especifican y son específicos de un dispositivo determinado. Para dejar esto muy claro, tenga en cuenta que el esquema utilizado en el ejemplo de Atmel solo se aplica a ese ejemplo, y prácticamente no es estándar. La implementación de USI difiere de la implementación de TWI en algunas formas importantes. + Con USI, el reloj es proporcionado por software; con TWI es proporcionado por un generador de tasa de bits. + El método USI no usa interrupciones; el TWI lo hace. Esto tiene cierto sentido, ya que la familia Mega (usando TWI) podría estar haciendo muchas otras cosas y no debería ser acaparada por transferencias I2C. Una versión impulsada por interrupciones para USI es ciertamente posible, simplemente no está implementada en este Instructable. + El hardware USI no está optimizado para I2C y solo puede manejar transferencias de 8 bits. Esto significa que se requieren dos transferencias para enviar el noveno bit (ya sea NACK o ACK). El hardware TWI maneja esto automáticamente. Esto hace que la implementación del controlador USI sea un poco más complicada. + La detección de errores para el TWI se maneja en hardware. La USI requiere manejo en software que complica un poco las cosas. + El hardware TWI controla la configuración del puerto directamente. El hardware USI requiere que los bits del puerto se configuren antes de que se pueda usar el puerto. Verá esto en la rutina Master_Initialize para la USI.- Atmel afirma que es posible usar pull-ups de puerto AVR para los pull-ups de bus I2C. No he descubierto una manera de hacer que ese enfoque funcione. Usar dos resistencias externas parece un esquema bastante simple, por lo que no dediqué mucho tiempo a esto.

Recomendado: