Como me aconsejaron mis compañeros apiladores en mi publicación anterior, también probé la función "Write_to_slave" en Proteus en tiempo real, enviando bytes al RTC y el esclavo responde adecuadamente con un bit de reconocimiento por cada byte que recibe, por lo tanto, el la operación de escritura está funcionando 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 reconocimiento 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 deberían ser los segundos contando de 0 a 60 (y 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 sucede, como puede ver en la instantánea de Proteus. A continuación se muestra el código, he realizado solo una operación de lectura para leer el registro de segundos para verificar si mi método funciona, pero desafortunadamente no es así:
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, he adjuntado 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 del esclavo + escritura, A = reconocimiento del esclavo, 05 = dirección de registro en el RTC, A = reconocimiento del esclavo, 01 = datos escritos en 05H, A = reconocimiento del esclavo, P = Detener. De manera similar para otros ciclos de escritura y también de lectura, mientras que en lectura hay "Sr", es decir, I2C_restart seguido de "N" NACK y, como podemos ver, no hay "P", es decir, parada después de NACK. También he adjuntado la imagen del hardware. Vuelvo a leer el modo esclavo como transmisor en la hoja de datos DS1307, pero no encuentro nada malo con la secuencia "Read_from_slave".
Perdón por el mensaje tedioso, ya que sería de gran ayuda 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. ¡Gracias de nuevo!
Saludos ~VD
Una razón muy común por la que recibe un 0xFF es porque la línea SCL del I2C no se retiene el tiempo suficiente para que el esclavo transmita datos. Entonces, lo que sugiero es agregar un retraso de, digamos, 10 microsegundos para estirar el reloj después de la función de lectura i2c y verificar si está recibiendo datos. Es un método de prueba y error básicamente. Simplemente siga aumentando la demora hasta que reciba datos relevantes. He tenido el mismo problema antes con un Atmega y en realidad se solucionó 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 disminuir la demora para que obtenga sus valores en el mínimo tiempo posible.
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 a obtener la confirmación de la transmisión exitosa. Esto también está presente en su write_to_slave()
. Tal vez podría intentar cambiar el orden, por si acaso.
A continuación se muestra el flujo que uso regularmente para leer datos de DS1307
1. Enviar INICIO
2. Escribir SLAVE_ADDR + W
3. Obtener ACK del esclavo
4. Escribir REG_ADDR (este es el registro ds1307 desde donde desea leer los datos)
5. Obtener ACK desde el esclavo
6. Envíe REPEATED_START
7. Escriba SLAVE_ADDR + R
8. Obtenga ACK del esclavo
9. Espere DATA
10. Envíe ACK para obtener los siguientes DATA de ds1307 y luego vaya al paso 9
11. Envíe NACK para detener la transferencia
12. Envíe 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 según lo sugerido por otros miembros.
chicopsico
brahans
chicopsico