martes, 2 de julio de 2024

I2C Comunicacion Maestro Esclavo PIC16F

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)
Un aspecto interesante de este bus, es que el protocolo I2C incorpora el proceso de direccionamiento Maestro-Esclavo por software, es decir que la conexión lógica entre dos dispositivos se determina por un campo de informacion de direccionamiento que se envía al inicio de la comunicación. Los microcontroladores que disponen de este recurso establecen la señalización de manera automática, y en el caso de no contar con este recurso también es posible implementarlo mediante software.

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:

Para nuestro caso practico estos bits mantendrán los siguientes valores: modo esclavo de 7-bits SSPM=0110 y modo maestro SSPM=1000
  • 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
Si el maestro quiere recibir informacion del esclavo, recordemos que únicamente el maestro es quien establece la comunicación I2C, por lo tanto para recibir un dato del esclavo, el maestro puede establecer el siguiente protocolo de comunicación:

Fig4. Maestro recibe dato del Esclavo
Puesto que se trata de una comunicación bidireccional donde el maestro debe enviar datos del estado en sus entradas al esclavo y mostrar en sus salidas los niveles lógicos que tienen las entradas del esclavo, es posible que el maestro establezca este intercambio con el siguiente protocolo.

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; 

<Usos del TMRO>

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
Una vez cargado el programa correspondiente a cada PIC16F, notara que en ambos PIC16F887 empieza a destellar el LED una vez por segundo, esto indica que el programa se encuentra en funcionamiento normal. También observara que los cuatro LED de salida están activados, cuando los conmutadores no están cerrados, esta lógica obedece al hecho de que las entradas conectadas al los pines del PORTB RB4:RB7 tienen las entradas con resistencias pull-up activadas, entonces al presionar o cerrar el conmutador el nivel logico recién cambia a 0.
 

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.

También de dejo vídeo donde explico como abrir el proyecto MPLABX y compilar con otro PIC diferente al utilizado. 

Sin mas que mencionar agradezco tu visita al blog y espero que el ejemplo que trabajamos pueda ser útil en tu formación y el proyecto que desarrollas.
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