ds1307 comunicacion I2C

Hola! soy nuevo en este foro! estoy elaborando un reloj propeller con un pic18f4550 y un ds1307 para guardar ahí la hora, he estado probando un programa que hice por medio del manual y la hoja de datos pero no funciona, espero y me puedan ayudar, de antemano gracias!

Código:
#include <p18f4550.h>
#include <i2c.h>
#define RTC_SDA  PIN_B0
#define RTC_SCL  PIN_B1

#pragma config PLLDIV = 1            // No prescale (4 MHz oscillator input drives PLL directly)
#pragma config CPUDIV = OSC1_PLL2    // [OSC1/OSC2 Src: /1][96 MHz PLL Src: /2]
#pragma config USBDIV = 1            // USB clock source comes directly from the primary oscillator block with no postscale
#pragma config FOSC = XT_XT            // HS oscillator, HS used by USB
#pragma config FCMEN = OFF            // Fail-Safe Clock Monitor disabled
#pragma config IESO = OFF            // Oscillator Switchover mode disabled
#pragma config PWRT = OFF            // PWRT disabled
#pragma config BOR = OFF            // Brown-out Reset disabled in hardware and software
#pragma config VREGEN = OFF            // USB voltage regulator disabled
#pragma config WDT = OFF            // HW Disabled - SW Controlled
#pragma config MCLRE = ON            // MCLR pin enabled; RE3 input pin disabled
#pragma config LPT1OSC = OFF        // Timer1 configured for higher power operation
#pragma config PBADEN = OFF            // PORTB<4:0> pins are configured as digital I/O on Reset
#pragma config CCP2MX = ON            // CCP2 input/output is multiplexed with RC1
#pragma config STVREN = ON            // Stack full/underflow will cause Reset
#pragma config LVP = OFF            // Single-Supply ICSP disabled
#pragma config ICPRT = OFF            // ICPORT disabled
#pragma config XINST = OFF            // Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config DEBUG = OFF            // Background debugger disabled, RB6 and RB7 configured as general purpose I/O pins
    // Data and code memory without protection

unsigned char SEG,MIN,HRS,DAY,DIA,MES,ANO,SEGUNDOS;
int BAN=1;


void main(void)
{
    //CONFIGURAR SSPCON1
    SSPCON1 = 0X00;
    SSPCON1bits.SSPEN = 1;
    
    
    // CONFIGURAR BRG A velocidad de 100 KHZ con un cristal de 4MHZ
    SPBRG = 0x027;

    //CONFIGURACION ADCON1 TODOS SALIDAS DIGITALES
    ADCON1=0x0f;
    
    //CONFIGURACION TRISB
    TRISB= 0x03;
    TRISD=0x00;
    PORTD=0B00000000;
    SEG=0b00000000;
    
    IdleI2C();
    StartI2C();
    IdleI2C();
    WriteI2C(0B11010000);// DIRECCION DEL DS1307 EN ESCLAVO
    IdleI2C();
    WriteI2C(0B00000000);//INDICA QUE POSICION SE VERA CAMBIADA, EN ESTE CASO LOS SEGUNDOS
    IdleI2C();
    WriteI2C(SEG);// iNDICA EL SEG. ACTUAL
    IdleI2C();
    StopI2C();//DEJA DE MANDAR INSTRUCCIONES
    
    
        
    do
    {

         //pROCESO DE lECTURA
        IdleI2C();
        StartI2C(); 
        IdleI2C();
        WriteI2C(0b11010000); // INDICA LA DIRECCION DEL ESCLAVO CON EL BIT 0=0 PARA ESCRIBIR EL APUNTADOR
        IdleI2C();
        WriteI2C(0b00000000); // PONE EL PUNTERO EN EL REGISTRO 0(SEGUNDOS)
        IdleI2C();
        RestartI2C(); // REINICIA I2C
        IdleI2C();
        WriteI2C(0b11010001); // SE COLOCA LA DIRECCION DEL ESCLAVO CON EL BIT 0=1 PARA INDICAR LECTURA 
        IdleI2C();

        SEGUNDOS = ReadI2C(); // GUARDA LA LECTURA DE LOS SEGUNDOS 
        AckI2C();
        IdleI2C();
        NotAckI2C();
        IdleI2C();
        StopI2C();
                 
        PORTD=SEGUNDOS;//SE MANDA LA VARIABLE DE SEGUNDOS AL PUERTO D

    }while(BAN==0);
    
    
}
 
Última edición por un moderador:
Hola:
Fig2403_DS1307.gif


http://www.pic16f84a.org/index.php?...w=article&id=66&Itemid=87#Proteus_Capitulo_24

;)
 
Hola gracias por responder! estoy tratand de mandar el registro de segundos a los leds pero no se prenden y creo q lo q esta mal es la programacion :S me podrias ayudar?!
 
saludos amigos, podrian ayudarme con un proyectico de matriz de led 8x64 monocolor, lo que quiero hacer es en el codigo del progama del microcontrolador agregarle DS1307 para mostrar hora, minutos y segundos en la matriz pero realmente no lo he logrado, un un proyecto de grado, saludos
 
hola que tal yo trabajo en lenguaje c y me gustaria poder leer el ds1307 y lo e podido hacer pero tengo cierto problema el cual es que cuando loleo este al parecer me da datos hexadecimales y no decimales al parecer no solo consta en leer y expresar en el lcd sino tambien se debe convertir en decimal alguien podria darme alguna solucion a esto gracias .. no se quisa deba convertir mediante una operacion matematica como se hace al convertir de analogico a digital .
 
hola de hecho el DS1307 te entrega los datos en formato BCD a mi se me ocurrio separar los nibles y con un switch asignar el valor correspondiente a ASCII para poder mostrarlo en LCD
 
Hola, bueno aqui te dejo un driver que hice para este reloj, a mi me funciona de maravilla, también te dejo una imagen con las conexiones.

Código:
/*
#ifndef RTC_SCL

#define RTC_SCL PIN_B1
#define RTC_SDA  PIN_B2

#endif
*/
#define segundos 0
#define minutos 1
#define horas 2
#define dia_semana 3
#define fecha 4
#define mes 5
#define anio 6
#define registro_de_control 7

#define escribir_ds1307 0xd0
#define leer_ds1307 0xd1

//para escribir en la memoria NVRAM que trae el reloj
#define DS1307_NVRAM_START_ADDR 8

// Con este valor desactivamos la señal de salida por el pin SQW
// porque consume mucha bateria si está activada.
#define DS1307_CONTROL_REG_INIT_VALUE 0x80

//    Para activar el pin SQW a una frecuencia de 32768Hz
//    Descomentaremos esta definicion
//
//    #define DS1307_CONTROL_REG_INIT_VALUE 0x13

//    Funcion para leer en un registro de la memoria NVRAM que trae           
//    incorporada el reloj DS1307.                                            

int read_ds1307(int direccion)
{
      int retval;

      disable_interrupts(GLOBAL);
      i2c_start();
      i2c_write(escribir_ds1307);
      i2c_write(direccion);

      i2c_start();
      i2c_write(leer_ds1307);
      retval = i2c_read(0); // no esperamos por ack
      i2c_stop();

      enable_interrupts(GLOBAL);

   return(retval);
}

//    Funcion para escribir en un registro de la memoria NVRAM que trae       
//    incorporada el reloj DS1307.                                            

void write_ds1307(int direccion, int val)
{
      disable_interrupts(GLOBAL);

      i2c_start();
      i2c_write(escribir_ds1307);
      i2c_write(direccion);
      i2c_write(val);
      i2c_stop();

      enable_interrupts(GLOBAL);
}

void RTC_init()
{
output_low(DS1307_SDA);
delay_us(2);
output_low(DS1307_SCL);
}

char bin2bcd(char valor_binario)
{
      char temp;
      char retval;

      temp = valor_binario;
      retval = 0;

      while(1)
         {
               // coge las decenas y les resta 10
               // para obtener unidades
               if(temp >= 10)
                  {
                     temp -= 10;
                     retval += 0x10;
                  }
               else
                  {
                     retval += temp;
                     break;
                  }
         }
   return(retval);
}

char bcd2bin(char valor_bcd)
{
      char temp;
      temp = valor_bcd;
      temp >>= 1;
      temp &= 0x78;
   return(temp + (temp >> 2) + (valor_bcd & 0x0f));
}

void rtc_set_datetime(int day, int mth, int year, int dow, int hr, int min, int seg) 
{
      seg = bin2bcd(seg);
      min = bin2bcd(min);
      hr  = bin2bcd(hr);
      dow = bin2bcd(dow);
      day = bin2bcd(day);
      mth = bin2bcd(mth);
      year = bin2bcd(year);
      
      seg &= 0x7f;
      min &= 0x7f;
      hr  &= 0x3f;
      dow &= 0x07;             
      day &= 0x3f; 
      mth &= 0x1f;
      
      disable_interrupts(GLOBAL);

      i2c_start();
      i2c_write(escribir_ds1307);
      // se empieza escribiendo los segundos
      i2c_write(segundos);

      // y luego se escriben 7 bytes más....
      i2c_write(seg); //Siempre grabamos en la posicion de segundos el valor '0'
      i2c_write(min);
      i2c_write(hr);
      i2c_write(dow);
      i2c_write(day);
      i2c_write(mth);
      i2c_write(year);
      // despues de ajustar los registros
      // modificamos el registro de control
      i2c_write(3);
      i2c_stop();

      enable_interrupts(GLOBAL);
}


void rtc_get_date() 
{
      disable_interrupts(GLOBAL);

      i2c_start();
      i2c_write(0xd0);
      // empezamos leyendo los segundos
      i2c_write(segundos);

      i2c_start();
      i2c_write(leer_ds1307);

      // leemos los 7 bytes restantes. hacemos mascaras para los
      //bits que no usamos

      NDia = i2c_read();
      NDia = i2c_read();
      NDia = i2c_read();
      NDia = i2c_read() & 0x07;
      Fdia = i2c_read() & 0x3f;
      Fmes = i2c_read() & 0x1f;
      Fanio = i2c_read(0);
      i2c_stop();

      enable_interrupts(GLOBAL);

      // convertimos de bcd a binario
      
      NDia = bcd2bin(NDia);
      Fdia = bcd2bin(Fdia);
      Fmes = bcd2bin(Fmes);
      Fanio = bcd2bin(Fanio);
}

void rtc_get_time()
{
      disable_interrupts(GLOBAL);

      i2c_start();
      i2c_write(0xd0);
      // empezamos leyendo los segundos
      i2c_write(segundos);

      i2c_start();
      i2c_write(leer_ds1307);

      // leemos los 7 bytes restantes. hacemos mascaras para los
      //bits que no usamos

      Tseg = (i2c_read() & 0x7f);
      Tmin = (i2c_read() & 0x7f);
      Thora = (i2c_read(0) & 0x3f);
      i2c_stop();

      enable_interrupts(GLOBAL);

      // convertimos de bcd a binario
      
      Tseg = bcd2bin(Tseg);
      Tmin = bcd2bin(Tmin);
      Thora = bcd2bin(Thora);
}


void rtc_write_nvr(BYTE address, BYTE data) {
   write_ds1307(address|0x08,data);
}

BYTE rtc_read_nvr(BYTE address) {
    return(read_ds1307(address|0x08));
}
PD: la parte inicial que está comentada la puedes descomentar y definirla en tu programa principal, te recomendaría que este archivo lo guardes con un nombre como driver_ds1307.c y en tu programa principal lo llames usando los include, eso te ayudará a tener tu programa mucho mas ordenado.

en tu programa principal declaras las variables como globales a:

int8 THora, TMin, TSeg, FDia, FMes, FAnio, NDia; //Variables tiempo y fecha Princ

ya luego solo tienes que llamar la rutina de por ejemplo lectura de tiempo asi:

rtc_get_time();

y listo.

Saludos!! :)
 

Adjuntos

  • ds1307 i2c.jpg
    ds1307 i2c.jpg
    159.1 KB · Visitas: 51
Última edición:
chrisck87 muchas gracias pero ya lo resolvi lo unico que debia hacer era tomar el dato y expresarlo como hexa en el lcd , luego de dar tumbos me dia cuenta ... consulta no se si habras echo algo con teclado se que es facil lo se pero la verdad no me sale me sale siempre algun error no se si me pudieras facilitar un circuito de coexion con algun pic y un lcd y un programa sencillo el cual muestre el valor de la tecla precionada. gracias .

en una ocasion lo hice me salio pero no recuerdo que debia hacer creo que modifique algo en el compilador ...
 
Que tal, sobre lo del pic con teclado y lcd, particularmente uso un pic dedicado para el teclado y éste le envia a un pic principal la tecla presionada, pero funcionaria perfectamente todo en un solo pic, esto lo hago para no cargar el programa de mi pic "principal" con cosas como un teclado.

Bueno en este ejemplo esta de la manera en que te comento, un pic dedicado al teclado y otro como principal.

El pic del teclado es el 16F628A, lo elijo porque es barato, no necesita oscilador y es pequeño.
El pic principal es un 18F452, bastante mas potente que el 628A, por eso es el principal.

Las conexiones para el teclado matricial y el 628A te las pongo en la imagen "Teclado matricial"
El código completo es este:

Código:
#define LED_OP PIN_A7
int1 Edo_led;
int8 Cont_T0;
#int_TIMER1
void  TIMER1_isr(void)
{
   if(Edo_led==1)
   {
      Cont_T0++;
      if(Cont_T0>=8)
      {
         Edo_led=0;
         Cont_T0=0;
         output_low(LED_OP);
      }
   }
}  

#int_TIMER0
void  TIMER0_isr(void) 
{

}

int8 Pines[4]={PIN_B4, PIN_B5, PIN_B6, PIN_B7}, Tecla;

void Pines_low()
{
   for(Tecla=0; Tecla<4;Tecla++)
   {
      Output_low(Pines[tecla]);
   }
}

void Pines_high()
{
   for(Tecla=0; Tecla<4;Tecla++)
   {
      Output_high(Pines[tecla]);
   }
}

void Verifica()
{
   int8 i,j;
   Output_low(Pines[0]);
   for(i=0;i<4;i++)
   {
      if(i>0)
      {Output_high(Pines[i-1]);}
      Output_low(Pines[i]);
      
      delay_ms(1);
      j=Input(PIN_B0) + (Input(PIN_B1)*2) + (Input(PIN_B2)*4) + (Input(PIN_B3)*8);
      j=15-j;
      if(j!=0x00)
      {
         Tecla = 10 * i;
         Tecla+=j;
         goto Fin;
      }
   }
   Fin:
   j=0;
}

void main()
{
   int8 Entradas, Salida;
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_16); //4ms
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //65ms
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   enable_interrupts(INT_TIMER1);
   disable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   port_b_pullups(true);
   // TODO: USER CODE!!
   
   Pines_low();
   output_a(255);
   output_low(LED_OP);
   
   do
   {
      
      Entradas=Input(PIN_B0) + (Input(PIN_B1)*2) + (Input(PIN_B2)*4) + (Input(PIN_B3)*8);
      if(Entradas!=0x0F)
      {
         delay_ms(50);
         Entradas=Input(PIN_B0) + (Input(PIN_B1)*2) + (Input(PIN_B2)*4) + (Input(PIN_B3)*8);
         if(Entradas!=0x0F)
         {
            pines_high();
            Verifica();
            if(Tecla!=0)
            {
               if(Tecla<10)
               {  Salida=0;   }
               else if(Tecla<20)
               {  Salida=4;   Tecla-=10;}
               else if(Tecla<30)
               {  Salida=8;   Tecla-=20;}
               else if(Tecla<40)
               {  Salida=12;  Tecla-=30;}
               Switch(Tecla)
               {
                  case 1:
                           Salida+=1;
                           break;
                  case 2:
                           Salida+=2;
                           break;
                  case 4:
                           Salida+=3;
                           break;
                  case 8:
                           Salida+=4;
                           break;         
               }
               if((Salida!=15) && (Salida!=16))
               {   
                  output_a(Salida);
                  Edo_led=1;
                  output_high(LED_OP);
               }
               Pines_low();
            }
         }
         else
         {output_a(15);}
      }
      else
      {output_a(15);}
   }while(true);
}
Tal vez se ve un poco enredado pero lo que hace es hacer detectar algun dato en los pines B0-B3 que son las columnas, si detecta una columna con tecla presionada, hace un barrido en las filas para saber en cual fila está la tecla presionada de esa manera se sabe la columna y la fila de la tecla presionada, luego de eso acomoda los datos para dar un valor a la variable "Salida" segun la tecla que se haya presionado y lo saca por el puerto A.
Al ser un teclado matricial de 4x4 tendras 16 teclas, en este programa se pueden detectar 13, pero eso es poque para mi solo necesitaba esas teclas asi que deshabilite las otras.
Para este caso siguiendo la imagen, cuando presiones la tecla 4D, la variable salida sera 1, cuando presiones 3D, la variable salida sera 2, 2D-3, 1D-4, 4C-5, 3C-6, 2C-7, 1C-8, 4B-9, 3B-10, 2B-11, 1B-12, 4A-13, 3A-14, la 2A y 1A están deshabilitadas.
Y si no presionas ninguna tecla, envia el dato F o 15.

Ahora en la imagen "Conexion con CPU" verás que los pines del puerto A del pic 628 están conectados a los pines del puerto B del pic principal.

En el pic principal ya solo tendrías que leer esos pines, sería algo asi:

Código:
int8 Tecla, Anterior;
int1 key_press()
{ 
  delay_us(200);
  Anterior=input(PIN_B4) + (input(PIN_B5)*2) + (input(PIN_B6)*4) + (input(PIN_B7)*8);
  Tecla&=0x0F;
  if(Tecla!=0x0F)
  {
      return(Tecla); 
  }
  else
  { return(0); }
}
Esa seria tu subrutina para detección de la tecla presionada, en el código principal llamarías esa subrutina asi:

Código:
if(key_press()!=0)
{
                     switch(Tecla)
                     {  case 1:         .... /tu código para la tecla 1
                                          break; 
                        case 2:         .... /tu código para la tecla 2
                                          break; 
                        case 3:      .... /tu código para la tecla 3
                                          break;
                        case 4:     .... /tu código para la tecla 4
                                          break;
                       .....    
                      }
}
si deseas tener un código mas ordenado pues en el programa principal declaras nombres a cada tecla por ejemplo

Código:
#define T_ESC 12
#define T_ENTER 10
#define T_UP 11
#define T_DW 7
#define T_LF 8
#define T_RG 6
#define T_ULF 4
#define T_URG 3
#define T_A 9
#define T_B 5
#define T_C 2
#define T_D 1
y en switch reemplazarias los números por los nombres.

Código:
if(key_press()!=0)
{
                     switch(Tecla)
                     {  case T_D:         .... /tu código para la tecla 1
                                          break; 
                        case T_C:         .... /tu código para la tecla 2
                                          break; 
                        case T_URG:      .... /tu código para la tecla 3
                                          break;
                        case T_ULF:     .... /tu código para la tecla 4
                                          break;
                       .....    
                      }
}
tengo varios circuitos funcionando con esos códigos, son bastante fiables.

Ahora con respecto al LCD, no se como andarás en ese tema, si sabes programar un LCD, que tipo de LCD es, en que puerto se conectará y cosas asi, en este caso, yo coloque el LCD en el puerto D, y en mi caso el LCD es uno gráfico.

Saludos
 

Adjuntos

  • Teclado matricial.jpg
    Teclado matricial.jpg
    94.7 KB · Visitas: 20
  • Conexion con CPU.jpg
    Conexion con CPU.jpg
    134.9 KB · Visitas: 22
Atrás
Arriba