es es en es es gl es es en es hbs_lat es es es es es es es es es es es es es en es es es en es es es en es es en pt es es es es it es es en ko es es es es es es en it es es en it es es es es es es es es en ko es es es en es en es en es es en es en en ceb la en de es es en en la es en es es es es en es km es es en uk km en en en es ru kn kn es en fr en es en kn km es en es es es pt en ja en pt zh en en es en it es es en it es pt en it es en en es es es en it es es es es en es es es en es es es es es fr en es es it en es en en en en en es es pt it es es es pt it es pt it es es es es es pt es es es es pt it es es es es es es es en es es es es es es gl es es hbs_lat es es es
La comunicación I2C es muy útil a la hora de comunicarse con dispositivos de un mismo circuito. Con esta entrada quiero dar un poco de luz a este protocolo que pese a su sencillez es un auténtico misterio a la hora de implementarlo.
Cabe destacar que, atendiendo a la definición del protocolo, la dirección del slave es de 7 bits (del bit 7 al 1). De esta manera el bit 0 se utiliza para decirle al slave si el master quiere leer (bit 0 = 1) o quiere escribir (bit 0 = 1). Es por eso que en el código se utilizan dos direcciones diferentes en función de si se quiere leer o escribir.
El master escribe continuamente “Saludos desde el Master” y después lee 23 bytes del Slave, que devuelve “Por el Slave todo bien”.
Para poder cambiar el número de bytes para leer o escribir desde el master hay que cambiar las variables n_read y n_write. (Si sabéis de algún método mejor, soy todo oídos). La implementación utiliza el propio hardware del PIC (en este caso el PIC16F877) aunque se podría haber hecho mediante software y haber utilizado cualquier pin del procesador. En este caso habría que añadir la opción FORCE_SW en la inicialización del I2C.
NOTA: Solo se puede implementar I2C por software para el master. Para el Slave debe de ser forzosamente hardware.
El código para el master es:
El Slave lo único que hace es gestionar la llegada de paquetes I2C, tanto de escritura como de lectura. Para entender un poco más el código recomiendo leer la documentación del PIC C Compiler (CCS) (pulsando F1), donde explica con detalle las diferentes funciones que se utilizan.
Faltan añadir algunas mejores en el Slave para recibir un número flexible de bytes. Ahora solo imprime los datos por consola (RS232) cuando se envían el número exacto de bytes descritos en max_written.
El código del Slave es:
El código ha sido depurado y probado utilizando Proteus 8, así que os aseguro que el código funciona, aunque si vais a copiar y pegarlo, os recomiendo que os hagáis vuestra propia cabecera y solo copiéis las funciones.
10 junio 202212 junio 2022 rubensm
Transistor implementation of Schmitt trigger
6 abril 202213 abril 2022 rubensm
Anterior: Filtro paso banda activo con realimentación multiple
Siguiente: Servidor SQL con Raspberry Pi solo accesible desde área local con conectividad a Microsoft Access
12 comentarios en «I2C en PIC utilizando CCS como master y slave»
29 noviembre 2016 a las 17:23
Saludos, excelente trabajo, me preguntaba ¿Es posible cambiar de master a esclavo o de esclavo a master en tiempo de ejecución? suponiendo que durante el programa el dispositivo debe funcionar un tiempo como esclavo y otro como master, gracias por compartir!
29 noviembre 2016 a las 22:27
Gracias por tu comentario. Me alegro que pueda serte de ayuda.
En cuanto al cambio dinámico entre máster y slave, nunca lo he probado y desconozco si es posible. Todo es cuestión de ir al datasheet del micro en cuestión y ver si una vez el programa está corriendo te deja cambiar los valores del registro que habilitan las funciones hardware de máster o de slave.
De todas maneras, y aunque fuese posible, la sincronización de ambos microcontroladores te va a complicar mucho el código. Por lo que yo te recomiendo que decidas cuál de los dos va a ser el máster y que crees una rutina en el máster para monitorizar el estado del slave. De esta manera podrás saber cuándo el slave tiene datos que enviar al slave y no será necesario cambiar los roles, que es algo que no es nada habitual en un protocolo como I2C.
Si de verdad necesitas una comunicación half-duplex te recomendaría que buscases otro protocolo de comunicación. Aunque en el entorno embebido SPI, I2C y Serial son los que se utiliza en el 99% de los casos y suelen ser suficientes para la mayor parte de aplicaciones.
8 enero 2018 a las 20:55
Si se puede, se llama modo multimaster… Búscalo en la ayuda de ccs… suerte
4 enero 2017 a las 21:11
cuando defines writeBuffer, que código estas usando dentro del mismo, ya que no se como puedes escribir «Por el Slave todo bien» con ese código.
Y por otro lado, donde está el mensaje «Saludos desde el Master» en el código que no lo puedo ver?
4 enero 2017 a las 21:35
En C para definir un char y asignarlo se hace de la siguiente manera:
char c = 'A';
También se puede hacer del siguiente modo:
char c = 0x41;
char c = 65;
y esto es porque un char en C no es más que un número. Existe un estándar de codificación llamado ASCII en el que cada letra se codifica como un número (ya sea en formato decimal o hexadecimal) y es el que utiliza C para imprimir un carácter. Puedes ver una tabla de equivalencias en este enlace.
Cuando definí el vector writeBuffer, por ejemplo en el slave, hice lo siguiente:
int writeBuffer[] = {0x50,0x6F,0x72,0x20,0x65,0x6C,0x20,0x53,0x6C,0x61,0x76,0x65,0x20,0x74,0x6F,0x64,0x6F,0x20,0x62,0x69,0x65,0x6E};
En este vector cada número hexadecimal corresponde a un carácter como puedes comprobar:
Espero que haya aclarado tu duda.
19 febrero 2017 a las 16:59
Lo primero es agradecer por tu gran trabajo, ha sido de mucha utilidad.
Por otra parte he encontrado un detalle en tu código y lo he modificado un poco para obtener exactamente el resultado esperado.
Al aplicar tu codigo directamente sobre mis uControladores pic16f886 (haciendo previamente el reemplazo de los operadores « » por respectivamente), he notado una discrepancia en los datos impresos por el Master vía UART. La diferencia es que el terminal (Realterm) musetra que el primer Byte es un «ETB» y los siguientes entregan el mensaje esperado. Lo anterior descrito puede ser visto en la siguiente imagen.
Pues esperaba que algo así pasara ya que el mensaje que envia el Slave en respuesta a la solicitud del Maestro contiene 22 Bytes y no 23 como se definió en ambas partes.
Para solucionar este Byte indeseado hice modificaciones leves que se muestran a continuación.
– «int n_read=23;» se cambia por «int n_read=22;»
– if(state >= 0x80){ //Master is waiting for data
if ((state-0x80) == max_written){
La rutina anterior la he reemplazado por la siguiente. Dado que se sabe el largo exacto del arreglo que contiene la frase a enviar me pareció mejor usar un ciclo «FOR».
delay_us(2); // Este delay le da tiempo a que acabe y se estabilice la instrucción
Con las modificaciones anteriormente mencionadas el resultado es el siguiente.
Espero ver mas de tu trabajo pronto, muchas gracias 🙂
– MPLAB X IDE v3.51
– CCS compiler v5.015
Si es necesario puedo compartir también los codigos fuente.
22 mayo 2017 a las 22:32
podrias compartirlo por favor
13 agosto 2018 a las 14:47
Olá, já algum tempo estou tentando elaborar uma saída de pulsos do contador up/down. A saída deve ser por I2C e a cada mudança de contagem, deve ser transmitido os pulsos binários referente a contagem. Ejemplo: Parei a contagem em «1250», então o último trem de pulsos pelo barramento I2C foi «10011100010», se o numero do display for «8955» os pulsos em binário foi de «10001011111011» e assim por diante. Possuo o contador com display de 7 segmentos, mas preciso montar essa parte do código I2C que faz a saída da contagem em binário. O projeto é compilado por CCS C Compiler.
13 agosto 2018 a las 14:53
Hello, for some time I am trying to elaborate an output of counter pulses up / down. The output must be by I2C and with each count change, the binary pulses referring to the count must be transmitted. Example: I stopped the count at «1250», then the last pulse train on the I2C bus was «10011100010», if the display number was «8955» the torque pulses was «10001011111011» and so on. I have the counter with 7-segment display, but I need to mount that part of the I2C code that outputs the count in binary. The project is compiled by CCS C Compiler.
Raziel Israel Escamilla Zepeda dice:
7 octubre 2018 a las 00:49
Si no requiero utilizar la comunicacion serial, únicamente omito los printf´s y el SPI ¿verdad?
27 noviembre 2018 a las 13:25
me gustaría saber como podria leer por ejemplo, el puerto adc en una vez convertido a float( es decir ya la tension, si fuese temperatura) en el slave desde el master.
Juan Diego Osorio Plaza dice:
29 enero 2019 a las 01:02
Muchas gracias por su código Ing. Rubén Sánchez, me sirvió como referencia para terminar el mío y solucionar el problema.