No funciona la conexión I2C de PIC con EEPROM

Intento guardar en la posición 1928 de una EEPROM el valor de 208, y luego leer esa misma posición para escribir en una pantalla lcd su valor, así que el lcd debería mostrar "208", pero muestra "7"(que sería el valor en decimal del byte alto del valor de la posición es decir el 1928 el cual en binario sería: 111 1000 1000)

Cuando cargo el registro SSPADD con el valor de 9, el lcd no muestra 7 sino 136, y estando el SSPADD cargado con 4, si habilito los 2 if que están comentados en el código, el lcd muestra 161.

Cuando hago la simulacion en proteus, el error que muestra 7 veces es:
"Data written SSPBUF whilst MSSP(in I2C master mode) is active-data has been ignored"

Estoy usando el compilador PICC, y sé que este tiene sus funciones para la conexion I2C, de hecho ya lo hice de esa manera y me funcionó, pero esta vez lo quiero hacer sin el uso de esas funciones.

Agradezco cualquier opinion, gracias.

Este es el código:

#INT_SSP
void inti2c(){

sspif==0;
}

long int dir=1928;
void main(){

TRISC = 0b10011000;
PORTC = 0x00;
SSPSTAT = 0b00000000;
SSPCON = 0b00101000; //modo master; habilita el modulo ssp
SSPCON2 = 0x00;
SSPADD = 4; //baud rate 100kHZ
INTCON = 0b11000000;
PIE1 = 1; //habilita int. por ssp
lcd_init();

/********************************************************************/
/****************************ESCRITURA*******************************/
/********************************************************************/

sen = 1; //condicion start.
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa0; //carga el registro con la dir. del esclavo en modo escritura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir>>8; //direccion a escribir de la eeprom (parte alta)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir; //direccion a escribir de la eeprom (parte baja)
//if(ack==1)PORTC_5 = 1;
//if(ack==0)PORTC_1 = 1;
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = 208; //dato a escribir
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
pen = 1; //condicion stop.
while(sspif==1); //espera a que el stop termine.


/********************************************************************/
/****************************LECTURA*********************************/
/********************************************************************/

sen = 1; //condicion start.
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa0; //carga el registro con la dir. del esclavo en modo escritura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir>>8; //direccion a escribir de la eeprom (parte alta)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir; //direccion a escribir de la eeprom (parte baja)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
SSPCON2 = 0b00001010; //habilita modo recepcion y start repetido
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa1; //carga el registro con la dir. del esclavo en modo lectura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
printf(lcd_putc,"%u",sspbuf);
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
pen = 1; //condicion stop.
while(sspif==1); //espera a que el stop termine.

while(1);
}
 
C:
#INT_SSP
void inti2c(){

sspif==0;
}

long int dir=1928;
void main(){

TRISC = 0b10011000;
PORTC = 0x00;
SSPSTAT = 0b00000000;
SSPCON = 0b00101000; //modo master; habilita el modulo ssp
SSPCON2 = 0x00;
SSPADD = 4; //baud rate 100kHZ
INTCON = 0b11000000;
PIE1 = 1; //habilita int. por ssp
lcd_init();

/********************************************************************/
/****************************ESCRITURA*******************************/
/********************************************************************/

sen = 1; //condicion start.
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa0; //carga el registro con la dir. del esclavo en modo escritura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir>>8; //direccion a escribir de la eeprom (parte alta)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir; //direccion a escribir de la eeprom (parte baja)
//if(ack==1)PORTC_5 = 1;
//if(ack==0)PORTC_1 = 1;
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = 208; //dato a escribir
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
pen = 1; //condicion stop.
while(sspif==1); //espera a que el stop termine.


/********************************************************************/
/****************************LECTURA*********************************/
/********************************************************************/

sen = 1; //condicion start.
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa0; //carga el registro con la dir. del esclavo en modo escritura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir>>8; //direccion a escribir de la eeprom (parte alta)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
sspbuf = dir; //direccion a escribir de la eeprom (parte baja)
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
SSPCON2 = 0b00001010; //habilita modo recepcion y start repetido
while(sspif==1); //espera a que start termine.

/********************************************************************/
sspbuf = 0xa1; //carga el registro con la dir. del esclavo en modo lectura
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
printf(lcd_putc,"%u",sspbuf);
while(sspif==1); //espera a que el dato sea recibido.

/********************************************************************/
pen = 1; //condicion stop.
while(sspif==1); //espera a que el stop termine.

while(1);
}
El PIC es el 16F877 y la EEPROM es la M24512

Gracias
 
Estoy tratando de comunicar por protocolo I2C un pic 16f876(maestro) con un reloj DS1307(esclavo), para tomar el tiempo(los segundos, minutos y horas) del reloj y que esa información de tiempo se muestre en un lcd.

Cuando ejecuto la animación en proteus, la primera vez que tomo el tiempo del reloj todo funciona bien y el lcd muestra la información, pero la segunda vez que tomo el tiempo el I2C debuger de proteus muestra que se generaron algunos bits Noack y el lcd no muestra la información correcta.

Como se puede corregir esto?

Adjunto la imagen donde se ve la información del I2C debugger del proteus.
Y aquí esta el código:

C:
#include<16F876.h>
#fuses XT,NOWDT,NOLVP
#use delay (crystal=4MHz)

#include<lcd.c>
#define LCD_DATA_PORT getenv("SFR:PORTB")

long int dir, i;
char lectura;
int sec, min, hor;

#INT_SSP //vector de interrupción
void inti2c(){
        
}

int bcdabin(int bcd){ //conversor BCD a binario
   int varia;
   varia=bcd;
   varia >>= 1;
   varia &= 0x78;
   return(varia + (varia >> 2) + (bcd & 0x0f));
}

void i2c_lectura(){

         SSPCON2 |= (1<<0); //condicion start.       
         delay_ms(10);
              
         sspbuf = 0xD0; //carga el registro con la dir. del esclavo en modo escritura
         delay_ms(10);
                                  
         sspbuf = 0x00; //1ra direccion a leer         
         delay_ms(10);                 
 
         SSPCON2 |= (1<<1); //start repetido
         delay_ms(10);
        
         sspbuf = 0xD1; //Modo lectura
         delay_ms(10);       
        
         SSPCON2 |= (1<<3); //pone el maestro en modo recepción
         delay_ms(10); 
        
         sec = bcdabin(sspbuf & 0x7f);
         SSPCON2 |= (1<<4); //acken
         SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo
         delay_ms(10);
        
         SSPCON2 |= (1<<3); //pone el maestro en modo recepción
         delay_ms(10);
        
         min = bcdabin(sspbuf & 0x7f);
         SSPCON2 |= (1<<4);
         SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo
         delay_ms(10);

         SSPCON2 |= (1<<3); //pone el maestro en modo recepción
         delay_ms(10);

         hor = bcdabin(sspbuf & 0x3f);
         SSPCON2 |= (1<<5); //maestro manda Noack al esclavo
         SSPCON2 |= (1<<4);
         delay_ms(10);
        
         SSPCON2 |= (1<<2); //condicion stop.           
         delay_ms(10);
}

void main(){  
   TRISC = 0b10011000;
   PORTC = 0x00;
   SSPSTAT = 0b10000000;
   SSPCON = 0b00101000; //modo master; habilita el modulo ssp
   SSPCON2 = 0x00;
   SSPADD = 9; //baud rate 100kHZ
   INTCON = 0b11000000;
   PIE1 |=  (1<<3); //habilita int. por ssp
   lcd_init();

   while(1){
         i2c_lectura();
        
         lcd_gotoxy(1,2);
         printf(lcd_putc,"Leyendo: %u",sec);
         delay_ms(250);
        
         lcd_gotoxy(1,2);
         printf(lcd_putc,"Leyendo: %u",min);
         delay_ms(250);
        
         lcd_gotoxy(1,2);
         printf(lcd_putc,"Leyendo: %u",hor);
         delay_ms(250);
                               
   } //cierra while     
}

Gracias.
 

Adjuntos

  • Problema-Noack.JPG
    Problema-Noack.JPG
    73.9 KB · Visitas: 6
¿En que criterio te basas para imponer esos Delays (250) ?
A veces el único problema es la velocidad, es decir el TEMPO
A los programadores se les suele pasar por alto lo tiempos de acceso al chip.
Siempre trabajo con la hoja de datos del fabricante de los chips a mi lado.
Si lo hace bien una vez, es porque básicamente la rutina esta bien, entonces, queda el reposicionamiento a cero para repetir el enlace o que algunos de ambos chips se atraganta con los datos o dicho de otro modo , algo mal en el SINCRONISMO.
Un osciloscopio a menudo ayuda.
( No suelo usar emuladores, me manejo con fierro puro y duro)

La otra pregunta que me hago es ---> ¿ Porque no implementar un reloj dentro del mismo PIC y gastar en un chip RTC ?
Salvo que sea para practicar, la otra razón tiene que ser muy poderosa. :rolleyes: 🥴 🤣
 
Última edición:
¿En que criterio te basas para imponer esos Delays (250) ?
A veces el único problema es la velocidad, es decir el TEMPO
A los programadores se les suele pasar por alto lo tiempos de acceso al chip.
Siempre trabajo con la hoja de datos del fabricante de los chips a mi lado.
Si lo hace bien una vez, es porque básicamente la rutina esta bien, entonces, queda el reposicionamiento a cero para repetir el enlace o que algunos de ambos chips se atraganta con los datos o dicho de otro modo , algo mal en el SINCRONISMO.
Un osciloscopio a menudo ayuda.
( No suelo usar emuladores, me manejo con fierro puro y duro)

La otra pregunta que me hago es ---> ¿ Porque no implementar un reloj dentro del mismo PIC y gastar en un chip RTC ?
Salvo que sea para practicar, la otra razón tiene que ser muy poderosa. :rolleyes: 🥴 🤣
Los delays de 10mS los pongo para darle tiempo a los procesos del protocolo I2C(condición de start/stop, escritura/lectura de datos, start repetido), para asegurarme que cada uno de dichos procesos finalicen antes que empiece el siguiente proceso.

Dices que el problema puede ser falla en la sincronización; ¿como haces para hacer que la sincronización sea correcta?
 
Los delays de 10mS los pongo para darle tiempo a los procesos del protocolo I2C(condición de start/stop, escritura/lectura de datos, start repetido), para asegurarme que cada uno de dichos procesos finalicen antes que empiece el siguiente proceso.

Dices que el problema puede ser falla en la sincronización; ¿como haces para hacer que la sincronización sea correcta?
Cuando hago electrónica, lo básico es osciloscopio doble trazo. lo demas es adivinar.
 
Cuando hago electrónica, lo básico es osciloscopio doble trazo. lo demas es adivinar.
Estuve usando el osciloscopio de proteus para ver los tiempos de cada proceso que realiza el protocolo I2C, pero no encontré ninguna falla en la sincronización, pero en el proceso se me ocurrió hacer un ligero cambio en el código que consistió en invertir estas 2 líneas:

SSPCON2 |= (1<<4); //acken
SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo

quedando así:
SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo
SSPCON2 |= (1<<4); //acken

Ahora funciona OK.
Gracias por tu ayuda (y)
 
Estuve usando el osciloscopio de proteus para ver los tiempos de cada proceso que realiza el protocolo I2C, pero no encontré ninguna falla en la sincronización, pero en el proceso se me ocurrió hacer un ligero cambio en el código que consistió en invertir estas 2 líneas:

SSPCON2 |= (1<<4); //acken
SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo

quedando así:
SSPCON2 &= ~(1<<5); //maestro manda ack al esclavo
SSPCON2 |= (1<<4); //acken

Ahora funciona OK.
Gracias por tu ayuda (y)
Usted disculpe, el osciloscopio de PROTEUS es una emulación de un osciloscopio, no se corresponde con la realidad, es una imitación.
Me refería a uno real, preferentemente analógico. :rolleyes:
Para I2C podría aceptar uno digital, porque es mas fácil para capturar STRINGs de DATOS a memoria y verlos ahí cómodamente, para analizar las secuencias de error o de ACKnowledge
 
Última edición:
Arriba