Problema al realizar la operación de lectura I2C desde ds1307 a pic18F

1

Tal como lo recomendaron mis compañeros apiladores en mi publicación anterior, probé la función "Write_to_slave" en Proteus también en tiempo real, enviando bytes al RTC y el esclavo responde adecuadamente con un bit de confirmación para cada byte que recibe Por lo tanto, la operación de escritura funciona bien. Sin embargo, ahora tengo problemas con mi función "Read_from_slave". El problema es que, durante la secuencia de lectura, hasta el envío de la "Dirección del esclavo + Lectura", es decir, 0xD1, funciona bien y también recibe un acuse de recibo del esclavo, pero el problema surge después de la ejecución de la función I2C_restart. Los datos leídos del SSPBUF o los datos recibidos del esclavo son FF, mientras que los segundos deben contar de 0 a 60 (y se muestra 63 en la pantalla LCD), seguido de un NACK. Y después de enviar el NACK, I2C_stop () debería finalizar la transacción mientras eso no esté sucediendo, como se puede ver en la instantánea de Proteus. A continuación se muestra el código, solo realicé una operación de lectura para leer el registro de segundos para verificar si mi método está funcionando, pero desafortunadamente no:

void Wait_MSSP() 
{
while(SSPIF==0);
SSPIF = 0;
}

void check_ACK_Master_Transmit()
{
if(SSPCON2bits.ACKDT == 0) //If ACKDT is 0, ACK has been recieved 
   arraydisp("ACK success");
   else if (SSPCON2bits.ACKDT == 1) //If ACKDT is 1, ACK has not been recieved
   arraydisp("ACK fail");
}
    unsigned char Read_from_slave(unsigned char addr)
{
    unsigned char x;
    I2C_start();
    SSPBUF = RTC_ADDRW; 
    Wait_MSSP();                            //Slave address+Write
    SSPBUF = addr; 
    Wait_MSSP();                              ////RTC register to be read
    I2C_restart();
    SSPBUF = RTC_ADDRR;
    Wait_MSSP();  
    SSPCON2bits.RCEN = 1;                       //Enable Master to receive data from slave
    x = SSPBUF;                             //Read the SSPBUF
    SSPCON2bits.ACKDT = 1;                     //send NACK after receiving the data
    SSPCON2bits.ACKEN = 1;                    //Enable Acknowledge sequence on SDA and SCL
    I2C_stop();                                //Wait until stop operation is completed
    return(x);
 }
void Write_to_slave(unsigned char addr, unsigned char data)
{
I2C_start();

SSPBUF = RTC_ADDRW; //Slave address + Write
Wait_MSSP();
check_ACK_Master_Transmit(); //Checks the
SSPBUF = addr; // RTC Registor location address to be written
Wait_MSSP();
check_ACK_Master_Transmit();
SSPBUF = data; //data to be writen to the address location
Wait_MSSP();
check_ACK_Master_Transmit();
I2C_stop();
Wait_MSSP();
}

void I2C_write(unsigned char addr)
{
    PIR1bits.SSPIF = 0;
    SSPBUF = addr;
    while(PIR1bits.SSPIF == 0);
    return;
}

void Reset_time()
{
    I2C_start();
    I2C_write(RTC_ADDRW);
    I2C_write(0x00);
    I2C_write(0x00);
    I2C_write(0x00);
    I2C_write(0x01);
    I2C_write(0x01);
    I2C_write(0x01);
    I2C_write(0x01);
    I2C_write(0x00);
    I2C_stop();
    return;
}

void Set_time()
{
    Write_to_slave(0x00,0x00);     //Write data 0x00 to address 00H (Seconds) of RTC (CH = 0)
    Write_to_slave(0x01,0x30);      //Write data  0x00 to address 01H(Minutes) of the RTC
    Write_to_slave(0x02,0x10);      //Write data 0x00 to address 02H(HOUR) of the RTC
    Write_to_slave(0x03,0x06);      //Write data 0x01 to address 03H (DAY) of the RTC
    Write_to_slave(0x04,0x01);      //Write data 0x01 to address 04H (Date) of the RTC
    Write_to_slave(0x05,0x01);      //Write data 0x01 to address 05H (Month) of the RTC
    Write_to_slave(0x06,0x16);      //Write data 0x00 to address 06H (Year) of the RTC
}




   void main()
{
    TRISCbits.TRISC0 = 0;
    TRISCbits.TRISC1 = 0;
    TRISCbits.TRISC2 = 0;
    TRISD = 0;
    char16x2LCDInit();
    I2C_Init();
    Reset_time();
    Set_time();



while(1)
{
     sec = Read_from_slave(0x00);
     __delay_ms(10);
Write_Command(0xC0);
    LCDWriteInt(BCD2Lowerch(sec),1);
    LCDWriteInt(BCD2Upperch(sec),1);

}
  }

Solo para obtener una imagen clara de las transacciones que ocurren en el bus I2C, adjunto una instantánea de la ventana del Depurador I2C que muestra las operaciones I2C durante la simulación en Proteus. La primera secuencia es la siguiente:     S = inicio,     D0 = dirección de esclavo + escritura,     A = Acuse de recibo del esclavo,     05 = Registrar dirección en el RTC,     A = Acuse de recibo del esclavo,     01 = datos escritos a 05H,     A = Acuse de recibo del esclavo,     P = Detener. De manera similar, para otros ciclos de escritura y lectura, mientras que en lectura hay "Sr", es decir, I2C_restart seguido de "N" NACK y, como podemos ver, no hay "P", es decir, se detiene después de NACK. También he adjuntado la imagen del hardware. Vuelvo a leer el esclavo como modo transmisor en la hoja de datos DS1307, pero no encuentro ningún problema con la secuencia "Read_from _slave".

Lo siento por el tedioso mensaje, ya que cualquier otro consejo o dirección con respecto a mi enfoque para realizar la operación de lectura o la identificación de cualquier problema con los métodos sería de gran ayuda. Gracias de nuevo!

Saludos ~ VD

    
pregunta PsychedGuy

3 respuestas

1

Una razón muy común de por qué recibe un 0xFF es porque la línea SCL del I2C no se mantiene durante el tiempo suficiente para que el esclavo transmita datos. Lo que sugiero es agregar un retraso de, por ejemplo, 10 microsegundos para alargar el reloj después de la función de lectura i2c y comprobar si está recibiendo datos. Es un método de prueba y error básicamente. Solo sigue aumentando la demora hasta que recibas datos relevantes. He tenido el mismo problema antes con un Atmega y realmente se eliminó en SE: P.

    sec = Read_from_slave(0x00); //Read address 00H(Seconds) from the RTC and display on LCD
    _delay_ms(10); //add a small delay to stretch the clock.
    Write_Command(0xC0);

Espero que funcione! Y si funciona, intente reducir la demora para que obtenga sus valores en el mínimo tiempo posible.

    
respondido por el Rohan Narlanka
2

No estoy seguro pero:

    SSPBUF = addr; //RTC register to be read
    check_ACK_Master_Transmit();
    Wait_MSSP();

Parece que primero comprobó el ACK antes de esperar para obtener la confirmación de la transmisión exitosa. Esto también está presente en su write_to_slave() . Tal vez podrías intentar cambiar el orden, por si acaso.

    
respondido por el TisteAndii
0

A continuación se muestra el flujo que uso regularmente para leer datos de DS1307
1. Enviar START
2. Escribe SLAVE_ADDR + W
3. Obtener ACK de esclavo
4. Escriba REG_ADDR (este es el registro ds1307 desde donde desea leer los datos)
5. Obtener ACK de esclavo
6. Enviar REPEATED_START
7. Escribe SLAVE_ADDR + R
8. Obtener ACK de esclavo
9. Espere a que DATA 10. Envíe ACK para obtener los siguientes DATOS desde ds1307 y luego vaya al paso 9
11. Enviar NACK para detener la transferencia
12. Enviar STOP

En su función Read_from_slave (), el paso 6 y el paso 7 se intercambian, es decir, está enviando RTC_ADDRR antes de emitir I2C_restart ().

También debe esperar hasta que se complete la transmisión, luego verifique si recibió ACK o NACK como lo sugieren otros miembros.

    
respondido por el anishkumar

Lea otras preguntas en las etiquetas