Comunicación y decodificación I2C [RTC][DS1307]

Hola a todos.

Necesito un poco de ayuda con el tema de los relojes RTC, en la parte de comunicación, y otro poco en el tema de la decodificación.

Estoy usando microcontroladores PIC. Más específicamente el 16f877a, pero más adelante voy a pasar al 16f685, que es más chico, más barato, y no hace que gaste recursos.

Estoy haciendo un proyecto de reloj digital (de más está decir), donde comunico la hora al PIC que maneja la parte gráfica, desde un DS1307. Estos integrados son de 8 patas y se comunican mediante el protocolo I2C (mediante 2 cables).
Tienen una entrada de batería de 3V, por si la alimentación general se corta, y guardar la hora.
Como tiene una RAM de 64x8 bits, de los cuales sólo 8 registros se usan para el reloj, se puede guardar más información en los registros restantes, y obviamente, salvarlos del apagón (cosa muy común donde vivo).
La hoja de datos dice que con una batería de 48mAh, el integrado funciona por 10 años, para que se den una idea de lo poco que consume.

Bueno, ahora, vamos al tema.

El tema de la comunicación ya lo tengo dominado (o al menos eso parece), porque vi bastantes ejemplos, incluyendo cómo usarlo en la hoja de datos, y coinciden con lo que yo hago.
Doy ejemplos, más o menos:

Para escribir:

Inicio de transmisión.
Dirección de esclavo + bit de escritura
Dirección donde se va a escribir
Enviar información
Fin de transmisión.

Para leer (de algún lugar específico)

Inicio de transmisión
Dirección de esclavo + bit de escritura
Dirección donde se va a escribir
Inicio de transmisión (reinicio)
Dirección de esclavo + bit de lectura
Recibir información
Fin de transmisión.

Está bien eso?
Supongamos que ese tema está resuelto.

Hoja de datos: CLICK ACÁ


Ahora, según el fabricante, el integrado muestra los datos (cuando se lo lee, obviamente) de la siguiente forma, y doy el ejemplo de un sólo registro:

8 bits: _._._._._._._._ (cada _ es 1 bit).

El primer bit (de la izquierda de todo) es un 0.
Los siguientes 3 bits son las DECENAS de los minutos.
Los siguientes (y últimos) 4 bits al anterior, son las UNIDADES de los minutos.

Entonces, si estoy en el minuto 37, me manda el 3 con 3 bits, y el 7 con 4 bits (cosa coherente porque el máximo es 59 y el 5 y el 9 se pueden codificar con 3 y 4 bits cada uno respectivamente).

Ahora, no habría sido mejor enviar el número 59b (00111011) en los 8 bits, por más que sobren algunos? Bueno, no va a cambiar la cosa, pero es un comentario nomás.

Necesitaría alguna forma de, justamente, con ese número descompuesto en decenas y unidades, generar el mismo en formato decimal.

Y digo nomás, para no quedar mal, lo que se me ocurrió:

Leer un registro y guardarlo en una variable de 8 bits.
A esa variable hacerle una máscara (con operador &), y sacar los bits importantes, de a partes.
Con las unidades parece funcionar bien (probé con papel y lápiz...), pero con las decenas me quedan ceros a la derecha. No hay un operador de C, llamado "corrimiento de bits hacia la derecha/izquierda" (<< ó >>)? Ahora, si pongo >> me corre 1 hacia la derecha, y en algunos lugares vi escrito ">>7"; eso corre 7 bits hacia la derecha, o es otro operador?


Muchas gracias por su tiempo y comprensión, espero sus respuestas.
 
El formato que maneja el DS1307 es BCD (4 bits), necesitas una rutina donde se convierta de BCD a binario (decimal) para leer y otra de binario a BCD para escribir.
En el foro hay sobre éste RTC y bastante...

Saludos.

PD. Creo que te van a moderar!!!
 
Muchas gracias por responder. No creo que me moderen porque ya leí los otros temas, y ninguno respondía mi pregunta.

Abajo de todo el testamento que escribí dice un método para convertir, pero para correr los bits a la derecha tengo la duda.

Saludos.
 
Con el DS1307 utilicé estas rutinas en asm:

Código:
; Entrada: en W el numero en BCD
; Salida: en W el byte en formato decimal
BCD_a_Decimal
      movwf   aux_1,BANKED 
      movlw   0x0F
      andwf   aux_1,W,BANKED
      movwf   aux_2,BANKED  ;unidades
      swapf   aux_1,W,BANKED
      andlw   0x0F
      movwf   aux_1,BANKED     ; aux_1 sera contador decenas
      movf    aux_1,W,BANKED   ; para ver indicador Z
      btfsc   STATUS,Z,ACCESS
      goto    fin_decenas
otra_decena
      movlw   .10 
      addwf   aux_2,F,BANKED     ;añadimos decenas
      decfsz  aux_1,F,BANKED
      goto    otra_decena
fin_decenas
      movf    aux_2,W ,BANKED
      return 
 
 
; Entrada: en W el numero en Decimal
; Salida: en W el byte en formato BCD
Decimal_a_BCD
      movwf   aux_1,BANKED 
      clrf    aux_2,BANKED
decBCD
      movlw   .10
      subwf   aux_1,W,BANKED
      btfsc   STATUS,N,ACCESS
      goto    BCD_low
      movwf   aux_1,BANKED        ; restamos 10 al numero decimal
      movlw   .16                       ; añadimos una decena en BCD
      addwf   aux_2,F,BANKED
      goto    decBCD
BCD_low
      movf    aux_1,W,BANKED      ; aux_1 debe contener solamente unidades 
      addwf   aux_2,W,BANKED      ; aux_2 contiene las decenas en BCD
      return
Salu2.
 
Última edición por un moderador:
Muchas gracias por responder. Hago eso mismo, compiló, y simulo en proteus (isis) . Me salta el Watchdog (cuando está desactivado en los fusibles.

Programo en c, con el picc compiler.

Alguien podría pasarme un código donde se escriba en una posición, y se lea una distinta? Es para orientarme nomas.

Gracias
 
Última edición:
Hola a todos, como están?

Bueno, estoy trabajando en un proyecto el cual básicamente es un reloj despertador. Consta de 4 partes; la fuente, el microcontrolador, el RTC (DS1307) y los displays.

La fuente y los displays ya los tengo resueltos, no es la gran cosa.

Ahora, el programa lo tengo ya diagramado y hay que hacerle unas modificaciones, y me falta por completo la parte de lectura, escritura y conversión de formatos del RTC DS1307 como ya dije.

Ese integrado usa protocolo I2C, y tiene 55x8 bits libres de RAM volátil, pero como tiene entrada para batería tipo "botón" de 3V, vendría a ser una especie de NVRAM, pongamosle. Una batería de 48mAh lo mantiene prendido por 10 años, así que dense una idea...

Entonces, hice un programa y un circuito de prueba con un PIC16F877a, el cual adjunto.

El programa de prueba es el siguiente:

Código:
#include <16f887.h>
#fuses nowdt,noprotect,nobrownout,noput                  //fusibles.
#use i2c(master,sda=PIN_A0,scl=PIN_A1,slow)           //configurar comunicación i²c.
#use delay(clock=20M)   //Cristal 20MHz

     // I2C entre PIC y RTC
    
void main() 
{

   set_tris_a( 0xff );
   set_tris_b( 0x00 );
   set_tris_c( 0x00 );
   set_tris_d( 0x00 );
   set_tris_e( 0x00 );
  
   output_b( 0x00 );       //Inicializa puerto B en 0.
   
   delay_ms(1000);         //Prueba de funcionamiento.
   output_b(0xff);
   delay_ms(500);
   output_b(0x00);
   
   while(1)
   {
   
   i2c_start();
   i2c_write( 0xD0 );
   i2c_write( 0x00 );         //Pone cursor de memoria en 00h (segundos).
   
   i2c_start();                   //Resetea transmisión
   i2c_write( 0xD1 );         //Manda dirección de esclavo y orden de leer.
     
   output_b( i2c_read() );    //Segundos.
   output_c( i2c_read() );    //Minutos.
   output_d( i2c_read() );    //Horas.

   i2c_stop();

   delay_ms( 1000 );
   
   }  
}


Lo que debería hacer básicamente es: Llamar al esclavo, poner "cursor" en dirección 00h, y poner los puertos B, C y D en los valores que reciba al leer las direcciones. El puerto B se pone en el valor de 00h, C en el de 01h y D en el de 02h. Es para controlar visualmente que se recibe un valor.

Se ve que hay un "programita" de prueba, que prende y apaga el puerto B, afuera del bucle infinito. Esa parte funciona, pero salta el watchdog timer (cuando está desactivado en los fusibles) apenas empieza a hacer el bucle.
Alguien sabe por qué es?


Adjunto circuito.
NOTA: La pata de batería del DS1307 está a tierra porque no tenía ganas de ponerle batería...

Ver el archivo adjunto 104694

Espero que me puedan ayudar, no sé si hay que incluir una librería de i2c. Si hubiera, me podrían pasar el archivo?

Muchas gracias, saludos.
 
ok estoy haciendo un termostato programable y con temporizador de tiempo real ,utilizo FLOWCODE 5.
Estoy en punto de operacion total ,pero estoy interesado en convertir la programacion del reloj de DECIMAL a BCD(O HEXAGESIMAL EN SU DEFECTO) para poder enviarlo al RTC.
En este momento cargo los datos en una hoja de calculo de fc5 que me permite escribir los valores y simplemente lo cargo al codigo y un simple boton lo ajusta.
 

Adjuntos

  • HOJA DE CALCULO FC5.jpg
    HOJA DE CALCULO FC5.jpg
    66.2 KB · Visitas: 12
Atrás
Arriba