Comunicación Maestro Esclavo PIC16F
Este sitio fue creado para compartir el mutuo interés en la electrónica y en especial la programación de microcontroladores PIC. Agradecido por visitar mi blog te quiero recordar que estoy atento a critica constructiva relacionada con esta publicación.
En esta ocasión veremos como hacer uso del modulo MSSP para implementar una comunicaciones bidireccional entre dos PIC16F utilizando el protocolo I2C, y que nos servirá para aplicar esta comunicación a diversos dispositivos y/o sensores que hacen uso de esta interfaz.
La programación se realizara utilizando MPLABX y el compilador XC8 ambos disponibles en la pagina de microchip. Aquí dejo los enlaces de las versiones utilizadas para nuestro ejemplo: <<MPLABX v6.20>> <<XC8 v2.45>>
Mencionar también que es necesario contar con conocimientos mínimos sobre programación en lenguaje C y el uso de microcontroladores PIC16.Introducción al Tema
I2C es un protocolo de comunicación síncrono que posibilita la interconexión de múltiples de dispositivos mediante un bus común, conformado por dos lineas de conexión, una del tipo bidireccional para los datos (SDA) y una linea de sincronismo para el reloj (SCL), tal como se observa en la figura 1.
![]() |
Fig1. Bus I2C (Wikipedia) |
Antes de continuar, es importante saber que existe bastante informacion relacionado al protocolo I2C en la web y canales de internet, por lo que compartiré un par de enlaces que nos ayudaran con la introducción:
Con esta lectura daremos por hecho que sabemos como funciona I2C, y estamos con la necesidad de utilizar esta interfaz en algún proyecto electrónico, en este caso utilizaremos un microcontrolador PIC16F que disponga del modulo MSSP.
Modulo Serial SSP/MSSP
Es importante mencionar que los microcontroladores PIC de 8-bit con capacidad de comunicación I2C disponen de unos los siguientes módulos:
- MSSP (Master Synchronous Serial Port): Este modulo posibilita la comunicación I2C en modo maestro y esclavo, soportando por hardware toda la señalización necesaria para I2C.
- SSP (Synchronous Serial Port): Posibilita la comunicación I2C en modo esclavo, y provee señalización de inicio y parada para la implementación del modo maestro mediante software.
Dado que el modulo MSSP es un recurso mas completo que el SSP, nos centraremos en su configuracion tomando como referencia el microcontrolador PIC16F887. En la hoja de datos del PIC16F887 encontrara el diagramas de bloque del modulo MSSP- I2C para la operación en ambos modos Maestro y Esclavo. siendo los siguientes registros de memoria utilizados para implementar esta comunicación:
- SSPSR (Registro de desplazamiento temporal): Este no registro no es directamente accesible, y su función es recuperar o enviar en serie los bits que conforman el dato.
- SSPBUF (Registro de dato): Contiene el dato según el caso. si se trata de una recepción, los bits recibidos en el registro SSPSR se cargan a SSPBUF para su lectura, y en el caso de una transmisión, el dato que contiene SSPBUF se carga al registro SSPSR para enviar los bits.
- SSPADD (Registro para Dirección o Contador): En modo esclavo, este registro sirve para establecer una dirección de 7 bits del protocolo I2C, y en modo maestro con este registro es posible configurar la frecuencia del reloj de acuerdo a la siguiente relación: Fi2clk = Fosc/(4*(SSPADD+1))
- SSPSTAT (Registro de estado). Únicamente el bit SMP deberá ser ajustado dependiendo de la frecuencia utilizada para el reloj, los valores predeterminados para este fin son SMP=1 para 100Khz./1MHz y SMP=0 para 400KHz. Los bits de lectura D/A, P, S, R/W, UA y BF son utilizando para indicar el estado de la señalización durante la comunicación.
- SSPCON1 (Registro de configuracion 1):
Los bits de este registro establecen la siguiente configuracion del modulo; WCOL y SSPOV indican el estado de colisión o desbordamiento en el bus, este estado requiere restablecimiento de la funcionalidad; El bit SSPEN habilita la operación del modulo; El bit CKP en modo esclavo permite controlar la liberación del reloj(clock streetch), y finalmente los cuatro bits SSPM:3:0 determinan los siguientes modos de operación:
- SSPCON2: Registro de configuracion 2
Los bits de este registro son utilizados en el modo maestro para establecer la señalización necesaria durante la comunicación I2C, la manipulación de estos se dan dentro de las funciones que posee la librería i2c.
Configuración MSSP modo Maestro
Los aspectos importantes a considerar en un dispositivo maestro, es este provee la señal del reloj en el pin SCL, por lo que es necesario configurarlo, además el maestro es responsable del direccionamiento a los dispositivos esclavos conectados al bus, y por lo tanto debe asegurarse un nivel logico para el estado de reposo, para este fin se agregan unas resistencias pull-up a las lineas SDA y SCL.
La configuracion de los pines asociados a SDA y SCL se establecen de manera automática al configurar y habilitar el modulo MSSP como maestro.
Consideraremos como ejemplo de configuracion del siguiente código, un dispositivo I2C maestro con frecuencia de 100KHz, y donde la frecuencia de oscilación del PIC16F887 sera de 8MHz.
/*MSSP MODO I2C MASTER Fosc=8MHz -> rate=100KHz*/
SSPSTATbits.SMP = 1; //Slew rate 1=off(100KHz/1MHz) 0=On(400KHz)
SSPADD = 19; //[Fosc/(4 * rate)]-1 para 100KHz
SSPCONbits.SSPM = 0b1000; //Fosc/(4*(SPADD+1))
SSPCONbits.SSPEN = 1; //Activa el modulo MSSP
Configuración MSSP modo Esclavo
En un dispositivo esclavo, se debe considerar que este posee un dirección única de 7 bits entre los demás dispositivos conectados al bus I2C, aunque es posible el direccionamiento a 10 bits, este modo no se tratara en nuestro caso.
En el modo esclavo el modulo MSSP del PIC16F887 requiere que los pines asociados a SDA y SCL estén configurados como entradas digitales. Además debido que el inicio de la comunicación es establecida por el dispositivo maestro, es importante que la notificación de este evento se apoye en la bandera de interrupción SSPIF. En esta caso la funcionalidad del la comunicación I2C se establecerá dentro de la rutina de interrupción ISR.
/*MSSP MODO I2C SLAVE Fosc=8MHz -> rate=100KHz*/
TRISCbits.TRISC3 = 1; //SCL configura el pin como entrada
TRISCbits.TRISC4 = 1; //SDA configura el pin como entrada
SSPSTATbits.SMP = 1; //Slew rate 1=off(100KHz/1MHz) 0=On(400KHz)
SSPADD = I2CADDR; //Direccion del esclavo SPADD[7:1]
SSPCONbits.SSPM = 0b0110; //Modo esclavo a 7-bit
SSPCONbits.CKP = 1; //0=Hold clock low 1=Release Clock
SSPCONbits.SSPEN = 1; //Activa el modulo MSSP
PIR1bits.SSPIF = 0; //Limpia la bandera de evento I2C
PIE1bits.SSPIE = 1; //Activa la interrupcion del evento I2C
Esquema de Circuito
Se describe el esquema del circuito que se utilizara para desmostar la comunicación I2C Maestro-Esclavo entre los microcontroladores PIC16F887.
![]() |
Fig2. Circuito de prueba Maestro-Esclavo PIC16F |
El circuito que se ilustra en la figura 2, muestra la interconexión de ambos microcontroladores PIC16F al bus I2C mediante los pines SDA y SCL, donde las resistencias pull-up aseguran un nivel logico del bus en estado de reposo.
Cada PIC16F posee cuatro diodos LED conectados a los pines de salida RB0:RB3 y cuatro conmutadores a los pines de entrada RB4:RB7 del PORTB, adicionalmente hay un diodo LED conectado al pin RE2, que sirve para indicar actividad del programa mediante un destello.
A fines de una mejor comprensión del esquema, el PIC16F de la izquierda sera el Maestro y el PIC16F de la derecha el Esclavo, por lo tanto el funcionamiento del circuito sera el siguiente: Se establece en ambos una comunicación bidireccional utilizando I2C de tal manera que el PIC maestro muestra a través de los LED conectados a su salida el nivel logico que tienen los conmutadores del PIC esclavo y así mismo los niveles lógicos en los conmutadores del PIC maestro se mostraran en los LED del PIC esclavo.
Como se menciono mas arribe, en ambos PIC16F el LED del pin RE2 destellara cada segundo para indicar actividad en sus respectivos programas.
La dirección del dispositivo esclavo se establecerá en 0x3E, por lo tanto si el Maestro quiere enviar informacion al Esclavo deberá establecer el siguiente protocolo de comunicación:
![]() |
Fig3. Maestro envía dato al Esclavo |
![]() |
Fig4. Maestro recibe dato del Esclavo |
![]() |
Fig5. Maestro envía y recibe dato del Esclavo |
Utilizaremos el ultimo caso, considerando un intervalo de 200ms entre cada comunicación o dialogo I2C entre ambos PIC16F, los intervalos estarán apoyados con las interrupciones del temporizador TMR0. Si deseas conocer como configurar este modulo, te recomiendo revisar la siguiente entrada;
Programación del PIC16F887
Seguidamente se detalla parte del código del programa que se utiliza en ambos PIC16F, se comentara según el caso que instrucción corresponde al Maestro y al Esclavo. Mas abajo se dejan los enlaces para que pueda descargar el código completo del proyecto en MPLABx.
#include <xc.h>
#include <stdint.h>
#include "i2c.h"
#define LEDpin PORTEbits.RE2
#define I2CADDR 0x7E //Dirección 7-bit I2C 0111-111x (3Eh)
typedef struct //Estructura de Puerto
{
unsigned OUTpins :4;//Salida LEDS
unsigned INPpins :4;//Entrada Conmutadores
} PORTstruct_t;
volatile PORTstruct_t PORT __at(0x006); //Asocia al PORTB
volatile uint8_t tick1ms = 0; //Bandera 1ms
uint16_t cntms = 0; //Contador de ms
uint8_t i2cdata = 0; //dato i2c
void setupMCU(void); //Procedimiento de configuracion
void taskLED(void); //Procedimiento destello LED RE2
void taskI2C(void); //Procedimiento comunicación Maestro
void main(void) //Programa principal
{
setupMCU(); //Configuración del PIC16F
while(1) //Bucle indefinido del programa
{
if(tick1ms) //bucle Intervalo 0.001seg
{
tick1ms = 0;
taskLED(); //Tarea destellar LED
taskI2C(); //Comunicación I2C, solo en modo maestro
}
}
}
void setupMCU(void) //Configuración del PIC
{
OSCCONbits.IRCF = 0b111; //Fosc=8MHz Tcy=0.5uS Oscilador RC
while(OSCCONbits.HTS == 0){}; //Espera
ANSEL = 0; //Desactiva los puertos AN0 al AN7
ANSELH = 0; //Desactiva los puertos AN8 al AN13
TRISB = 0xF0;//Pines RB0-RB3 salidas y RB4-RB7 entradas
PORTB = 0x00; //Salidas PORTB en nivel 0
TRISEbits.TRISE2 = 0; //Pin de salida LED
PORTEbits.RE2 = 0; //Salida del pin en nivel 0
OPTION_REGbits.nRBPU = 0; //Activa pull-ups entradas PORTB
PORT.OUTpins = 0; //Establece en 0 las salidas
/*CONFIGURACION TIMER0 1MS Fosc=8Mhz*/
OPTION_REGbits.T0CS = 0;//Modo Termporizador
OPTION_REGbits.PSA = 0; //Con prescala
OPTION_REGbits.PS = 0b011; //Prescala 1:16
TMR0 = 131; //256-(time/((pre)*(4/Fosc))) time=0.001 seg
INTCONbits.T0IF = 0; //Limpia bandera
INTCONbits.T0IE = 1; //Activa interrupción del TMR0
/*CONFIGURACION MSSP MODO I2C MASTER Fosc=8MHz -> rate=100KHz*/
Codigo de la configuracion en modo Maestro
/*MSSP MODO I2C SLAVE Fosc=8MHz -> rate=100KHz*/
Codigo de la configuracion en modo Esclavo
/*CONFIGURA INTERRUPCIONES*/
INTCONbits.GIE = 1;
}
Código del Maestro
Aquí se describen las instrucciones del procedimiento taskI2C utilizado en el programa del dispositivo Maestro, note que este código es llamada a un intervalo de 0.001 segundo, pero al utilizar un contador cnt vera que la comunicación ocurre cada 200 llamadas al procedimiento, esto es 5 veces por segundo.
void taskI2C(void) //Cada 1ms
{
static uint16_t cnt = 0;
if(cnt++ > 199) //Actualiza I2C cada 200ms
{
//I2C Protocol <S><ADDR><W><PORTOUT><R><ADDR><R><PORTIN>
i2cdata = PORT.INPpins; //Carga dato con valores de RB4:RB7
I2CIdle(); //Espera a que el bus este en modo reposo
I2CStart(); //Inicia la comunicación
I2CWrite(I2CADDR); //Direcciona al esclavo para escritura RW=0
I2CWrite(i2cdata); //Envia el dato al esclavo
I2CRestart(); //Reiniciar la comunicación
I2CWrite(I2CADDR | 0x01); //Direcciona al esclavo para lectura
i2cdata = I2CRead(); //Carga el dato recibido del esclavo
I2CNotAck(); //Señaliza el no-reconocimiento para indicar final
I2CStop(); //Finaliza la comunicación
PORT.OUTpins = i2cdata; //Establece los LEDS con el dato recibido
cnt = 0;
}
}
Código del Esclavo
Ahora describiremos el código de comunicación correspondiente al dispositivo Esclavo, donde se denota que el código que maneja la comunicación I2C se encuentran dentro de la rutina de atención a la interrupción ISR, por lo tanto el proceso de atención se da con el evento SSPIF, que indica la presencia de un dato o dirección recibido desde el maestro.
void __interrupt() isr(void)
{
if(PIR1bits.SSPIF) //Evento que ocurre en el Receptor
{
PIR1bits.SSPIF = 0; //Limpia la bandera de interrupción
i2cdata = I2CSlaveRead(); //Lectura del byte recibido
if((!SSPSTATbits.R_nW) && SSPSTATbits.D_nA)//Si un dato es recibido
PORT.OUTpins = i2cdata; //Establece RB0:RB3 con el valor del dato
if(SSPSTATbits.R_nW && (!SSPSTATbits.D_nA))//Si un dato es solicitado
{
i2cdata = PORT.INPpins; //Carga el dato con el valor de RB4:RB7
I2CSlaveWrite(i2cdata);//Envía el dato al maestro
}
}
}
Pruebas de comunicación
![]() |
Fig6. Montaje del circuito con dos PIC16F |
Conclusiones
Se verifico correctamente la comunicación I2C entre los microcontroladores PIC16F887, haciendo uso de sus respectivos módulos MSSP, cumpliendo así con el objetivo de esta publicación, si
bien las características de I2C van mas allá de los descrito en esta sección, aspectos como el direccionamiento de 10-bit, el modo multi-maestro, el evento de llamada general, etc. El ejemplo que vimos representa la mayoría de los casos de uso con microcontroladores.
Aquí dejo
los enlaces para que puedas descargar el proyecto MPLABX, mismo que se encuentra comprimidos en gzip.
Atte. Pablo Zárate Arancibia
email: pablinza@me.com / pablinzte@gmail.com, @pablinzar
Santa Cruz de la Sierra - Bolivia
No hay comentarios.:
Publicar un comentario