Ir ao conteúdo
  • Cadastre-se

Driver p/ RTC DS1307


Posts recomendados

Olá galera,

Estou trabalhando em um projeto que utiliza um CI RTC o DS1307, o DS1307 tem a função de exibir os valores como hora e data em um display LCD 16x2 que é controlado pelo PIC16F877A.

Uso o CCS compiler, porém eu percebi que não existe o driver para o uso do DS1307, portanto eu pesquisei no fórum da CCS e encontrei um driver "genérico" para o uso do DS1307, só que ele não funciona corretamente, tentei fazer algumas correções, o código segue abaixo:


/// DS1307.C ///
/// Driver for Real Time Clock ///
/// ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Disable squarewave output ///
/// ///
/// ds1307_set_date_time(dia,mes,ano,dow,hora,min,seg) Set the date/time ///
/// ///
/// ds1307_get_date(dia,mes,ano,dow) Obter data ///
/// ///
/// ds1307_get_time(hora,min,seg) Obter tempo ///
/// ///
////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE seg;
BYTE min;
BYTE hora;
BYTE dow;
BYTE dia;
BYTE mes;
BYTE ano;

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
BYTE segundos = 0;

i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_stop();
i2c_start();
i2c_write(0xD1); // RD from RTC
segundos = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
i2c_stop();
segundos &= 0x7F;

delay_us(3);

i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_write(bin2bcd(segundos)); // Start oscillator with current "seconds value
i2c_stop();
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x80); // Disable squarewave output pin
i2c_stop();

}

void ds1307_set_date_time(BYTE dia, BYTE mes, BYTE ano, BYTE dow, BYTE hora, BYTE min, BYTE seg)
{
seg &= 0x7F;
hora &= 0x3F;

i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(seg)); // REG 0
i2c_write(bin2bcd(min)); // REG 1
i2c_write(bin2bcd(hora)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(dia)); // REG 4
i2c_write(bin2bcd(mes)); // REG 5
i2c_write(bin2bcd(ano)); // REG 6
i2c_write(0x80); // REG 7 - Disable squarewave output pin
i2c_stop();
}

void ds1307_get_date(BYTE &dia, BYTE &mes, BYTE &ano, BYTE &dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
dow = bcd2bin(i2c_read() & 0x7f); // REG 3
dia = bcd2bin(i2c_read() & 0x3f); // REG 4
mes = bcd2bin(i2c_read() & 0x1f); // REG 5
ano = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

void ds1307_get_time(BYTE &hora, BYTE &min, BYTE &seg)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
seg = bcd2bin(i2c_read() & 0x7f);
min = bcd2bin(i2c_read() & 0x7f);
hora = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;

temp = binary_value;
retval = 0;

while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}

return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;

temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;

// Now return: (Tens * 8) + (Tens * 2) + Ones

return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
////////////////////////////////////////////////////////////////////////////////

Abaixo o exemplo de uso do driver DS1307.c:


#include <ds1307.c>
#include <lcd.c>

#define I2C_SCL PIN_C3
#define I2C_SDA PIN_C4
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)


int1 flag=1;
int a_seg;


void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_init();
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);

lcd_init();
ds1307_init();

//Exemplo: 09/07/2010 (data)
// 23:20:00 (hora)
ds1307_set_date_time(9,7,10,00,23,20,0);

a_seg = seg;

while(TRUE)
{
ds1307_get_time(hora,min,seg);
ds1307_get_date(dia,mes,ano,dow);

If(a_seg!=seg)
{
printf(lcd_putc,"\f %02i:%02i:%02i\n %02i/%02i/%02i",hora,min,seg,dia,mes,ano);
a_seg=seg;
}
}
}
#include "C:\Program Files (x86)\PICC\Projetos\Projects\PIC 16f877A\Transmissor [Versao A].h"

Como podem ver o uso é bem simples, é so utilizar o comando ds1307_set_date_time(), ds1307_get_date(),ds1307_get_time() para obter os valores correspondentes.

Mas como eu citei, o driver funciona com alguns erros:

- O DS1307 não "memoriza" a hora anterior, mesmo estando ligado a bateria.

- Quando o PIC é ligado sem utilizar o comando ds1307_set_date_time o valor exibido é "00:00:00".

- E quando é utilizado o comando ds_1307_set_date_time o DS1307 sempre inicia na mesma hora configurada (óbvio), sendo assim interrompendo a contagem anterior.

Gostaria de saber se alguém poderia me disponibilizar algum driver do DS1307 que funcione corretamente.

Desde já agradeço pela ajuda. :D

Link para o comentário
Compartilhar em outros sites

Olá Felipe_ZeRo! Cara fiz uma biblioteca para o RTC DS1307, ainda não implementei fisicamente, mas fiz o projeto no Proteus com o pic 18F452, e funcionou certinho.

Ve se te é útil, tá muito completa, e se você achar algum bug dê um report e sinta-se livre para debuga-la. Como biblioteca I2C, adaptei a do Fábio Pereira para atender as especificaões de tempo mínimo de scl e sda do DS1307.

Abaixo a biblioteca DS1307.c


/***************************************/
/* DS1307.C */
/* Biblioteca para o RTC DS1307 */
/* */
/* autor: Alysson Machado */
/***************************************/

//importante: A biblioteca I2C.c deve estar incluída antes desta bibioteca!
const byte slave_ad_write=0xD0;
const byte slave_ad_read= 0xD1;
byte seg,min,hor,d,dat,a;

void data_escreve_rtc(byte word_ad, byte dado)
// envia comando de escrita no rtc
{
//Converte Decimal para BCD
dado=((dado/10)<<4)+(dado%10);
I2C_start();
I2C_escreve_byte(slave_ad_write);
delay_us(3);
I2C_le_ack();
I2C_escreve_byte(word_ad);
I2C_le_ack();
I2C_escreve_byte(dado);
I2C_le_ack();
I2C_stop();
}
unsigned char data_le_rtc(byte word_ad_read)
//le um byte enviado pelo rtc do barramento I2C
{
byte rtc_byte;
I2C_start();
I2C_escreve_byte(slave_ad_write);
delay_us(3);
I2C_le_ack();
I2C_escreve_byte(word_ad_read);
I2C_le_ack();
I2C_start();
I2C_escreve_byte(slave_ad_read);
I2C_le_ack();
rtc_byte=I2C_le_byte();
delay_us(2);
I2C_nack();
I2C_stop();
//Converte BCD para decimal
rtc_byte=((rtc_byte>>4)*10)+rtc_byte%16;
return rtc_byte;
}
unsigned byte converte_decimal_to_BCD(byte info)
//converte o dado para BCD
{
info=((info/10)<<4)+(info%10);
return info;
}
void grava_alldata_rtc(seg,min,hor,d,dat,m,a)
//grava todos os dados no RTC
{
seg=converte_decimal_to_BCD(seg);
min=converte_decimal_to_BCD(min);
hor=converte_decimal_to_BCD(hor);
d=converte_decimal_to_BCD(d);
dat=converte_decimal_to_BCD(dat);
m=converte_decimal_to_BCD(m);
a=converte_decimal_to_BCD(a);
I2C_start();
I2C_escreve_byte(slave_ad_write);
delay_us(3);
I2C_le_ack();
I2C_escreve_byte(0x00);
I2C_le_ack();
I2C_escreve_byte(seg);
I2C_le_ack();
I2C_escreve_byte(min);
I2C_le_ack();
I2C_escreve_byte(hor);
I2C_le_ack();
I2C_escreve_byte(d);
I2C_le_ack();
I2C_escreve_byte(dat);
I2C_le_ack();
I2C_escreve_byte(m);
I2C_le_ack();
I2C_escreve_byte(a);
I2C_le_ack();
I2C_stop();
}
void desativa_clock_rtc()
//desativa o clock do RTC
{
byte aux_seg;
aux_seg=data_le_rtc(0x00);
data_escreve_rtc(0x00,(0x50+aux_seg));
}
void ativa_clock_rtc()
//ativa o clock do RTC
{
byte aux_seg;
aux_seg=data_le_rtc(0x00)-0x50;
data_escreve_rtc(0x00,aux_seg);
}
void zera_segundos_rtc()
//zera a contagem dos segundos
{
data_escreve_rtc(0x00,0);
}
void seleciona_clockout_rtc(int1 OUT,int1 SQWE,int1 RS1,int1 RS0)
//seleciona o estado do pino SQW/OUT
{
if(SQWE==0)
{
if(OUT==0)
{
data_escreve_rtc(0x07,0);
}
else if(OUT==1)
{
data_escreve_rtc(0x07,80);
}
}
else if(SQWE==1)
{
if((RS0==0)&&(RS1==0))
{
data_escreve_rtc(0x07,10);
}
else if((RS0==1)&&(RS1==0))
{
data_escreve_rtc(0x07,11);
}
else if((RS0==1)&&(RS1==1))
{
data_escreve_rtc(0x07,13);
}
}
}

Abaixo está a biblioteca I2c.c para a comunicação


/*************************************************************/
/* I2C.C */
/* Biblioteca de comunicação I2C por software com suporte a memórias */
/* EEPROM */
/* autor: Fábio Pereira */
/*************************************************************/

#ifndef scl
//Definições dos pinos de comunicação
#define scl pin_b1 //pino de clock
#define sda pin_b0 //pino de dados
#define EEPROM_SIZE 32768 //tamanho dem bytes da memória eeprom
#endif

#define seta_scl output_float(scl) //seta o pino scl
#define apaga_scl output_low(scl) //apaga o pino scl
#define seta_sda output_float(sda) //seta o pino sda
#define bit_sda output_high(sda) //coloca nivel no barramento
#define apaga_sda output_low(sda) //apaga o pino sda

void I2C_start(void)
//coloca o barramento na condição de start
{
apaga_scl;
delay_us(3);
seta_sda;
delay_us(3);
seta_scl;
delay_us(3);
apaga_sda;
delay_us(3);
apaga_scl;
delay_us(3);
}
void I2C_stop(void)
//coloca o barramento na condição de stop
{
delay_us(3);
apaga_scl;
delay_us(3);
apaga_sda;
delay_us(3);
seta_scl;
delay_us(4);
seta_sda;
delay_us(3);
}
void I2C_ack()
//coloca o sinal de reconhecimento no barramento
{
apaga_sda;
delay_us(3);
seta_scl;
delay_us(3);
apaga_scl;
delay_us(3);
seta_sda;
delay_us(3);
}
void I2C_nack()
//coloca no barramento o sinal de não reconhecimento
{
seta_sda;
delay_us(3);
seta_scl;
delay_us(3);
apaga_scl;
delay_us(3);
}
boolean I2C_le_ack()
//efetua a leitura do sinal de ack/nack
{
boolean estado;
seta_sda;
delay_us(3);
seta_scl;
delay_us(2);
do{
estado=input(sda);
delay_us(3);
apaga_scl;
delay_us(3);
return estado;
delay_us(3);
}while(estado!=0);

}
void I2C_escreve_byte(unsigned byte dado)
{
//envia um byte pelo barramento I2C
int conta=8;
delay_us(2);
apaga_scl;
while(conta)
{
//envia primeiro o MSB
if(shift_left(&dado,1,0)) {seta_sda; delay_us(3);} else { apaga_sda;delay_us(3);}
//dá um pulso em scl;
seta_scl;
delay_us(3);
conta--;
apaga_scl;
delay_us(3);
}
//ativa sda
seta_sda;
delay_us(3);
}
unsigned char I2C_le_byte()
//recebe um byte pelo barramento I2C
{
unsigned char bytelido,conta=8;
bytelido=0;
apaga_scl;
delay_us(3);
seta_sda;
delay_us(3);
while(conta)
{
//ativa scl
seta_scl;
delay_us(3);
//lê o byte em sda, deslocando em byte lido
shift_left(&bytelido,1,input(sda));
conta--;
// desativa scl
delay_us(3);
apaga_scl;
delay_us(3);
}
return bytelido;
}
void escreve_eeprom(byte dispositivo,long endereco,byte dado)
//escreve em um endereço do dispositivo
//dispositivo - é o endereço do dispositivo escravo
//endereco - é o endereço de memória a ser escrito
//dado - é a informação a ser guardada
{
if(dispositivo>7) dispositivo=7;
I2C_start();
I2C_escreve_byte(0xA0|(dispositivo<<1));
I2C_le_ack();
I2C_escreve_byte(endereco>>8);
I2C_le_ack();
I2C_escreve_byte(endereco);
I2C_le_ack();
I2C_escreve_byte(dado);
I2C_le_ack();
I2C_stop();
delay_ms(10);
}
byte le_eeprom(byte dispositivo,long int endereco)
//lê um dado de um endereço específico no dispositivo
//dispositivo - é o endereço do dispositivo escravo (0 - 7)
//endereco - é o endereço da memória a ser lida
{
byte dado;
if(dispositivo>7) dispositivo=7;
I2C_start();
I2C_escreve_byte(0xA0|(dispositivo<<1));
I2C_le_ack();
I2C_escreve_byte(endereco>>8);
I2C_le_ack();
I2C_escreve_byte(endereco);
I2C_le_ack();
I2C_start();
//envia comando de leitura
I2C_escreve_byte(0xA1|(dispositivo<<1));
I2C_le_ack();
dado=I2C_le_byte();
I2C_nack();
I2C_stop();
return dado;
}

Espero ter ajudado! Abraço.

Link para o comentário
Compartilhar em outros sites

AlyssonMachado, caraca... Você desenvolveu a biblioteca? Parabéns ai amigo!!!!!!!!!!!!!

Quando fui montar no protoboard para testar deu muita zebra até funcionar, porém, quando montei na placa (fiz uma pequena plaquinha) nunca deu zebra, está funcionando até hoje com a bateria e nem atrasou, já faz 4 mêses...

Segue o link do código feito no CCS, e do esquema para simulação no proteus:

http://www.easy-share.com/1911330587/RTC_ds1307_PIC_PROTEUS_CCS.rar

Dica: Meu PC é bem velhinho (parceiro de guerra =}), então quando vou fazer simulações no proteus eu vou em System > Set animations options e desmarco a opção Show logic state of pins... Quando não faço isso, o RTC fica locão e mostra 455:115:100 para hora =D'...

- Quando o PIC é ligado sem utilizar o comando ds1307_set_date_time o valor exibido é "00:00:00".

Ligue o PIC, depois desligue e grave ele sem o comandos ds1307_init() e ds1307_set_date_time, e então ligue ele de novo...

Só usei esses comandos para configurar a hora na primeira vez, depois não o usei mais

Link para o comentário
Compartilhar em outros sites

Ta aí , o exemplo pra te dar uma clareada.:D ta grande porque resolvi postar completo, talvez ache algo que lhe seja útil.

Estudando este código saberá trabalhar com a biblioteca que fiz, flwss

OBS: a pinagem do LCD não está no padrão do driver CCS lcd.c! para testar você terá que mudar a pinagem. caso não consiga simular, posto depois a biblioteca lcd_flex.c que tenho que é mais fácil modificar os pinos do lcd( não precisar mexer com structs).


#include<18F452.H>
#use delay(clock=4000000)
#fuses XT,NOWDT,LVP,PUT,NOBROWNOUT,NOSTVREN
#use rs232(BAUD=9600, xmit=pin_c6, rcv=pin_c7)

#define BT input(pin_c4)
#define BT1 input(pin_c5)
#define BT2 input(pin_c3)
#define BT3 input(pin_c2)
#define scl pin_d0
#define sda pin_d1

#include<I2C.c>
#include<DS1307.c>
#include<input.c>
#include<lcd.c>
#include<string.h>
#include<stdio.h>
int8 segundos,minutos,horas,data,mes,dia,ano,CH;
int j=7;

void carrega_alldata_rtc()
{
I2C_start();
I2C_escreve_byte(slave_ad_write);
delay_us(3);
I2C_le_ack();
I2C_escreve_byte(0x00);
I2C_le_ack();
I2C_start();
I2C_escreve_byte(slave_ad_read);
I2C_le_ack();
segundos=I2C_le_byte();
delay_us(2);
I2C_ack();
minutos=I2C_le_byte();
delay_us(2);
I2C_ack();
horas=I2C_le_byte();
delay_us(2);
I2C_ack();
dia=I2C_le_byte();
delay_us(2);
I2C_ack();
data=I2C_le_byte();
delay_us(2);
I2C_ack();
mes=I2C_le_byte();
delay_us(2);
I2C_ack();
ano=I2C_le_byte();
delay_us(2);
I2C_nack();
I2C_stop();
}

void converte_BCD_to_INT()
{
segundos=((segundos>>4)*10)+segundos%16;
minutos=((minutos>>4)*10)+minutos%16;
horas=((horas>>4)*10)+horas%16;
data=((data>>4)*10)+data%16;
mes=((mes>>4)*10)+mes%16;
ano=((ano>>4)*10)+ano%16;
}

char dia_semana_converte(dia)
//lê o dia da semana
{
char dia_semana[7][4]={"dom","seg","ter","qua","qui","sex","sab"};
char dia_hoje[4];
switch(dia)
{
case 1: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 2: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 3: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 4: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 5: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 6: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;

case 7: strcpy(dia_hoje,dia_semana[dia-1]);
return (dia_hoje);
break;
default:
break;
}
}

#INT_TIMER1
void atualiza_lcd()
//Manda para o LCD os dados do RTC
{

set_timer1(3036-get_timer1());
carrega_alldata_rtc();
converte_BCD_to_INT();
if(segundos>79) segundos-=80;
lcd_gotoxy(1,1);
printf(lcd_putc,"%s - %02.0u/%02.0u/%02.0u",dia_semana_converte(dia),data,mes,ano);
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u:%02.0u:%02.0u",horas,minutos,segundos);

}

void ajuste_horas()
//função para o ajuste de horas
{

while(BT)
{

lcd_gotoxy(j,2);
lcd_setcursor(1,0);
if(!BT1)
{
delay_ms(300);
j+=3;
if(j>13) j=7;
}
if((j==7)&&(!BT2))
{
delay_ms(300);
horas-=1;
if(horas==-1) horas=23;
lcd_setcursor(0,0);
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u",horas);
}
else if((j==10)&&(!BT2))
{
delay_ms(300);
minutos-=1;
if(minutos==-1) minutos=59;
lcd_setcursor(0,0);
lcd_gotoxy(9,2);
printf(lcd_putc,"%02.0u",minutos);
}
else if((j==13)&&(!BT2))
{
delay_ms(300);
segundos-=1;
if(segundos==-1) segundos=59;
lcd_setcursor(0,0);
lcd_gotoxy(12,2);
printf(lcd_putc,"%02.0u",segundos);
}
if((j==7)&&(!BT3))
{
delay_ms(300);
horas+=1;
if(horas==24) horas=0;
lcd_setcursor(0,0);
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u",horas);
}
else if((j==10)&&(!BT3))
{
delay_ms(300);
minutos+=1;
if(minutos==60) minutos=0;
lcd_setcursor(0,0);
lcd_gotoxy(9,2);
printf(lcd_putc,"%02.0u",minutos);
}
else if((j==13)&&(!BT3))
{
delay_ms(300);
segundos+=1;
if(segundos==60) segundos=0;
lcd_setcursor(0,0);
lcd_gotoxy(12,2);
printf(lcd_putc,"%02.0u",segundos);
}
}
lcd_setcursor(0,0);
data_escreve_rtc(0x00,segundos);
data_escreve_rtc(0x01,minutos);
data_escreve_rtc(0x02,horas);
}
void ajuste_data()
//função para o ajuste de data
{
while(BT)
{
lcd_gotoxy(j,2);
lcd_setcursor(1,0);
if(!BT1)
{
delay_ms(300);
j+=3;
if(j>13) j=7;
}

if((j==7)&&(!BT2))
{
delay_ms(300);
data-=1;
if(data==0) data=31;
lcd_setcursor(0,0);
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u",data);
}
else if((j==10)&&(!BT2))
{
delay_ms(300);
mes-=1;
if(mes==0) mes=12;
lcd_setcursor(0,0);
lcd_gotoxy(9,2);
printf(lcd_putc,"%02.0u",mes);
}
else if((j==13)&&(!BT2))
{
delay_ms(300);
ano-=1;
if(ano==-1) ano=99;
lcd_setcursor(0,0);
lcd_gotoxy(12,2);
printf(lcd_putc,"%02.0u",ano);
}
if((j==7)&&(!BT3))
{
delay_ms(300);
data+=1;
if(data==32) data=1;
lcd_setcursor(0,0);
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u",data);
}
else if((j==10)&&(!BT3))
{
delay_ms(300);
mes+=1;
if(mes==13) mes=1;
lcd_setcursor(0,0);
lcd_gotoxy(9,2);
printf(lcd_putc,"%02.0u",mes);
}
else if((j==13)&&(!BT3))
{
delay_ms(300);
ano+=1;
if(ano==100) ano=1;
lcd_setcursor(0,0);
lcd_gotoxy(12,2);
printf(lcd_putc,"%02.0u",ano);
}
}
lcd_setcursor(0,0);
data_escreve_rtc(0x04,data);
data_escreve_rtc(0x05,mes);
data_escreve_rtc(0x06,ano);
}
void ajuste_dia()
{
while(BT)
{
if(!BT2)
{
lcd_setcursor(0,0);
delay_ms(300);
dia-=1;
if(dia==-1) dia=7;
dia_semana_converte(dia);
lcd_gotoxy(8,2);
printf(lcd_putc,"%s",dia_semana_converte(dia));
}
if(!BT3)
{
lcd_setcursor(0,0);
delay_ms(300);
dia+=1;
if(dia==8) dia=1;
dia_semana_converte(dia);
lcd_gotoxy(8,2);
printf(lcd_putc,"%s",dia_semana_converte(dia));
}
}
data_escreve_rtc(0x03,dia);

}
main()
{
set_tris_d(0);
set_tris_b(0);
set_tris_a(0b00111000);
set_tris_c(0b00111111);
output_d(0);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
set_timer1(3036);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
disable_interrupts(INT_TIMER0);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
lcd_init();
//Este trecho apenas simula a primeira vez que o RTC é inicializado ********
//grava_alldata_rtc(80,0,0,1,1,1,0);
CH=data_le_rtc(0x00);
CH=(((CH/10)<<4)+(CH%10))>>7;
segundos=0x50-(data_le_rtc(0x00));
segundos=segundos&0x00;
printf("valor do registrador 0x00 = %d",segundos);
printf("\rvalor do bit CH = %d",CH);
if((CH==1)&&(segundos==0))
{
disable_interrupts(INT_TIMER1);
lcd_gotoxy(3,1);
lcd_putc("\fAjuste de horas");
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u:%02.0u:%02.0u",horas,minutos,segundos);
ajuste_horas();
delay_ms(300);
lcd_gotoxy(3,1);
lcd_putc("\fAjuste de data");
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u/%02.0u/%02.0u",data,mes,ano);
ajuste_data();
delay_ms(300);
lcd_gotoxy(3,1);
lcd_putc("\fAjuste de dia");
lcd_gotoxy(8,2);
printf(lcd_putc,"%s",dia_semana_converte(dia));
ajuste_dia();
data_escreve_rtc(0x00,0x00); //zera o bit CH do endereço dos segundos
}
//****************************************************************************
enable_interrupts(INT_TIMER1);
lcd_putc('\f');
while(1)
{
if(!BT)
{
int cont_bt_pres,i;
disable_interrupts(INT_TIMER1);
delay_ms(100);
if(!BT)
{
for(i=0;i<10;i++)
{
if(!BT) {cont_bt_pres++; lcd_putc('\f');}
if(cont_bt_pres>3) cont_bt_pres=1;
if(cont_bt_pres==1)
{
lcd_gotoxy(3,1);
lcd_putc("Ajuste de horas");
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u:%02.0u:%02.0u",horas,minutos,segundos);
}
if(cont_bt_pres==2)
{
lcd_gotoxy(3,1);
lcd_putc("Ajuste de data");
lcd_gotoxy(6,2);
printf(lcd_putc,"%02.0u/%02.0u/%02.0u",data,mes,ano);
}
if(cont_bt_pres==3)
{
lcd_gotoxy(3,1);
lcd_putc("Ajuste de dia");
lcd_gotoxy(8,2);
printf(lcd_putc,"%s",dia_semana_converte(dia));
}
delay_ms(200);
}
if(cont_bt_pres==1) ajuste_horas();
if(cont_bt_pres==2) ajuste_data();
if(cont_bt_pres==3) ajuste_dia();
cont_bt_pres=0;
lcd_gotoxy(1,2);
lcd_putc(" ");
}
enable_interrupts(INT_TIMER1);
lcd_putc('\f');
}

if(!BT3)
{
boolean estado;
byte CH_bit,aux_seg;
delay_ms(300);
estado=!estado;
if(estado==1)
{
desativa_clock_rtc();
printf("\rComando de clock do DS1307 desligado");
}
else if(estado==0)
{
ativa_clock_rtc();
printf("\rComando de clock do DS1307 ligado");
}
}

if(!BT2)
/*********************************/
/* |RS1|RS0|SQWE/out|SQWE|OUT| */
/* | 0 | 0 | 1Hz | 1 | X | */
/* | 0 | 1 |4096kHz | 1 | X | */
/* | 1 | 0 |8192kHz | 1 | X | */
/* | 1 | 1 |32768kHz | 1 | X | */
/* | X | X | 0 | 0 | 0 | */
/* | X | X | 1 | 0 | 1 | */
/*********************************/
{
int estado2;
delay_ms(300);
estado2++;
if(estado2==7) estado2=1;
if(estado2==1)
{
seleciona_clockout_rtc(1,0,0,0); //SQW/OUT=1
}
else if(estado2==2)
{
seleciona_clockout_rtc(0,0,0,0); //SQW/OUT=0
}
else if(estado2==3)
{
seleciona_clockout_rtc(0,1,0,0); //SQW/OUT=1Hz
}
else if(estado2==4)
{
seleciona_clockout_rtc(0,1,0,1); //SQW/OUT=4096kHz
}
else if(estado2==5)
{
seleciona_clockout_rtc(0,1,1,0); //SQW/OUT=8192kHz
}
else if(estado2==6)
{
seleciona_clockout_rtc(0,1,1,1); //SQW/OUT=32768kHz
}
}

}
}


Test man, obrigado cara!! so tava achando biblioteca ruim de mexer com o DS1307, ai peguei o datasheet e fui mandando ver uashausuash. É muuuuito melhor mexer com uma biblioteca que você saiba cada linha dela, fik mais fácil desenvolver o projeto.

E tentei deixa-la bem simples de interptetar.

Felipe_ZeRo, ta aqui a biblioteca do lcd, creio que te irá ser útil em muitos projetos.

abraço!

lcd_flex.c


#define LCD_DB4 PIN_B4 // NIBLE de dados
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B2
#define LCD_E PIN_B3
//#define USE_LCD_RW 1

#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line
int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};

void lcd_send_nibble(int8 nibble){
// Obs: !! converte uma exprecao inteira
// para uma booleana (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
delay_us(2);//teste
}
// Envia um byte para o LCD.
void lcd_send_byte(int8 address, int8 n){
output_low(LCD_RS);
delay_us(60);
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
output_low(LCD_E);
lcd_send_nibble(n >> 4);
delay_us(2); //teste
lcd_send_nibble(n & 0xf);
}
void lcd_init(void){
int8 i;
output_low(LCD_RS);
output_low(LCD_E);
delay_ms(15);
for(i=0 ;i < 3; i++){
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++){
lcd_send_byte(0, LCD_INIT_STRING[i]);
}
delay_ms(15);
}
// posições válidas:
// de x=1 a x=16 y
// de y=1 a y=2
void lcd_gotoxy(int8 x, int8 y){
int8 address;
if(x > 0 && y > 0){
if(y > 1)
address = lcd_line_two;
else
address=0;
address += x-1;
lcd_send_byte(0, 0x80 | address); // Manda cursor a la posición
}
}

void lcd_putc(char c){
if(c>'\0'){
switch(c){
case '\f':
lcd_send_byte(0,1);
lcd_send_byte(0,2);
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1,2);
delay_ms(2);
break;
case '\b':
lcd_send_byte(0,0x10);
delay_ms(2);
break;
case '\t':
lcd_send_byte(0,0x14);
delay_ms(2);
break;
default:
lcd_send_byte(1,c);
delay_ms(2);
break;
}
}
}
void lcd_put_string(char *string){
//put string, inicia na posicao atucal do cursor
//assume que a estring na exceda a ram mostradada do lcd
char index=0;
while(string[index]!=0){
lcd_putc(string[index++]);
}
}
void lcd_put_string_xy(char *string, char x, char y){
//assume that string not excides from lcd displayed RAM
lcd_gotoxy(x,y);
lcd_put_string(string);
}

void lcd_setcursor(short visible, short blink) {
lcd_send_byte(0, 0xC|(visible<<1)|blink);
}
/*
' LCD
' Command Operation
' *********** *****************************************
' $FE, 1 Clear display
' $FE, 2 Return home
' $FE, $0C Cursor off
' $FE, $0E Underline cursor on
' $FE, $0F Blinking cursor on
' $FE, $10 Move cursor left one position
' $FE, $14 Move cursor right one position
' $FE, $80 Move cursor to beginning of first line
' $FE, $C0 Move cursor to beginning of second line
' *********** ***************************************** */

Oláa, esqueci de comenta!, Fiz com o PIC18F452 porque meu código tinha uma infinidade de funções e a ROM do 16F877A tava meio pequena pro projeto!, mas dependendo do seu ele é mais que suficiente!

fiz mais uma função para a biblioteca DS1307.c, para fazer o controle do formato das horas (12h ou 24h).

abraço.!


boolean seleciona_modo_am(boolean modo)
//seleciona o modo de exibição de horas AM/PM
{
boolean am_modo;
if(modo==true)
{
hor=data_le_rtc(0x02);
//Conversão 24H para AM
switch(hor)
{
case 12: hor=72; //O registrador de endereço 0x02 contém os dados
break; //da hora. Como ele é em BCD se quiser mandar o
case 13: hor=61; //seguinte campo de bits: 01010011
break; //temos que mandar o valor 53 em BCD.
case 14: hor=62; //o bit 6 quando setado muda o modo de horário para
break; //12horas(AM/PM), e quando é 0 o modo é o de 24horas
case 15: hor=63; //O bit 5 em nível 1 quando o bit6 está setado
break; //indica PM e quando 0 AM.
case 16: hor=64; //Os demais bits são para o horário
break; //Portanto para que selecionemos 02horas AM temos
case 17: hor=65; // que mandar o valor 42 em BCD pois assim teremos
break; //01000010, setando o bit6 indicamos que é formato
case 18: hor=66; //12horas e zerando o bit5 indicamos que é AM 02horas
break;
case 19: hor=67;
break;
case 20: hor=68;
break;
case 21: hor=69;
break;
case 22: hor=70;
break;
case 23: hor=71;
break;
case 0: hor=52;
break;
case 1: hor=41;
break;
case 2: hor=42;
break;
case 3: hor=43;
break;
case 4: hor=44;
break;
case 5: hor=45;
break;
case 6: hor=46;
break;
case 7: hor=47;
break;
case 8: hor=48;
break;
case 9: hor=49;
break;
case 10: hor=50;
break;
case 11: hor=51;
break;
default:
break;
}

data_escreve_rtc(0x02,hor);
return true;
}
else if(modo==false)
{
hor=data_le_rtc(0x02);
//conversão AM para 24H
switch(hor)
{
case 72: hor=12;
break;
case 61: hor=13;
break;
case 62: hor=14;
break;
case 63: hor=15;
break;
case 64: hor=16;
break;
case 65: hor=17;
break;
case 66: hor=18;
break;
case 67: hor=19;
break;
case 68: hor=20;
break;
case 69: hor=21;
break;
case 70: hor=22;
break;
case 71: hor=23;
break;
case 40: hor=0;
break;
case 41: hor=1;
break;
case 42: hor=2;
break;
case 43: hor=3;
break;
case 44: hor=4;
break;
case 45: hor=5;
break;
case 46: hor=6;
break;
case 47: hor=7;
break;
case 48: hor=8;
break;
case 49: hor=9;
break;
case 50: hor=10;
break;
case 51: hor=11;
break;
case 52: hor=0;
default:
break;
}
data_escreve_rtc(0x02,(hor));
return false;
}
}
//******************
//Exemplo de utilização:
//
// if(!input(pin_c3))
{
delay_ms(300); //filtro para o botão
seleciona_modo_am(true); //indica para o RTC que o formato é 12horas

/* Se fosse p.ex: 14:15h passaria para 02:15h [COLOR="Red"]PM[/COLOR] */
}

post-712360-13884956406006_thumb.jpg

Link para o comentário
Compartilhar em outros sites

  • 5 meses depois...
Olá galera,

Estou trabalhando em um projeto que utiliza um CI RTC o DS1307, o DS1307 tem a função de exibir os valores como hora e data em um display LCD 16x2 que é controlado pelo PIC16F877A.

Uso o CCS compiler, porém eu percebi que não existe o driver para o uso do DS1307, portanto eu pesquisei no fórum da CCS e encontrei um driver "genérico" para o uso do DS1307, só que ele não funciona corretamente, tentei fazer algumas correções, o código segue abaixo:


/// DS1307.C ///
/// Driver for Real Time Clock ///
/// ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Disable squarewave output ///
/// ///
/// ds1307_set_date_time(dia,mes,ano,dow,hora,mim,seg) Set the date/time ///
/// ///
/// ds1307_get_date(dia,mes,ano,dow) Obter data ///
/// ///
/// ds1307_get_time(hora,mim,seg) Obter tempo ///
/// ///
////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE seg;
BYTE mim;
BYTE hora;
BYTE dow;
BYTE dia;
BYTE mes;
BYTE ano;

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
BYTE segundos = 0;

i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_stop();
i2c_start();
i2c_write(0xD1); // RD from RTC
segundos = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
i2c_stop();
segundos &= 0x7F;

delay_us(3);

i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_write(bin2bcd(segundos)); // Start oscillator with current "seconds value
i2c_stop();
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x80); // Disable squarewave output pin
i2c_stop();

}

void ds1307_set_date_time(BYTE dia, BYTE mes, BYTE ano, BYTE dow, BYTE hora, BYTE mim, BYTE seg)
{
seg &= 0x7F;
hora &= 0x3F;

i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(seg)); // REG 0
i2c_write(bin2bcd(mim)); // REG 1
i2c_write(bin2bcd(hora)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(dia)); // REG 4
i2c_write(bin2bcd(mes)); // REG 5
i2c_write(bin2bcd(ano)); // REG 6
i2c_write(0x80); // REG 7 - Disable squarewave output pin
i2c_stop();
}

void ds1307_get_date(BYTE &dia, BYTE &mes, BYTE &ano, BYTE &dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
dow = bcd2bin(i2c_read() & 0x7f); // REG 3
dia = bcd2bin(i2c_read() & 0x3f); // REG 4
mes = bcd2bin(i2c_read() & 0x1f); // REG 5
ano = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

void ds1307_get_time(BYTE &hora, BYTE &mim, BYTE &seg)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
seg = bcd2bin(i2c_read() & 0x7f);
mim = bcd2bin(i2c_read() & 0x7f);
hora = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;

temp = binary_value;
retval = 0;

while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}

return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;

temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;

// Now return: (Tens * 8) + (Tens * 2) + Ones

return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
////////////////////////////////////////////////////////////////////////////////

Abaixo o exemplo de uso do driver DS1307.c:


#include <ds1307.c>
#include <lcd.c>

#define I2C_SCL PIN_C3
#define I2C_SDA PIN_C4
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3)


int1 flag=1;
int a_seg;


void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_init();
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);

lcd_init();
ds1307_init();

//Exemplo: 09/07/2010 (data)
// 23:20:00 (hora)
ds1307_set_date_time(9,7,10,00,23,20,0);

a_seg = seg;

while(TRUE)
{
ds1307_get_time(hora,mim,seg);
ds1307_get_date(dia,mes,ano,dow);

If(a_seg!=seg)
{
printf(lcd_putc,"\f %02i:%02i:%02i\n %02i/%02i/%02i",hora,mim,seg,dia,mes,ano);
a_seg=seg;
}
}
}
#include "C:\Program Files (x86)\PICC\Projetos\Projects\PIC 16f877A\Transmissor [Versao A].h"

Como podem ver o uso é bem simples, é so utilizar o comando ds1307_set_date_time(), ds1307_get_date(),ds1307_get_time() para obter os valores correspondentes.

Mas como eu citei, o driver funciona com alguns erros:

- O DS1307 não "memoriza" a hora anterior, mesmo estando ligado a bateria.

- Quando o PIC é ligado sem utilizar o comando ds1307_set_date_time o valor exibido é "00:00:00".

- E quando é utilizado o comando ds_1307_set_date_time o DS1307 sempre inicia na mesma hora configurada (óbvio), sendo assim interrompendo a contagem anterior.

Gostaria de saber se alguém poderia me disponibilizar algum driver do DS1307 que funcione corretamente.

Desde já agradeço pela ajuda. :D

Ola eu tambem estou tendo a mesma dificuldade que você estava enfrentando em relação a biblioteca ds1307, gostaria de saber se você chegou a alguma conclusão e se possivel postar o codigo.obrigado

Ola alyson, eu vi que você entende e muito de programação e gostaria de saber se você consegue arrumar a biblioteca do ds13o7 que esta dando erro ,no qual o felipezero se refere.Eu utilzei somente no proteus essa biblioteca e de repente as horas se alteram sosinha tipo 315:67:88 uns valores doidos e não sei o que fazer

Link para o comentário
Compartilhar em outros sites

Olá Diego, como pedido corrigi o driver do DS1307 . Segue abaixo o driver:

OBS: No código possui umas linhas comentadas ( //delay_us(3) ). Se depois de montado o projeto as vezes der erro de transmissão de dado descomente estas linhas.

ERRO que havia no arquivo:

funções:

void ds1307_get_date(BYTE *dia, BYTE *mes, BYTE *ano, BYTE *dow)

void ds1307_get_time(BYTE *hora, BYTE *mim, BYTE *seg)

Estavam com os parametro errados ( o erro era compilável ). Como as funções passam os valores por referencia deve ser enviado o endereço da variavel para um ponteiro ( &_mes -> *mes ) e estava enviando endereço para endereço ( &_mes -> &mes ) o que é erro do programador.

Concertado isso funcionou perfeitamente.

libDS1307.c


////////////////////////////////////////////////////////////////////////////////
/// DS1307.C ///
/// Driver for Real Time Clock ///
/// ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Disable squarewave output ///
/// ///
/// ds1307_set_date_time(dia,mes,ano,dow,hora,mim,seg) Set the date/time ///
/// ///
/// ds1307_get_date(dia,mes,ano,dow) Obter data ///
/// ///
/// ds1307_get_time(hora,mim,seg) Obter tempo ///
/// ///
////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE seg;
BYTE mim;
BYTE hora;
BYTE dow;
BYTE dia;
BYTE mes;
BYTE ano;

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
BYTE segundos = 0;

i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x00); // REG 0
//delay_us(3);
i2c_stop();
//delay_us(3);
i2c_start();
i2c_write(0xD1); // RD from RTC
//delay_us(3);
segundos = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
delay_us(3);
i2c_stop();
segundos &= 0x7F;

delay_us(3);

i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x00); // REG 0
//delay_us(3);
i2c_write(bin2bcd(segundos)); // Start oscillator with current "seconds value
//delay_us(3);
i2c_stop();
i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x07); // Control Register
//delay_us(3);
i2c_write(0x80); // Disable squarewave output pin
//delay_us(3);
i2c_stop();

}

void ds1307_set_date_time(BYTE dia, BYTE mes, BYTE ano, BYTE dow, BYTE hora, BYTE mim, BYTE seg)
{
seg &= 0x7F;
hora &= 0x3F;

i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(seg)); // REG 0
i2c_write(bin2bcd(mim)); // REG 1
i2c_write(bin2bcd(hora)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(dia)); // REG 4
i2c_write(bin2bcd(mes)); // REG 5
i2c_write(bin2bcd(ano)); // REG 6
i2c_write(0x80); // REG 7 - Disable squarewave output pin
i2c_stop();
}

void ds1307_get_date(BYTE *dia, BYTE *mes, BYTE *ano, BYTE *dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
*dow = bcd2bin(i2c_read() & 0x7f); // REG 3
*dia = bcd2bin(i2c_read() & 0x3f); // REG 4
*mes = bcd2bin(i2c_read() & 0x1f); // REG 5
*ano = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

void ds1307_get_time(BYTE *hora, BYTE *mim, BYTE *seg)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
*seg = bcd2bin(i2c_read() & 0x7f);
*mim = bcd2bin(i2c_read() & 0x7f);
*hora = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;

temp = binary_value;
retval = 0;

while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}

return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;

temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;

// Now return: (Tens * 8) + (Tens * 2) + Ones

return(temp + (temp >> 2) + (bcd_value & 0x0f));
}



Veja o funcionamento na imagem ( simulado no proteus ISIS 7.0 )

rtc.png

Abaixo um código exemplo do uso da biblioteca com PIC 16F877A

OBS : esse código usa a biblioteca lcd_flex.c ( fornecida por mim neste tópico )


#include<16f877.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)
#fuses XT,NOWDT,PUT,NOBROWNOUT

#include<input.c>
#include<string.h>
#include<stdio.h>
#include<libDS1307.c>

#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B2
#define LCD_E PIN_B3

#include<lcd_flex.c>

#define BT_ajustaHora_e_mais pin_a0 //botao para entrar no ajuste de hora e dado++
#define BT_ajutaData_e_menos pin_a1 //botao para entrar no ajuste de data e dado--
#define BT_desloca_dir pin_a2 //desloca para direita
#define BT_desloca_esq pin_a3 //desloca cursor para esquerda
// [...] quantos botões a aplicação exigir

#define ajuste_hora 1
#define ajuste_data 2

/* VAriaveis globais */
byte _dia,_mes,_ano,_dow,_hora,_min,_seg; //Variaveis que guardam os dados
int op=0; // variavel que mostra qual botao foi prescionado

/* Protótipo das funções */
void carrega_dados();
boolean debouce();
void trata_botoes(int op);


/* Declaração das funções */
void carrega_dados()
{
ds1307_get_date(&_dia,&_mes,&_ano,&_dow);
ds1307_get_time(&_hora,&_min,&_seg);
}

boolean debounce(void)
{
disable_interrupts(INT_TIMER1); //desabilita interrupção
delay_ms(150);
if((!input(BT_ajustaHora_e_mais ))|(!input( BT_ajutaData_e_menos)))
{
return true;
}
else return false;
}

void trata_botoes(int op)
{
switch(op)
{
case ajuste_hora:
//[...] Aqui o usuario define os comando de ajuste de hora
//printf("ajuste de hora\r") // linha para debug
break;

case ajuste_data:
//[...] Aqui o usuario define os comando de ajuste de data
//printf("ajuste de data\r") // linha para debug
break;
default:
break;
}


}



#INT_TIMER1
void atualiza_hora()
{
/******************************************************/
/* A interrupção é chamada a cada 1s e atualiza */
/* os dados adquiridos pelo DS1307 através do TIMER1 */
/******************************************************/
char dia_semana[7][4]={"dom","seg","ter","qua","qui","sex","sab"};
char dia_hoje[4];
set_timer1(3036-get_timer1());
ds1307_get_time(&_hora,&_min,&_seg);
ds1307_get_date(&_dia,&_mes,&_ano,&_dow);
strcpy(dia_hoje,dia_semana[_dow-1]);
lcd_gotoxy(1,1);
printf(lcd_putc,"%s - %02d/%02d/%02d",dia_hoje,_dia,_mes,_ano);
lcd_gotoxy(5,2);
printf(lcd_putc,"%02d:%02d:%02d ",_hora,_min,_seg);
}



void main()
{
/***************************************/
/* Configurações dos PORTS e TIMER1 e */
set_tris_b(0);
set_tris_c(0b00011000);
set_tris_e(1);
set_tris_a(1);
enable_interrupts(INT_TIMER1);
setup_timer_1( T1_INTERNAL|T1_DIV_BY_8);
set_timer1(3036);
disable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
/**************************************/
//Inicializa o LCD e o DS1307
lcd_init();
delay_ms(1000);
ds1307_init();
while(1)
{ /**************************************************************************/
/* Tratamento de botões
/* Para o tratamento de botões pode usar as seguinte técnicas:
/* >> Botoões no PORTB - trata interrupção de mundança de estado
/* Vantagens: >Não é necessário scan em loop infinito
/* sempre então o evento será tratado independente
do tempo de prescionamento
/* Desvantagens:
/* >É preciso verificar qual botão foi prescionado
/* para então trata-lo
/* >Ruídos no PORTB podem causar mau funcionamento
/* >> Scan dos butões
/* Vantagens
/* >Maior estabilidade contra ruídos
/* >Cada botão pode ter sua própria função()
/* Desvantagens
/* >Tempo é crítico
/* >Debounce necessita ter outras interrupções desativadas
/* Neste programa será usado o scan
/* Apenas um modelo como a implementação é trabalhosa não foi feita aqui
/**************************************************************************/


if((!input(BT_ajustaHora_e_mais )))
{
if(debounce())
{
op = ajuste_hora;
trata_botoes(op);

}

}
else if((!input(BT_ajutaData_e_menos)))
{
if(debounce())
{
op = ajuste_data;
trata_botoes(op);

}
}
enable_interrupts(INT_TIMER1); //após tratar os botões habilita interrupção


}
}



Espero ter ajudado!

Abraço!

Link para o comentário
Compartilhar em outros sites

Olá Diego, como pedido corrigi o driver do DS1307 . Segue abaixo o driver:..........

Muito obrigado vou fazer os testes aqui depois eu comento aqui.Muito obrigado pela sua disposição em ensinar ao proximo,parabens pra você.

AlyssonMachado não abusando da sua boa vontade será que daria pra você fornecer o arquivo do proteus do relogio com ajustes que você fez.obrigado

Link para o comentário
Compartilhar em outros sites

Olá Diego, como pedido corrigi o driver do DS1307 . Segue abaixo o driver:

OBS: No código possui umas linhas comentadas ( //delay_us(3) ). Se depois de montado o projeto as vezes der erro de transmissão de dado descomente estas linhas.

ERRO que havia no arquivo:

funções:

void ds1307_get_date(BYTE *dia, BYTE *mes, BYTE *ano, BYTE *dow)

void ds1307_get_time(BYTE *hora, BYTE *mim, BYTE *seg)

Estavam com os parametro errados ( o erro era compilável ). Como as funções passam os valores por referencia deve ser enviado o endereço da variavel para um ponteiro ( &_mes -> *mes ) e estava enviando endereço para endereço ( &_mes -> &mes ) o que é erro do programador.

Concertado isso funcionou perfeitamente.

libDS1307.c


////////////////////////////////////////////////////////////////////////////////
/// DS1307.C ///
/// Driver for Real Time Clock ///
/// ///
/// ds1307_init() - Enable oscillator without clearing the seconds register -///
/// used when PIC loses power and DS1307 run from 3V BAT ///
/// - Disable squarewave output ///
/// ///
/// ds1307_set_date_time(dia,mes,ano,dow,hora,mim,seg) Set the date/time ///
/// ///
/// ds1307_get_date(dia,mes,ano,dow) Obter data ///
/// ///
/// ds1307_get_time(hora,mim,seg) Obter tempo ///
/// ///
////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)

BYTE seg;
BYTE mim;
BYTE hora;
BYTE dow;
BYTE dia;
BYTE mes;
BYTE ano;

BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)
{
BYTE segundos = 0;

i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x00); // REG 0
//delay_us(3);
i2c_stop();
//delay_us(3);
i2c_start();
i2c_write(0xD1); // RD from RTC
//delay_us(3);
segundos = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307
delay_us(3);
i2c_stop();
segundos &= 0x7F;

delay_us(3);

i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x00); // REG 0
//delay_us(3);
i2c_write(bin2bcd(segundos)); // Start oscillator with current "seconds value
//delay_us(3);
i2c_stop();
i2c_start();
i2c_write(0xD0); // WR to RTC
//delay_us(3);
i2c_write(0x07); // Control Register
//delay_us(3);
i2c_write(0x80); // Disable squarewave output pin
//delay_us(3);
i2c_stop();

}

void ds1307_set_date_time(BYTE dia, BYTE mes, BYTE ano, BYTE dow, BYTE hora, BYTE mim, BYTE seg)
{
seg &= 0x7F;
hora &= 0x3F;

i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(seg)); // REG 0
i2c_write(bin2bcd(mim)); // REG 1
i2c_write(bin2bcd(hora)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(dia)); // REG 4
i2c_write(bin2bcd(mes)); // REG 5
i2c_write(bin2bcd(ano)); // REG 6
i2c_write(0x80); // REG 7 - Disable squarewave output pin
i2c_stop();
}

void ds1307_get_date(BYTE *dia, BYTE *mes, BYTE *ano, BYTE *dow)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(0xD1);
*dow = bcd2bin(i2c_read() & 0x7f); // REG 3
*dia = bcd2bin(i2c_read() & 0x3f); // REG 4
*mes = bcd2bin(i2c_read() & 0x1f); // REG 5
*ano = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

void ds1307_get_time(BYTE *hora, BYTE *mim, BYTE *seg)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
*seg = bcd2bin(i2c_read() & 0x7f);
*mim = bcd2bin(i2c_read() & 0x7f);
*hora = bcd2bin(i2c_read(0) & 0x3f);
i2c_stop();

}

BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;

temp = binary_value;
retval = 0;

while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += temp;
break;
}
}

return(retval);
}


// Input range - 00 to 99.
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;

temp = bcd_value;
// Shifting upper digit right by 1 is same as multiplying by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;

// Now return: (Tens * 8) + (Tens * 2) + Ones

return(temp + (temp >> 2) + (bcd_value & 0x0f));
}



Veja o funcionamento na imagem ( simulado no proteus ISIS 7.0 )

rtc.png

Abaixo um código exemplo do uso da biblioteca com PIC 16F877A

OBS : esse código usa a biblioteca lcd_flex.c ( fornecida por mim neste tópico )


#include<16f877.h>
#use delay(clock=4000000)
#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)
#fuses XT,NOWDT,PUT,NOBROWNOUT

#include<input.c>
#include<string.h>
#include<stdio.h>
#include<libDS1307.c>

#define LCD_DB4 PIN_B4
#define LCD_DB5 PIN_B5
#define LCD_DB6 PIN_B6
#define LCD_DB7 PIN_B7
#define LCD_RS PIN_B2
#define LCD_E PIN_B3

#include<lcd_flex.c>

#define BT_ajustaHora_e_mais pin_a0 //botao para entrar no ajuste de hora e dado++
#define BT_ajutaData_e_menos pin_a1 //botao para entrar no ajuste de data e dado--
#define BT_desloca_dir pin_a2 //desloca para direita
#define BT_desloca_esq pin_a3 //desloca cursor para esquerda
// [...] quantos botões a aplicação exigir

#define ajuste_hora 1
#define ajuste_data 2

/* VAriaveis globais */
byte _dia,_mes,_ano,_dow,_hora,_min,_seg; //Variaveis que guardam os dados
int op=0; // variavel que mostra qual botao foi prescionado

/* Protótipo das funções */
void carrega_dados();
boolean debouce();
void trata_botoes(int op);


/* Declaração das funções */
void carrega_dados()
{
ds1307_get_date(&_dia,&_mes,&_ano,&_dow);
ds1307_get_time(&_hora,&_min,&_seg);
}

boolean debounce(void)
{
disable_interrupts(INT_TIMER1); //desabilita interrupção
delay_ms(150);
if((!input(BT_ajustaHora_e_mais ))|(!input( BT_ajutaData_e_menos)))
{
return true;
}
else return false;
}

void trata_botoes(int op)
{
switch(op)
{
case ajuste_hora:
//[...] Aqui o usuario define os comando de ajuste de hora
//printf("ajuste de hora\r") // linha para debug
break;

case ajuste_data:
//[...] Aqui o usuario define os comando de ajuste de data
//printf("ajuste de data\r") // linha para debug
break;
default:
break;
}


}



#INT_TIMER1
void atualiza_hora()
{
/******************************************************/
/* A interrupção é chamada a cada 1s e atualiza */
/* os dados adquiridos pelo DS1307 através do TIMER1 */
/******************************************************/
char dia_semana[7][4]={"dom","seg","ter","qua","qui","sex","sab"};
char dia_hoje[4];
set_timer1(3036-get_timer1());
ds1307_get_time(&_hora,&_min,&_seg);
ds1307_get_date(&_dia,&_mes,&_ano,&_dow);
strcpy(dia_hoje,dia_semana[_dow-1]);
lcd_gotoxy(1,1);
printf(lcd_putc,"%s - %02d/%02d/%02d",dia_hoje,_dia,_mes,_ano);
lcd_gotoxy(5,2);
printf(lcd_putc,"%02d:%02d:%02d ",_hora,_min,_seg);
}



void main()
{
/***************************************/
/* Configurações dos PORTS e TIMER1 e */
set_tris_b(0);
set_tris_c(0b00011000);
set_tris_e(1);
set_tris_a(1);
enable_interrupts(INT_TIMER1);
setup_timer_1( T1_INTERNAL|T1_DIV_BY_8);
set_timer1(3036);
disable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
/**************************************/
//Inicializa o LCD e o DS1307
lcd_init();
delay_ms(1000);
ds1307_init();
while(1)
{ /**************************************************************************/
/* Tratamento de botões
/* Para o tratamento de botões pode usar as seguinte técnicas:
/* >> Botoões no PORTB - trata interrupção de mundança de estado
/* Vantagens: >Não é necessário scan em loop infinito
/* sempre então o evento será tratado independente
do tempo de prescionamento
/* Desvantagens:
/* >É preciso verificar qual botão foi prescionado
/* para então trata-lo
/* >Ruídos no PORTB podem causar mau funcionamento
/* >> Scan dos butões
/* Vantagens
/* >Maior estabilidade contra ruídos
/* >Cada botão pode ter sua própria função()
/* Desvantagens
/* >Tempo é crítico
/* >Debounce necessita ter outras interrupções desativadas
/* Neste programa será usado o scan
/* Apenas um modelo como a implementação é trabalhosa não foi feita aqui
/**************************************************************************/


if((!input(BT_ajustaHora_e_mais )))
{
if(debounce())
{
op = ajuste_hora;
trata_botoes(op);

}

}
else if((!input(BT_ajutaData_e_menos)))
{
if(debounce())
{
op = ajuste_data;
trata_botoes(op);

}
}
enable_interrupts(INT_TIMER1); //após tratar os botões habilita interrupção


}
}



Espero ter ajudado!

Abraço!

Ola alyson tentei montar aqui o circuito e o codigo fonte,porém o mesmo esta dando erro.será que você não poderia postar um codigo fonte sem ajustes das horas, somente para mostrar as horas no display.

Ola alyson tentei montar aqui o circuito e o codigo fonte,porém o mesmo esta dando erro.Será que você poderia postar um codigo fonte sem ajustes das horas, somente para mostrar as horas no display.

Ola gostaria de saber se você consegui resolver este problema,pois tambem estou enfrentando o mesmo problema que você.Se você consegui resolver,poderia me ajudar.Tambem uso o ccs.Obrigado

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Olá Diego, o código que postei anteriormente usando pic16F877a funcionou aqui. Qual problema está tendo? qual suar versão do CCS? poste aqui o seu código pra eu dar uma olhada e testar aqui. :D To sem CCS no momento, troquei de pc e ainda não arrumei tudo. Assim que tiver posto um outro fonte aqui.

Link para o comentário
Compartilhar em outros sites

Olá Diego, o código que postei anteriormente usando pic16F877a funcionou aqui. Qual problema está tendo? qual suar versão do CCS? poste aqui o seu código pra eu dar uma olhada e testar aqui. :D To sem CCS no momento, troquei de pc e ainda não arrumei tudo. Assim que tiver posto um outro fonte aqui.

o erro é o mesmo que postei ai no forum, os valores das horas se alteram do nada com uns valores doidos 355:88:33

Link para o comentário
Compartilhar em outros sites

  • 6 anos depois...

@AlyssonMachado Teria como você  explicar como usa as bibliotecas que você criou/ajustou (I2C e a DS1307).

Porque tenho um projeto que necessita das horas,minutos e segundos para ligar e desligar um motor. Ai eu gostaria de saber como uso as funções das bibliotecas para pegar os valores do DS1307 e comparar com outra variável.

Até olhei seu exemplo aqui, mas não consegui pegar direito o funcionamento kkk.

 

No mais obrigado!!!

Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!