Relógio e Calendário Digital com RTC DS1307
Esse projeto trata-se de um relógio e um calendário digital. A base de contagem do tempo é o RTC DS1307. O DS1307 na mais é do que um Relógio de Tempo Real que se comunica com o microcontrolador via I2C.
O DS1307 possui 7 registros internos destinados para a contagem dos segundos, minutos, horas, dia da semana, dia do mês, mês e ano. Esse RTC também "sabe" se é ano bissexto ou não e possui a opção de horário 24 horas ou 12 Horas (AM - PM).
Uma coisa ruim que eu acho desse DS1307 é que ele trabalha com número BCD ao invés de trabalhar com binários (que é bem mais fácil).
Uma coisa ruim que eu acho desse DS1307 é que ele trabalha com número BCD ao invés de trabalhar com binários (que é bem mais fácil).
Ao pressionar a chave S1, altera a seleção de ajuste (segundos, minutos, ... ). A chave S2 e S3, altera o valor, incrementando-o ou decrementando-o respectivamente.
No projeto foi utilizado um Clock de 4MHz para o PIC e para o RTC foi de 32,768KHz.
DOWNLOAD:
Firmware: Clock.hex;
Arquivo de simulação do Proteus: Clock.DSN;
CÓDIGO-FONTE:
MikroC PRO PIC
sbit LCD_RS at RB4_bit; sbit LCD_EN at RB5_bit; sbit LCD_D4 at RB6_bit; sbit LCD_D5 at RB1_bit; sbit LCD_D6 at RB2_bit; sbit LCD_D7 at RB3_bit; sbit LCD_RS_Direction at TRISB4_bit; sbit LCD_EN_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB6_bit; sbit LCD_D5_Direction at TRISB1_bit; sbit LCD_D6_Direction at TRISB2_bit; sbit LCD_D7_Direction at TRISB3_bit; unsigned short segundos, minutos, horas, semana, dia, mes, ano; unsigned short sgs, mins, hrs, ss, dd, mm, yy; unsigned short cnt=7; //Função para converter BCD para string e escrever no LCD void BcdToStr(unsigned short x, unsigned short y, unsigned short var) { unsigned short var1, var2; //var1 = (var << 4) + 0x30; //Tá errado!!!! var1 = (var >> 4) + 0x30; //Erro corrigido... Lcd_Chr(x,y,var1); var2 = (var & 0x0F) + 0x30; Lcd_Chr_CP(var2); } //função para ajustar o valor void escrita_i2c(unsigned short registro, unsigned short valor) { i2c1_stop(); //caso o barramento estiver ocupado envia um sinal de STOP i2c1_start(); // envia um sinal de START i2c1_wr(0xD0); //endereço do RTC no barramento e fazer a escrita i2c1_wr(registro); //endereço do registro(segundos=0x00, ...) i2c1_wr(valor); // valor que você quer escrever i2c1_stop(); //envia um sinal de STOP } //função que daz a leitura dos dados void leitura_i2c() { i2c1_start(); // Envia um sinal de START i2c1_wr(0xD0); //endereço no barramento e indicação de escrita i2c1_wr(0x00); //endereço inicial i2c1_Repeated_Start(); //Restart no barramento i2c1_wr(0xD1); // endereço no barramento e indicação de leitura segundos = i2c1_rd(1); //lê o 1º endereço e informa que ira continuar a leitura minutos = i2c1_rd(1); //lê o 2º endereço e informa que ira continuar a leitura horas = i2c1_rd(1); //lê o 3º endereço e informa que ira continuar a leitura semana = i2c1_rd(1); //lê o 4º endereço e informa que ira continuar a leitura dia = i2c1_rd(1); //lê o 5º endereço e informa que ira continuar a leitura mes = i2c1_rd(1); //lê o 6º endereço e informa que ira continuar a leitura ano = i2c1_rd(0); //lê o 7º endereço e informa que não ira mais ler i2c1_stop(); // envia um sinal de STOP } void encontrar_semana() { switch(semana) { case 1: Lcd_Out(2,13,"DOMINGO");break; case 2: Lcd_Out(2,13,"SEGUNDA");break; case 3: Lcd_Out(2,13," TERCA ");break; case 4: Lcd_Out(2,13,"QUARTA ");break; case 5: Lcd_Out(2,13,"QUINTA ");break; case 6: Lcd_Out(2,13," SEXTA ");break; case 7: Lcd_Out(2,13,"SABADO ");break; } } //função que escreve no LCD qual ajuste você está fazendo void funcao(unsigned short num) { lcd_Out(1,13,"ADJ"); switch(num) { case 0: Lcd_Out(1,17,"SGS");break; case 1: Lcd_Out(1,17,"MIN");break; case 2: Lcd_Out(1,17,"HRS");break; case 3: Lcd_Out(1,17,"DIA");break; case 4: Lcd_Out(1,17,"DATE");break; case 5: Lcd_Out(1,17,"MES ");break; case 6: Lcd_Out(1,17,"ANO");break; case 7: Lcd_Out(1,17,"OFF");break; } } void main() { bit oldstate; TRISD = 255; I2C1_Init( 100000 ); Lcd_Init(); //inicia LCD Lcd_Cmd(_LCD_CLEAR); //Limpa LCD Lcd_cmd(_LCD_CURSOR_OFF); //desliga cursor do LCD funcao(7); while(1) { BcdToStr(1,1,horas); Lcd_Out_CP(":"); BcdToStr(1,4,minutos); Lcd_Out_CP(":"); BcdToStr(1,7,segundos); BCdToStr(2,1,dia); Lcd_Out_CP("/"); BCdToStr(2,4,mes); Lcd_Out_CP("/"); BCdToStr(2,7,ano); leitura_i2c(); if(!PORTD.F0) oldstate=1; //para cada vez que pressionar o botao, altera a função de ajuste if(PORTD.F0 && oldstate) { cnt++; if(cnt==8) cnt=0; funcao(cnt); oldstate=0; } if(cnt==0) { if(PORTD.F1 && !PORTD.F2) { sgs = Bcd2Dec(segundos); //recebe o valor, converte-o sgs++; // incrementa-o if(sgs==60) sgs=0; escrita_i2c(0x00,Dec2Bcd(sgs)); //converte-o e escreve no RTC }else if(!PORTD.F1 && PORTD.F2) { sgs = Bcd2Dec(segundos); sgs--; if(sgs > 0 || sgs < 59) sgs=59; escrita_i2c(0x00,Dec2Bcd(sgs)); } } else if(cnt==1) { if(PORTD.F1 && !PORTD.F2) { mins = Bcd2Dec(minutos); mins++; if(mins==60) mins=0; escrita_i2c(0x01,Dec2Bcd(mins)); }else if(!PORTD.F1 && PORTD.F2) { mins = Bcd2Dec(minutos); mins--; if(mins > 0 || mins < 59) mins=59; escrita_i2c(0x01,Dec2Bcd(mins)); } } else if(cnt==2) { if(PORTD.F1 && !PORTD.F2) { hrs = Bcd2Dec(horas); hrs++; if(hrs==24) hrs=0; escrita_i2c(0x02,Dec2Bcd(hrs)); }else if(!PORTD.F1 && PORTD.F2) { hrs = Bcd2Dec(horas); hrs--; if(hrs > 0 || hrs < 23) hrs=23; escrita_i2c(0x02,Dec2Bcd(hrs)); } } else if(cnt==3) { if(PORTD.F1 && !PORTD.F2) { ss = Bcd2Dec(semana); ss++; if(ss==8) ss=1; escrita_i2c(0x03,Dec2Bcd(ss)); } else if(!PORTD.F1 && PORTD.F2) { ss = Bcd2Dec(semana); ss--; if(ss==0) ss=7; escrita_i2c(0x03,Dec2Bcd(ss)); } } else if(cnt==4) { if(PORTD.F1 && !PORTD.F2) { dd = Bcd2Dec(dia); dd++; if(dd==32) dd=1; escrita_i2c(0x04,Dec2Bcd(dd)); } else if(!PORTD.F1 && PORTD.F2) { dd = Bcd2Dec(dia); dd--; if(dd > 1 || dd < 31) dd=31; escrita_i2c(0x04,Dec2Bcd(dd)); } } else if(cnt==5) { if(PORTD.F1 && !PORTD.F2) { mm = Bcd2Dec(mes); mm++; if(mm==13) mm=1; escrita_i2c(0x05,Dec2Bcd(mm)); } else if(!PORTD.F1 && PORTD.F2) { mm = Bcd2Dec(mes); mm--; if(mm==0) mm=12; escrita_i2c(0x05,Dec2Bcd(mm)); } } else if(cnt==6) { if(PORTD.F1 && !PORTD.F2) { yy = Bcd2Dec(ano); yy++; if(yy==100) yy=0; escrita_i2c(0x06,Dec2Bcd(yy)); } else if(!PORTD.F1 && PORTD.F2) { yy = Bcd2Dec(ano); yy--; if(yy > 0 || yy < 99) yy=99; escrita_i2c(0x06,Dec2Bcd(yy)); } } encontrar_semana(); Delay_ms(200); } }
Boa tarde ,montei este circuito mas não esta funcionando, gostaria que me ajudasse,coloquei um cristal externo de 4mhz mas mas se eu medir em cima dos pinos de osc ele não tem nada, e é no programa o problemas, pois gravei outro programa no pic e coloquei no mesmo circuito montado e teve oscilação do cristal ....fico no aguardo por uma ajuda...Desde já agradeço
ResponderExcluirBoa tarde!! O código não interfere no funcionamento do cristal. A causas pode ser algum mau contato nos pinos ou o tipo de cristal selecionado. Na hora de gravar o pic, configure os fusiveis e selecione o cristal do tipo XT.
ExcluirObrigado Tiago Henrique,montei funcionou certinho,era somente as configurações na hora de gravar mesmo...
ResponderExcluirAgora estou com outro problema eu preciso colocar um PCF8563 no lugar deste DS1307 alguém saberia me ajudar no que preciso alterar no programa para que funcione com esse PCF8563?
Quando li seu comentário anterior, ja comecei a fazer o programa kkkkk!!!
ExcluirFiz ele um pouco diferente, optando por utilizar struct.
#define PCF8563_I2C_ADDR 0xA2
#define PCF8563_CONTROL1 0x00 //control/status 1
#define PCF8563_CONTROL2 0x01 //control/status 2
#define PCF8563_CLKOUT 0x0D //CLKOUT control
#define PCF8563_TCONTROL 0x0E //timer control
#define PCF8563_TIMER 0x0F //timer countdown value
#define PCF8563_SECONDS 0x02 //0..59 BCD
#define PCF8563_MINUTES 0x03 //0..59 BCD
#define PCF8563_HOURS 0x04 //0..23 BCD
#define PCF8563_DAYS 0x05 //1..31 BCD
#define PCF8563_WEEKDAY 0x06 //0..6
#define PCF8563_MONTHS 0x07 //0..12
#define PCF8563_YEARS 0x08 //0..99 BCD
#define PCF8563_MINUTE_ALARM 0x09 //0..59 BCD
#define PCF8563_HOUR_ALARM 0x0A //0..23 BCD
#define PCF8563_DAY_ALARM 0x0B //0..31 BCD
#define PCF8563_WEEKDAY_ALARM 0x0C //0..6
typedef struct
{
char year; //0..99
char month; //1..12
char week; //0..6
char days; //1..31
char hour; //0..23
char min; //0..59
char sec; //0..59
}TIME_STRUCT;
TIME_STRUCT ts = {13, 8, 1, 7, 13, 40, 0};
void PCF8563_Init()
{
I2C1_Init(400000);
I2C1_start();
I2C1_Wr(PCF8563_I2C_ADDR);
I2C1_Wr(PCF8563_CONTROL1);
I2C1_Wr(0x00);
I2C1_Wr(0x00);
I2C1_Stop();
}
void PCF8563_setDate(TIME_STRUCT *Pts)
{
I2C1_start();
I2C1_Wr(PCF8563_I2C_ADDR);
I2C1_Wr(PCF8563_SECONDS);
I2C1_Wr(Dec2Bcd(Pts->sec));
I2C1_Wr(Dec2Bcd(Pts->min));
I2C1_Wr(Dec2Bcd(Pts->hour));
I2C1_Wr(Dec2Bcd(Pts->days));
I2C1_Wr(Dec2Bcd(Pts->week));
I2C1_Wr(Dec2Bcd(Pts->month));
I2C1_Wr(Dec2Bcd(Pts->year));
I2C1_Stop();
}
void PCF8563_getDate(TIME_STRUCT *Pts)
{
I2C1_start();
I2C1_Wr(PCF8563_I2C_ADDR);
I2C1_Wr(PCF8563_SECONDS);
I2C1_Repeated_Start();
I2C1_Wr(PCF8563_I2C_ADDR | 1);
Pts->sec = Bcd2Dec(I2C1_Rd(1) & 0x7F);
Pts->min = Bcd2Dec(I2C1_Rd(1) & 0x7F);
Pts->hour = Bcd2Dec(I2C1_Rd(1) & 0x3F);
Pts->days = Bcd2Dec(I2C1_Rd(1) & 0x3F);
Pts->week = Bcd2Dec(I2C1_Rd(1) & 0x07);
Pts->month = Bcd2Dec(I2C1_Rd(1) & 0x1F);
Pts->year = Bcd2Dec(I2C1_Rd(0));
I2C1_Stop();
}
void main()
{
uart1_init(9600);
delay_ms(10);
PCF8563_Init();
PCF8563_setDate(&ts);
while(1)
{
PCF8563_getDate(&ts);
uart1_write((ts.hour/10) + '0');
uart1_write((ts.hour%10) + '0');
uart1_write(':');
uart1_write((ts.min/10) + '0');
uart1_write((ts.min%10) + '0');
uart1_write(':');
uart1_write((ts.sec/10) + '0');
uart1_write((ts.sec%10) + '0');
uart1_write(13);
delay_ms(500);
}
}
caso queira adicionar algum botao, ficaria assim
Excluirif(Botao==1)//pino qualquer
{
PCF8563_getDate(&ts);
ts.sec++;
if(ts.sec>59) ts.sec = 0;
PCF8563_setDate(&ts);
}
coloquei rodar esse seu programa ai e percebi que ele esta faltando a parte que faz aparecer no lcd né, e to apanhando até agora pra tentar fazer isso e não consigo kkkk, isso que da não intender praticamente nada de programação né hahaha
ResponderExcluirBoa noite Tiago! Gostei desse relogio, estou trabalhando nele aqui, ja compilei e tudo.
ResponderExcluirAgora quero colocar um lm 35 para ler temperatura junto com o relogio, depois vou alterar o lcd para um de 4 linhas, Não sei como colocar o codigo para o lm 35, sou novo em Mikroc, Poderia me dar uma mãozinha ai? Obrigado pelo post compartilhado com a gente.
unsigned LM35_ReadTemp()
Excluir{
unsigned temp;
temp = ADC_Read(0);
temp = temp * 100 / 206;
return temp;
}
Insira a função acima e habilita a biblioteca ADC.
Use a função WordToStr para converter o valor para string, depois vc escreve no lcd.
Boa noite.
ResponderExcluirEstou acompanhando seu blog, e seu projeto 15 do relógio calendário,e ele é bem parecido com o projeto que eu preciso para um trabalho, só que eu precisaria acrescentar um lote e turno na programação e no display, sendo o lote com 6 dígitos e o turno alternando de 1 à 3 a cada 8hrs. LOTE:227021 OBS: 227 CORRESPONDE O DIA DO ANO , 02 NUMERO DA MAQUINA É FIXO, 1 TURNO OBS: 1 DAS 5:01 AS 13:20 , 2 DAS 13:21 AS 21:40 , 3 DAS 21:41 AS 5:00.
Será que você poderia me ajudar?
Desde já agradeço sua atenção, fico a disposição para qualquer esclarecimento.
envie mais detalhes pro meu email: microcontrolandos2012@gmail.com
ExcluirBoa tarde,
ResponderExcluirmontei o circuito todo correto mais na hora de ligar aparece apenas ??:??: e ??/??/?? ,.... o que eu faço???
O meu tb apareceu isso, eu tinha alimentado o 1307 apenas com 3v, ai coloquei 5 volts na outra entrada e funcionou
ExcluirNo proteus ele só vai funcionar com 5 volts, mas no físico só suporta 3.3 volts.
ExcluirNão. De acordo com o datasheet o DS1307 suporta 5V. Veja se há mal contato, ou os resistores de pullup..
ExcluirBoa tarde!!!
ResponderExcluirParabéns pelo blog!!!
Estou acompanhando seu blog, e seu projeto 15 do relógio calendário,e ele é bem igual com o projeto que eu preciso para um trabalho de facull, mas ele tem que funcionar com o nokia 6610, alguém pode me ajuda? Minha duvida esta nesta parte do BCD...
//Função para converter BCD para string e escrever no LCD
void BcdToStr(unsigned short x, unsigned short y, unsigned short var){
unsigned short var1, var2;
var1 = (var >> 4) + 0x30;
Lcd_Chr(x,y,var1);
var2 = (var & 0x0F) + 0x30;
Lcd_Chr_CP(var2);
}
CARLOS
ResponderExcluirOlá sou novo por aqui gostaria de saber se tem como fazer este relógio com o pic16f628?
Tem sim. Voce terá que usar a biblioteca Soft_I2C para fazer a comunicacao com o DS1307.
ExcluirGostei muito do post. O seu blog é um guia de referência quando o assunto é mikroc. Como faço pra ele armazenar a hora e data atual quando for desligado ou a energia elétrica faltar, pois mesmo com a bateria isto não está acontecendo, sempre que ele é reiniciado a hora que ele mostra é a hora acertada na programação, aí tem que acertar toda vez que religá-lo.
ResponderExcluirMuito obrigado.
O problema era no código...retirei a função "programa_i2c()". Esta funcao resetava os valores do RTC sempre que o pic era ligado.
ExcluirAbraços.
Tiago, eu já havia comentado esta função pra ver se o programa continuava a atualizar a hora mesmo depois de desligado, porém, percebi que sem ela o programa não roda. Na simulação se percebe que o rtc atualiza, mas o display fica congelado, as teclas não funcionam, fica tudo travado, testei também na bancada e acontece o mesmo.
Excluiralem de ter comentada a funcao, tinha que inicializar o modulo I2C: "I2C1_Init(100000)".
ExcluirFuncionou. Obrigado.
ExcluirComo eu acho o componente l2C no proteus? Como está o nome dele lá?
ResponderExcluirNa barra lateral esquerda, localize o botao "Virtual Instruments Mode" e selecione "I2C Debugger"
ExcluirMeu mikroC Alega que o termo Bdc2Dec não foi declarado quando coloco esse programa. Te alguma idéia de qual seja o problema?
ResponderExcluirVoce habilitou a biblioteca Conversions? Tente isso. Tome cuidado tbm na escrita, o certo é "Bcd2Dec"
ExcluirSim, todas as bibliotecas estão ativadas, e no programa esta escrito correto!
Excluirse eu busco no help "Bcd2Dec" não encontra, encontra apenas o "Dec2Bcd"
Qual a versão do seu MikroC?
ExcluirEste comentário foi removido pelo autor.
ExcluirMikroc pro 2009
Excluirli que pode ser algo do mikroc "pro", vou tentar arranjar outro. =/
ExcluirBoa noite Tiago sou Osmar e preciso de um programa usando ds1307 só que tem que ser feito com o Source Boost IDE criado na linguagem boost C onde mostra a data e as horas em um display lcd 16x2
ResponderExcluironde eu troco a hora e os dias com botões.
Ti agradeço desde agora.
Bom Dia Thiago!
ResponderExcluirMontei esse circuito no Proteus mas o LCD fica congelado, oque pode ser?
Verifique se você colocou os resistores de pull-up nas linhas SCL e SDA.
ExcluirAinda continua travado, poderia me passar o aquivo do MickroC do projeto e o compilado agradeco, bruno.ruinho@gmaill.com
ExcluirOlá Tiago, primeiramente parabéns pelo blog, e gostaria de saber se você tem algum projeto (ou mesmo o código fonte para este projeto) para acionamento semanal, pois preciso acionar um motor uma vez por semana e com controle do horário e do dia da semana, para um silo para secagem de milho. Você teria alguma coisa que me atenda?
ResponderExcluirOBS: Não entendo muito de programação.
Desde já muito obrigado
Tentei simular no Proteus 8.1 e está ficando com display parado, não faz ajuste em nenhum botão. Usei o clock.hex. Alguém sabe o que está acontecendo?
ResponderExcluirCompila o fonte na sua maquina que funciona, não esqueça de corrigir a função para converter o bcd, o correto é deslocar os bits para a direita e não para a esquerda como está.
Excluir
ResponderExcluirbom dia Tiago,
Eu consegui compilar seu projeto do relógio calendário com ds1307 para PIC16f877a modifiquei os comandos I2c1 para I2C porque o compilador não aceitou I2C1....acho que é porque o pic16f877a só tem um HD I2c não é isso ?
e alterei o config do LCD
Compílou mas acredito que o barramento I2C não funciona porque mostra no lcd ? : ? : ? ?/ ?/ ? pode me ajudar ?
Eu vi os pulsos no barramento I2C aparente mente esta ok , alimentei o vbat com 3,0 vdc , resitor de pull up de 2K2 no barramento I2C , xt no pic 4 MHZ e 32768 no rtc
Na função de conversão de BCD possui um erro no deslocamento dos bits.
ResponderExcluirvoid BcdToStr(unsigned short x, unsigned short y, unsigned short var)
{
unsigned short var1, var2;
var1 = (var << 4) + 0x30; Linha com erro, o correto seria deslocar para direita.
Lcd_Chr(x,y,var1);
var2 = (var & 0x0F) + 0x30;
Lcd_Chr_CP(var2);
}
Função corrigida:
void BcdToStr(unsigned short x, unsigned short y, unsigned short var)
{
unsigned short var1, var2;
var1 = (var >> 4) + 0x30; Linha Corrigida, deslocando para direita
Lcd_Chr(x,y,var1);
var2 = (var & 0x0F) + 0x30;
Lcd_Chr_CP(var2);
}
Boa noite Tiago, em primeiro lugar, deixo os parabéns pelas matérias, muito boas, sempre busco informações em seu blog, estou utilizando um 18F4520 e quando compilo o código fonte na versão 6.6.1 ele me da o seguinte erro "15 393 'ss' Identifier redefined" da linha "unsigned short sgs, mins, hrs,ss, dd, mm, yy;" referenciando para SS, será que tenho que mudar alguma linha de código para este micro, na simulação o display fica stop e não aceita configuração, obrigado.
ResponderExcluirTiago, você poderia me ajudar a fazer um software para gerenciar um equpamento? Você é de qual estado? Se tiver, eu pago pela ajuda. Um abraço.
ResponderExcluirprecisava do mesmo código e do programa para fazer um relogio digital, porém utilizando matriz de led. alguem poderia ajudar??
ResponderExcluirComo eu uso esse código com o arduino?
ResponderExcluirEstou fazendo esse relogio RTC para um projeto da faculdade porém o professor exige que seja com o microcontrolador atmega328p(arduino) essa programão é para pic e não consegui arruma-la para arduino, tem como ajudar?
ACOMPANHANDO...
ResponderExcluirqual o nome do componente no proteus q marca 12C???
ResponderExcluircopiei esse codigo maisno display da erro ao inclemenar os minutos
ResponderExcluir