Error al interconectar DS1307 RTC con PIC32

Estoy interactuando DS1307 RTCcon PIC32MX795F512L. Estoy usando I2C1for DS1307 RTCy luego usando UART2para enviar el valor RTC a la terminal. He escrito el código pero no sé por qué no obtengo datos.

En mi código estoy usando

OpenI2C2 to open the i2c channel.
StartI2C2() to start the communication
StopI2C2() to stop the communication
MasterWriteI2C() to write the data
MasterReadI2C() to read the data

Estos están incluidos en el archivo plib.h.

CÓDIGO actualizado:

OpenI2C2(I2C_EN, 163); // I2C channel Configuration

StartI2C2();            
IdleI2C2();             
n = MasterWriteI2C2(0xD0);  //device address
IdleI2C2();              
MasterWriteI2C2(0x07);      
IdleI2C2();
MasterWriteI2C2(0x00);
IdleI2C2();
StopI2C2();

StartI2C2();            
IdleI2C2();             
MasterWriteI2C2(0xD0);  
IdleI2C2(); 
MasterWriteI2C2(0x01);
IdleI2C2(); 
MasterWriteI2C2(0b00010011);
IdleI2C2(); 
StopI2C2();


StartI2C2();
IdleI2C2();
MasterWriteI2C2(0xD0);
IdleI2C2();
MasterWriteI2C2(0x01);
IdleI2C2();
StopI2C2();

StartI2C2();
IdleI2C2();
MasterWriteI2C2(0xD1);
IdleI2C2();
**res = MasterReadI2C2();**
IdleI2C2();
NotAckI2C2();
IdleI2C2();
StopI2C2();

Estoy usando 163 ((33000000/2/100000)-2)como valor BRG para la comunicación I2C. Estoy depurando el código y puedo ver que todos los valores en los registros I2C son correctos, pero en res = MasterReadI2C2(), no aparece nada en I2C2RCVel registro que contiene el valor recibido e incluso no aparece nada en la resvariable. También usé una variable npara verificar si los valores realmente se transmiten o no. Entonces recibí 0x00como el valor de n y según el documento, 0 significa transmisión exitosa.

No sé dónde me estoy perdiendo el punto.

¿Quiere decir nada como realmente nada, o nada como en los tres bytes son 0?
en algún momento obtengo valores basura como? o * o algo más. En algún momento, la terminal está completamente en blanco o en algún momento obtengo NULL. Estoy usando Docklight
Tal vez inicialice los caracteres en un valor legible por humanos, pero sin sentido como 'Z', actualmente suena más como si tuviera un problema con su UART. (¿y se dio cuenta de que solo obtiene la hora una vez y la imprime para siempre?) Y para este tipo de prueba, asegúrese de configurar su terminal para mostrar valores hexadecimales o decimales, ya que los valores ASCII pueden ser muy engañosos.
¿Qué quiere decir con "inicializar los caracteres en un lenguaje legible por humanos" de qué caracteres está hablando? mi uart funciona porque si envío algo como helloworld, obtengo esto en la terminal
Ha unificado los caracteres ijk e i1 (que no se usa), que coloca en la función GetTime, para verificar si los valores cambian y, por lo tanto, se lee un tiempo, debe inicializarlos con algún valor, que se imprime muy bien en el Terminal.
Si los inicializo con algún valor, imprimirán el mismo valor. De hecho, estoy almacenando valores de rtc en ellos.
Está utilizando I2C2 en su código y menciona en la descripción que su dispositivo está en I2C1. ¿Cuál es - I2C1 o I2C2? (Por lo general, están en pines diferentes)
Olvidé editar la pregunta completa. Es una publicación anterior, ahora estoy usando I2C2.

Respuestas (3)

  1. Basado en la hoja de datos:

El bit 7 del registro 0 es el bit de parada de reloj (CH). Cuando este bit se establece en 1, el oscilador se desactiva. Cuando se borra a 0, el oscilador está habilitado

Entonces, cuando configure el segundo, asegúrese de que el bit 7 (CH) sea 0. Y configure el bit 7 (CH) en cero cada vez que se encienda el IC.

  1. Intente agregar un pequeño retraso (10 ms) antes del inicio de I2C y después de la parada de I2C.
  2. Intente establecer un registro a la vez.
  3. Ajuste la resistencia pull-up, intente cambiar a 1.5k/1.8k Ohm

Trabajé este RTC con ATMega128 y CodeVisionAVR Este código funciona:

rtc_init(0,1,0); // output pin for debugging

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x00);
i2c_write( (data_rtc[10]-48)*16 + (data_rtc[11]-48));      //second
i2c_stop();

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x01);
i2c_write( (data_rtc[8]-48)*16 + (data_rtc[9]-48));        // minutes
i2c_stop();

delay_ms(10);
i2c_start();
i2c_write(0xD0);
i2c_write(0x02);
i2c_write( (data_rtc[6]-48)*16 + (data_rtc[7]-48));        // hour
i2c_stop();

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x04);
i2c_write( (data_rtc[4]-48)*16 + (data_rtc[5]-48));        // day
i2c_stop(); 

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x05);
i2c_write( (data_rtc[2]-48)*16 + (data_rtc[3]-48));        // month
i2c_stop();

delay_ms(10);   
i2c_start();
i2c_write(0xD0);
i2c_write(0x06);
i2c_write( (data_rtc[0]-48)*16 + (data_rtc[1]-48));        // year
i2c_stop();

delay_ms(10); 
rtc_init(0,1,0);
De acuerdo, para obtener la sincronización adecuada, siempre debemos habilitar el oscilador, lo que significa que el bit 7 siempre será 0 y en mi código, RTC_SetTime (0x16,0x00,0x10) 0x10 significa 0001 0000, lo que significa que ya lo hice. entonces, cuál es el problema.
@CZabhinav, perdón por mi error, edité mi respuesta
¿Qué estás haciendo en esta línea i2c_write( (data_rtc[0]-48)*16 + (data_rtc[1]-48)); ??
Configurando la hora, pero data_rtc[x] en formato ASCII, entonces resto con 48. Luego multiplico el dígito de la izquierda con 16. Por ejemplo, queremos configurar segundo = 21, luego i2c_write(('2'-48)* 16 + ('1'-48))
No he hecho este tipo de conversión en mi código. Puede ser que este sea el error en mi código. ¿Tengo razón?
No lo creo, ya usas el formato BCD

Con las bibliotecas heredadas PLIB de Microchip para I2C, debe sondear manualmente el bus para que esté inactivo después de cada operación. A continuación se muestra un ejemplo:

StartI2C2(); // Send the Start Bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(0xE0); // Send slave address with write bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(addr);
IdleI2C2(); // Wait to complete
StopI2C2(); // Send Stop bit
IdleI2C2();
StartI2C2(); // Send the Start Bit
IdleI2C2(); // Wait to complete
MasterWriteI2C2(0xE1); // Send slave address with read bit
IdleI2C2(); // Wait to complete
val = MasterReadI2C2();
IdleI2C2();
NotAckI2C2(); // Master  Aknodledge End of transfer
StopI2C2(); // Send Stop bit
IdleI2C2(); 

La función IdleI2C2() es simplemente la siguiente:

while(I2C2CONbits.SEN || I2C2CONbits.PEN || I2C2CONbits.RSEN || I2C2CONbits.RCEN || I2C2CONbits.ACKEN || I2C2STATbits.TRSTAT);

Esta línea simplemente verifica cualquier bit que signifique que el periférico está ocupado (como una condición activa de inicio o parada, datos de salida actuales, etc.).

He usado su código para conectarlo con DS1307. He actualizado mi código. Me puedes ayudar con eso.!

Al mirar su código, no veo nada claramente incorrecto, pero si miramos la hoja de datos de DS1307 , página 13, especifica que para hacer una lectura de datos desde una ubicación específica, escriba la dirección, la ubicación en los registros de DS1307, luego inicie una rutina de "Inicio repetido", envíe la dirección nuevamente y luego lea los datos. Puede leer una ráfaga multibyte, secuencialmente, o un solo byte y luego enviar un STOP y comenzar el proceso nuevamente en una ubicación de registro diferente.

Recientemente encontré un intento fallido de comunicación entre un PIC maestro y un esclavo, y tenía un DS1307 por ahí, así que preparé un código. Afortunadamente, para i2c.h, no más golpes de bits. El código está escrito para PIC18F8722, pero debería encontrar que algo similar funcionará para usted:

#include <pic18f8722.h>
            #include <i2c.h>
            #include <spi.h>
            #include <delays.h>
            #include "LCD.h"
            #include "SerComm.h"

            #pragma config OSC = HSPLL
            #pragma config WDT = OFF
            #pragma config FCMEN = OFF

            #define newline 0x0A
            #define carriageReturn 0x0D

            void initialize(void);
            unsigned char x;
            unsigned char seconds = 0x00;
            unsigned char minutes = 0x36;
            unsigned char hours = 0x48;
            unsigned char days = 0x03;
            unsigned char date = 0x17;
            unsigned char month = 0x08;
            unsigned char year = 0x15;
            unsigned char hyear, lyear, hmonth, lmonth, hdate, ldate, hdays, ldays, hhours, lhours, hminutes, lminutes, hseconds, lseconds;
            unsigned char time[7];

            void main(void)
            {
                lcdInit();
                initialize();
                CloseI2C2();

                OpenI2C2(MASTER, SLEW_OFF);

                IdleI2C2();
                StartI2C2();
                WriteI2C2(0xD0);
                WriteI2C2(0x00);
                WriteI2C2(seconds);
                WriteI2C2(minutes);
                WriteI2C2(hours);
                WriteI2C2(days);
                WriteI2C2(date);
                WriteI2C2(month);
                WriteI2C2(year);
                StopI2C2();

                while(1)
                {
                IdleI2C2();
                StartI2C2();
                WriteI2C2(0xD0);
                WriteI2C2(0x00);
                RestartI2C2();
                WriteI2C2(0xD1);
                for(x = 0; x < 6; x++)
                {
                   time[x] = ReadI2C2();
                   AckI2C2();
                }
                time[6] = ReadI2C2();
                NotAckI2C2();
                StopI2C2();

                hyear = ((time[6] & 0xF0) >> 4) + 0x30;
                lyear = (time[6] & 0x0F) + 0x30;
                hmonth = ((time[5] & 0xF0) >> 4) + 0x30;
                lmonth = (time[5] & 0x0F) + 0x30;
                hdate = ((time[4] & 0xF0) >> 4) + 0x30;
                ldate = (time[4] & 0x0F) + 0x30;
                hdays = ((time[3] & 0xF0) >> 4) + 0x30;
                ldays = (time[3] & 0x0F) + 0x30;
                hhours = ((time[2] & 0x10) >> 4) + 0x30;
                lhours = (time[2] & 0x0F) + 0x30;
                hminutes = ((time[1] & 0xF0) >> 4) + 0x30;
                lminutes = (time[1] & 0x0F) + 0x30;
                hseconds = ((time[0] & 0xF0) >> 4) + 0x30;
                lseconds = (time[0] & 0x0F) + 0x30;



                lcdGoTo(0x00);
                lcdWriteString("Time: ");
                lcdChar(hhours);
                lcdChar(lhours);
                lcdChar(':');
                lcdChar(hminutes);
                lcdChar(lminutes);
                lcdChar(':');
                lcdChar(hseconds);
                lcdChar(lseconds);
                SerTx(hhours);
                SerTx(lhours);
                SerTx(':');
                SerTx(hminutes);
                SerTx(lminutes);
                SerTx(':');
                SerTx(hseconds);
                SerTx(lseconds);
                SerTx(newline);
                SerTx(carriageReturn);
                }

            }

            void initialize(void)
            {
                TRISAbits.RA2=0; // Chip select pin for the SPI port expander;

                TRISDbits.RD5 = 1;  //Set the ports of the I2C bus;
                TRISDbits.RD6 = 0;

                SSP2STAT = 0x80;    //Disable the slew rate control;
                SSP2CON1 = 0x28;    //Enable the Serial Port, Set the mode to: Master Mode, clock = Fosc/(4*(SSP1ADD + 1);
                SSP2CON2 = 0x00;    //No bits to set here;

                SSP2ADD = 0x59;     //Set to 100 kHz at 40 MHz clock;

                TXSTA1 = 0x24;      //Set serial communication to High Speed, TX enabled, 8 bit mode;
                RCSTA1 = 0x90;      //Enable the serial port, Enable the Receiver;
                BAUDCON1 = 0x00;    //;

                SPBRG1 = 42;        //57600 kBaud;
            }

Por favor, no seas demasiado duro con el código. Espero que esto ayude.

En tu while(1), has escrito WriteI2C2(0x00);, para que sirve esto.?? y con esta linea WriteI2C2(0xD1); está tratando de leer datos pero no ha mencionado qué registro leer. De todos modos, gracias por compartir tu código, ¡definitivamente intentaré esto!