Ir ao conteúdo
  • Cadastre-se

Problemas com DS1307 + PIC em C


Visitante

Posts recomendados

Bom dia pessoal!

Estou com um projeto de controle para um sinal de escola.

O projeto consiste em um circuito que dispara o sinal no inicio das aulas, nos intervalos, e no término das aulas, nos 3 turnos e só de segunda a sexta com as seguintes especificações:

Vai ter um display LCD16X2, Um teclado com 6 botões, Saída a relé para o acionamento da saída e usando um microcontrolador PIC18f452.

Como estava difícil implementar o calendário e o relógio com o microcontrolador, resolvi usar o ccto integrado RTC DS1307, mas meus problemas estavam apenas começando.

Depois de semanas de pesquisas (aqui no fórum e no google), consegui a comunicar com o RTC, porém, consigo apenas modificar os valores no mesmo, mas não consigo ler os valores do RTC.

acredito que seja as funções de leitura do RTC ou nas conversões nos dados de saída, mas como entendo pouco de programação, não consegui resolver o problema.

O problema é que tenho prazo para entregar o projeto montado e operante, e decidi pedir ajuda a vocês.

Se só conseguir ler o RTC, já "desgarra" o meu projeto.

Segue a seguir o código fonte e as bibliotecas que estou usando, tudo é de apenas testes então não reparem a bagunça, muitas funções inacabadas e não usadas.

Código fonte:

#include "16f877a.h"
#use delay(clock=20M)
#fuses hs,nowdt,nobrownout,nolvp,put,noprotect
#include"lcd.c"
#include"RTC_DS1307(original).c"
#include<string.h>

#define mais input(pin_a0)
#define menos input(pin_a1)
#define ok input(pin_a4)
#define muda input(pin_a2)

#define rele pin_a3

short seleciona_menu=0; //0=configura tempo 1=lê dados do rtc
short entra=0; //fica dentro das funções
short fica=0; //fica dentro do comando até salvar

short bisexto=0; //se o ano é bisexto, bisexto=1; se não, bisexto=0

int seconds=0;
int minutes=0;
int hours=0;
int date=0;
int day=0;
int month=0;
int year=0;



/*

// esta funcao converte um valor binario de 8 bits
// para um valor BCD de 8 bits. Range 0 a 99.

int toBCD(int val_bin){
int temp;
int retval;
temp = val_bin;
retval = 0;
for(;{
// obtem os digitos da dezenas atraves de multiplas subtracoes
// de 10 da variavel val_bin
if(temp >= 10)
{
temp -= 10;
retval += 0x10; // increment tens digit
}
else // get ones digit by adding remainder
{
retval += temp; // adjusted result
break;
}
}
return(retval);
}

// esta funcao converte um valor BCD de 8 bits
// para um valor binario de 8 bits.

int toBIN(int val_bcd){
int i;
int temp;
int unid;
int dez;
temp = val_bcd;
temp &= 0x0f;
unid = temp;
hora_unid[j] = temp;
temp = val_bcd;
for(i=0;i<4;i++) shift_right(&temp,1,0);
hora_dez[j]= temp;
temp *= 10;
dez = temp;
temp = dez + unid;
j++;
if (j>6) j=0;
return(temp);
}


*/

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

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

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

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

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

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

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


void configura_tempo()
{
while(entra)
{
lcd_escreve("\fAcerte as\nHoras:");
while(fica)////hora
{
if(mais)
{
hours++;
if(hours>23) hours=0;
printf(lcd_escreve,"\fAcerte as Horas:\n %u:%u",hours,minutes);
while(mais);
}
if(menos)
{
hours--;
if(hours==255) hours=23;
printf(lcd_escreve,"\fAcerte as Horas:\n %u:%u",hours,minutes);
while(menos);
}
if(muda)
{
lcd_escreve("\fAcerte os\nMinutos:");
fica=!fica;
while(muda);
}
}
while(!fica)////minuto
{
if(mais)
{
minutes++;
if(minutes>59) minutes=0;
printf(lcd_escreve,"\fAcerte minutos:\n %u:%u",hours,minutes);
while(mais);
}
if(menos)
{
minutes--;
if(minutes==255) minutes=59;
printf(lcd_escreve,"\fAcerte minutos:\n %u:%u",hours,minutes);
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fAcerte o Ano:");
while(muda);
}
}
while(fica)////ano
{
if(mais)
{
year++;
//if(date>12) month=0;
printf(lcd_escreve,"\fAcerte o ano:\n %u/%u/%u",date,month,year);
while(mais);
}
if(menos)
{
year--;
//if(minutes==255) minutes=59;
printf(lcd_escreve,"\fAcerte o ano:\n %u/%u/%u",date,month,year);
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fO ano é\nbisexto?");
while(muda);
}
}
while(!fica)////bisexto
{
if(mais)
{
bisexto=1;
lcd_escreve("\fSim.");
while(mais);
}
if(menos)
{
bisexto=0;
lcd_escreve("\fNao.");
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fAcerte o Mes:");
while(muda);
}
}
while(fica)////mes
{
if(mais)
{
month++;
if(month>12) month=0;
printf(lcd_escreve,"\fAcerte o mes:\n %u/%u/%u",date,month,year);
while(mais);
}
if(menos)
{
month--;
if(month==255) month=12;
printf(lcd_escreve,"\fAcerte o mes:\n %u/%u/%u",date,month,year);
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fAcerte o dia\ndo Mes:");
while(muda);
}
}
while(!fica)////dia do mes
{
if(mais)
{
date++;
if(month==(1 || 3 || 5 || 7 || 8 || 10 || 12))//mes de 31 dias
{
if(date>31) date=1;
}
if(month==(4 || 6 || 9 || 11))//mes de 30 dias
{
if(date>30) date=1;
}
if(month==2 && bisexto==1)//mes de fevereiro com 29dias
{
if(date>29) date=1;
}
if(month==2 && bisexto==0)//mes de fevereiro com 28dias
{
if(date>28) date=1;
}
printf(lcd_escreve,"\fAcerte o dia:\n %u/%u/%u",date,month,year);
while(mais);
}
if(menos)
{
date--;
if(month==(1 || 3 || 5 || 7 || 8 || 10 || 12))//mes de 31 dias
{
if(date==0) date=31;
}
if(month==(4 || 6 || 9 || 11))//mes de 30 dias
{
if(date==0) date=30;
}
if(month==2 && bisexto==1)//mes de fevereiro com 29dias
{
if(date==0) date=29;
}
if(month==2 && bisexto==0)//mes de fevereiro com 28dias
{
if(date==0) date=28;
}
printf(lcd_escreve,"\fAcerte o dia:\n %u/%u/%u",date,month,year);
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fAcerte o dia\nda Semana:");
while(muda);
}
}
while(fica)////dia da semana
{
if(mais)
{
day++;
if(day>7) day=1;
printf(lcd_escreve,"\fHoje é %s.",dia_semana_converte(day));
while(mais);
}
if(menos)
{
day--;
if(day==0) day=7;
printf(lcd_escreve,"\fHoje é %s.",dia_semana_converte(day));
while(menos);
}
if(muda)
{
fica=!fica;
lcd_escreve("\fPressione ok/nppara salvar:");
while(muda);
}
}
while(!fica)
{
if(muda)
{
fica=!fica;
while(muda);
}
if(ok)
{
ds1307_set_date_time(date,month,year,day,hours,minutes,0);
lcd_escreve("\fSalvo");
while(ok);
}
}

}
}



void main()
{
lcd_ini();
while(1)
{
a:
lcd_escreve("\f Le tempo/data\n Conf. tempo");
while(!entra)
{
if(seleciona_menu)
{
lcd_pos_xy(0,0);
lcd_escreve("a");
while(!entra && seleciona_menu)
{
if(ok)
{
//lcd_escreve("\fentrou");
delay_ms(1000);
entra=1;
fica=1;
while(ok);
configura_tempo();
}
if(mais || menos)
{
seleciona_menu=!seleciona_menu;
while(mais || menos);
}
}
}

if(!seleciona_menu)
{
lcd_pos_xy(0,1);
lcd_escreve("a");
while(!entra && !seleciona_menu)
{
if(ok)
{
//lcd_escreve("\fentrou");
delay_ms(1000);
while(ok);
ds1307_get_date(date,month,year,day);
printf(lcd_escreve,"\f%u/%u/%u\n%s",date,month,year,dia_semana_converte(day));
delay_ms(1000);
ds1307_get_time(hours,minutes,seconds);
printf(lcd_escreve,"\f%u:%u:%u",hours,minutes,seconds);
delay_ms(1000);
goto a;
}
if(mais || menos)
{
seleciona_menu=!seleciona_menu;
while(mais || menos);
}
}
}
}
}
}

A biblioteca do lcd:

/************************************************************************/
/* MOD_LCD.C - Biblioteca de manipula??o de m?dulo LCD */
/* */
/* Autor: F?bio Pereira */
/* */
/************************************************************************/

// As defini??es a seguir s?o utilizadas para acesso aos pinos do display
// caso o pino RW n?o seja utilizado, comente a defini??o lcd_rw
#ifndef lcd_enable
#define lcd_enable pin_b6 // pino enable do LCD
#define lcd_rs pin_b7 // pino rs do LCD
//#define lcd_rw pin_e2 // pino rw do LCD
#define lcd_d4 pin_b2 // pino de dados d4 do LCD
#define lcd_d5 pin_b3 // pino de dados d5 do LCD
#define lcd_d6 pin_b5 // pino de dados d6 do LCD
#define lcd_d7 pin_b4 // pino de dados d7 do LCD
#endif

#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 linhas
#define lcd_seg_lin 0x40 // Endere?o da segunda linha na RAM do LCD

// a constante abaixo define a seq??ncia de inicializa??o do m?dulo LCD
byte CONST INI_LCD[4] = {0x20 | (lcd_type << 2), 0xf, 1, 6};

byte lcd_le_byte()
// l? um byte do LCD (somente com pino RW)
{
byte dado;
// configura os pinos de dados como entradas
input(lcd_d4);
input(lcd_d5);
input(lcd_d6);
input(lcd_d7);
// se o pino rw for utilizado, coloca em 1
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_high(lcd_enable); // habilita display
dado = 0; // zera a vari?vel de leitura
// l? os quatro bits mais significativos
if (input(lcd_d7)) bit_set(dado,7);
if (input(lcd_d6)) bit_set(dado,6);
if (input(lcd_d5)) bit_set(dado,5);
if (input(lcd_d4)) bit_set(dado,4);
// d? um pulso na linha enable
output_low(lcd_enable);
output_high(lcd_enable);
// l? os quatro bits menos significativos
if (input(lcd_d7)) bit_set(dado,3);
if (input(lcd_d6)) bit_set(dado,2);
if (input(lcd_d5)) bit_set(dado,1);
if (input(lcd_d4)) bit_set(dado,0);
output_low(lcd_enable); // desabilita o display
return dado; // retorna o byte lido
}

void lcd_envia_nibble( byte dado )
// envia um dado de quatro bits para o display
{
// coloca os quatro bits nas saidas
output_bit(lcd_d4,bit_test(dado,0));
output_bit(lcd_d5,bit_test(dado,1));
output_bit(lcd_d6,bit_test(dado,2));
output_bit(lcd_d7,bit_test(dado,3));
// d? um pulso na linha enable
output_high(lcd_enable);
output_low(lcd_enable);
}


void lcd_envia_byte( boolean endereco, byte dado )
{
// coloca a linha rs em 0
output_low(lcd_rs);
// aguarda o display ficar desocupado
//while ( bit_test(lcd_le_byte(),7) ) ;
// configura a linha rs dependendo do modo selecionado
output_bit(lcd_rs,endereco);
delay_us(100); // aguarda 100 us
// caso a linha rw esteja definida, coloca em 0
#ifdef lcd_rw
output_low(lcd_rw);
#endif
// desativa linha enable
output_low(lcd_enable);
// envia a primeira parte do byte
lcd_envia_nibble(dado >> 4);
// envia a segunda parte do byte
lcd_envia_nibble(dado & 0x0f);
}


void lcd_ini()
// rotina de inicializa??o do display
{
byte conta;
output_low(lcd_d4);
output_low(lcd_d5);
output_low(lcd_d6);
output_low(lcd_d7);
output_low(lcd_rs);
#ifdef lcd_rw
output_high(lcd_rw);
#endif
output_low(lcd_enable);
delay_ms(15);
// envia uma seq??ncia de 3 vezes 0x03
// e depois 0x02 para configurar o m?dulo
// para modo de 4 bits
for(conta=1;conta<=3;++conta)
{
lcd_envia_nibble(3);
delay_ms(5);
}
lcd_envia_nibble(2);
// envia string de inicializa??o do display
for(conta=0;conta<=3;++conta) lcd_envia_byte(0,INI_LCD[conta]);
}

void lcd_pos_xy( byte x, byte y)
{
byte endereco;
if(y!=1)
endereco = lcd_seg_lin;
else
endereco = 0;
endereco += x-1;
lcd_envia_byte(0,0x80|endereco);
}

void lcd_escreve( char c)
// envia caractere para o display
{
switch (c)
{
case '\f' : lcd_envia_byte(0,1);
delay_ms(2);
break;
case '\n' :
case '\r' : lcd_pos_xy(1,2);
break;
case '\b' : lcd_envia_byte(0,0x10);
break;
default : lcd_envia_byte(1,c);
break;
}
}

char lcd_le( byte x, byte y)
// le caractere do display
{
char valor;
// seleciona a posi??o do caractere
lcd_pos_xy(x,y);
// ativa rs
output_high(lcd_rs);
// l? o caractere
valor = lcd_le_byte();
// desativa rs
output_low(lcd_rs);
// retorna o valor do caractere
return valor;
}

A biblioteca do RTCDS1307:

////////////////////////////////////////////////////////////////////////////////
/// 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_b0
#define RTC_SCL PIN_b1

#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));
}

Também tenho o ccto de simulação no Proteus

esquemamg.png

Só que não sei como colocar o esquema funcionando aqui no fórum.

Conto com a ajuda de vocês.

Link para o comentário
Compartilhar em outros sites

Opa. Estou trabalhando com o mesmo RTC a algum tempo já só que com o PIC32. Fiz uma biblioteca pra usar ele e uma pra I2C. Adapte o codigo para o 18F que deve funcionar. Boa sorte no projeto.

/*******************************************************************

*******************************************************************/

#define I_ACKDT I2C1CONbits.ACKDT

#define I_ACKEN I2C1CONbits.ACKEN

#define I_RCEN I2C1CONbits.RCEN

#define I_PEN I2C1CONbits.PEN

#define I_RSEN I2C1CONbits.RSEN

#define I_SEN I2C1CONbits.SEN

#define I_ACKSTAT I2C1STATbits.ACKSTAT

#define I_TRSTAT I2C1STATbits.TRSTAT

#define itx I2C1TRN

#define irx I2C1RCV

#define I_LIMIT 10

#define I_WR 0

#define I_RD 1

#define I_ACK 0

#define I_NACK 1

void iStart(void)

{

I_SEN=1;

while( I_SEN );

}

void iRestart(void)

{

I_RSEN=1;

while( I_RSEN );

}

void iStop(void)

{

I_PEN=1;

while( I_PEN );

}

BOOL iWriteByte(unsigned char iWbyte)

{

while( I_TRSTAT );

itx = iWbyte;

while( I_TRSTAT );

if( I_ACKSTAT )

return 0;

else

return 1;

}

unsigned char iWrite(unsigned char iWslave,unsigned char iWaddr, unsigned char *iWbuf, unsigned char iWtam)

{

unsigned char iWerr;

iStart();

if( iWriteByte(iWslave) )

{

if( iWriteByte(iWaddr) )

{

iWerr=0x00;

for( ; iWtam; iWtam-- )

{

if( !iWriteByte( *iWbuf ) )

iWerr = 0x09;

iWbuf++;

}

}

else

iWerr = 0x05; //não setou endereço inicial

}

else

iWerr = 0x03; //nao encontrou slave

iStop();

return iWerr;

}

unsigned char iReadByte(BOOL iRack)

{

I_ACKDT = iRack;

while( I_RCEN );

I_RCEN=1;

while( I_RCEN );

I_ACKEN=1;

while( I_ACKEN );

return irx;

}

unsigned char iRead(unsigned char iRslave, unsigned char iRaddr, unsigned char *iRbuf, unsigned char iRtam)

{

unsigned char iRerr;

iStart();

if( iWriteByte(iRslave) )

{

if( iWriteByte(iRaddr) )

{

iRestart();

if( iWriteByte(iRslave|I_RD) )

{

iRerr=0x00;

for(;iRtam;iRtam--)

{

if( iRtam>1)

*iRbuf = iReadByte(I_ACK);

else

*iRbuf = iReadByte(I_NACK);

iRbuf++;

}

}

else

iRerr=0x11;

}

else

iRerr=0x05;

}

else

iRerr=0x03;

iStop();

return iRerr;

}

/*******************************************************************

*******************************************************************/

/*

***** I2C slave address

*/

#define RTC_ADDRESS 0xD0

/*

***** Register Map

*/

#define RTC_SECONDS 0x00

#define RTC_CH 0x80

#define RTC_MINUTES 0x01

#define RTC_HOURS 0x02

#define RTC_12_24 0x40

#define RTC_AM_PM 0x20

#define RTC_DAY 0x03

#define RTC_DATE 0x04

#define RTC_MONTH 0x05

#define RTC_YEAR 0x06

#define RTC_CONTROL 0x07

#define RTC_OUT 0x80

#define RTC_SQWE 0x10

#define RTC_RS1 0x02

#define RTC_RS0 0x01

/*

***** System Config Options

*/

#define RTC_MODE_12 0x40

#define RTC_MODE_24 0x00

#define RTC_OUT_CLOCK 0x10

#define RTC_OUT_FIXED 0x00

#define RTC_LEVEL_HIGH 0x80

#define RTC_LEVEL_LOW 0x00

#define RTC_FREQ_1 0x00

#define RTC_FREQ_4096 0x01

#define RTC_FREQ_8192 0x02

#define RTC_FREQ_32768 0x03

/*

***** Desfault System Config

*/

#define RTC_MODE RTC_MODE_24

#define RTC_OUT_MODE RTC_OUT_CLOCK

#define RTC_LEVEL RTC_LEVEL_HIGH

#define RTC_FREQ RTC_FREQ_1

/*

***** Data Struct

*/

typedef struct

{

BOOL CH;

BOOL MODE;

BOOL AM_PM;

unsigned char second;

unsigned char minute;

unsigned char hour;

unsigned char day;

unsigned char date;

unsigned char month;

unsigned char year;

}RTC_DATA;

/*

***** Converts a BCD byte into a DEC

*/

unsigned char BCDtoDEC(unsigned char valBCD)

{

unsigned char valDEC;

valDEC = (valBCD&0x0F);

valDEC += (((valBCD&0xF0)>>4)*10);

return valDEC;

}

/*

***** Converts a DEC byte into a BCD

*/

unsigned char DECtoBCD(unsigned char valDEC)

{

//valDEC = valDEC%100;

return( ((valDEC/10)<<4) | (valDEC%10) );

}

/*

***** Config RTC

*/

unsigned char RTCConfig( unsigned char RTCCconfig )

{

return iWrite( RTC_ADDRESS, RTC_CONTROL, &RTCCconfig, 1 );

}

/*

***** Reset RTC

*/

unsigned char RTCReset(void)

{

#if RTC_OUT_MODE==RTC_OUT_CLOCK

unsigned char RTCRbuf[8]={0,0,RTC_MODE,0,0,0,0,RTC_OUT_MODE|RTC_FREQ};

#elif RTC_OUT_MODE==RTC_OUT_FIXED

unsigned char RTCRbuf[8]={0,0,RTC_MODE,0,0,0,0,RTC_OUT_MODE|RTC_LEVEL};

#endif

return iWrite( RTC_ADDRESS, RTC_SECONDS, RTCRbuf, 8 );

}

/*

***** Get RTC Calendar

*/

unsigned char RTCGetCalendar( RTC_DATA * RTCGCdata )

{

unsigned char RTCGCreturn, RTCGCbuf[7];

RTCGCreturn = iRead( RTC_ADDRESS, RTC_SECONDS, RTCGCbuf, 7 );

if( !RTCGCreturn )

{

RTCGCdata->CH = !!(RTCGCbuf[0]&RTC_CH);

if( RTCGCdata->CH )

{

RTCGCdata->MODE = 0;

RTCGCdata->AM_PM = 0;

RTCGCdata->second = 0;

RTCGCdata->minute = 0;

RTCGCdata->hour = 0;

RTCGCdata->day = 0;

RTCGCdata->date = 0;

RTCGCdata->month = 0;

RTCGCdata->year = 0;

}

else

{

RTCGCdata->second = BCDtoDEC( RTCGCbuf[0]&0x7F );

RTCGCdata->minute = BCDtoDEC( RTCGCbuf[1]&0x7F );

RTCGCdata->MODE = !!( RTCGCbuf[2]&RTC_12_24 );

if( RTCGCdata->MODE == 1 )

{//12 hr mode

RTCGCdata->AM_PM = !!( RTCGCbuf[2]&RTC_AM_PM );

RTCGCdata->hour = BCDtoDEC( RTCGCbuf[2]&0x1F );

}

else

{//24 hr mode

RTCGCdata->AM_PM = 0;

RTCGCdata->hour = BCDtoDEC( RTCGCbuf[2]&0x3F );

}

RTCGCdata->day = BCDtoDEC( RTCGCbuf[3]&0x07 );

RTCGCdata->date = BCDtoDEC( RTCGCbuf[4]&0x3F );

RTCGCdata->month = BCDtoDEC( RTCGCbuf[5]&0x1F );

RTCGCdata->year = BCDtoDEC( RTCGCbuf[6] );

}

}

return RTCGCreturn;

}

/*

***** Set RTC Calendar

*/

unsigned char RTCSetCalendar( RTC_DATA * RTCSCdata )

{

unsigned char RTCSCbuf[7];

RTCSCbuf[0] = DECtoBCD( RTCSCdata->second );

RTCSCbuf[1] = DECtoBCD( RTCSCdata->minute );

if( RTCSCdata->MODE == 1 )

{//12 hr mode

RTCSCbuf[2] = DECtoBCD( RTCSCdata->hour );

RTCSCbuf[2] |= RTC_12_24;

RTCSCbuf[2] |= (RTCSCdata->AM_PM<<5);

}

else

{//24 hr mode

RTCSCbuf[2] = DECtoBCD( RTCSCdata->hour );

}

RTCSCbuf[3] = DECtoBCD( RTCSCdata->day );

RTCSCbuf[4] = DECtoBCD( RTCSCdata->date );

RTCSCbuf[5] = DECtoBCD( RTCSCdata->month );

RTCSCbuf[6] = DECtoBCD( RTCSCdata->year );

return iWrite( RTC_ADDRESS, RTC_SECONDS, RTCSCbuf, 7 );

}

Link para o comentário
Compartilhar em outros sites

Beleza edu.

Parabens cara, fazer uma biblioteca num é pra qualquer um!

Não querendo abusar, Será que não tem como você postar um exemplo de uso das suas bibliotecas ai não?

Ou se possível você dar uma olhada no meu código pra ver onde está errado. Como eu disse, só não estou conseguindo ler o RTC (consegui até que consigo, mas só leio zeros), as vezes é uma coisa boba, mas para um leigo no assunto como eu, passa despercebido, entende.

Se der pra você conferir meu código, eu te passo o esquema de simulação no Proteus.

Agradeço a atenção. :)

Link para o comentário
Compartilhar em outros sites

Boa tarde pessoal,

Vou explicar melhor meu problema a vocês: Quando vou ler o RTC, só consigo ler zeros, e não os dados; as funções que efetuam a leitura são as seguintes:

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();

}

Em que as variáveis que uso para retornar os valores são todas inteiras de 8 bits e mostro através da função printf.

No geral, meu código fica assim para ler a data:

ds1307_get_date(date,month,year,day);//função que lê a data.
printf(lcd_escreve,"\f%u/%u/%u\n%s",date,month,year,dia_semana_converte(day));//mostro os valores da data no display

E assim para ler as horas:

ds1307_get_time(hours,minutes,seconds);//função que lê as horas
printf(lcd_escreve,"\f%u:%u:%u",hours,minutes,seconds);mostra as horas no display

conto com a ajuda de vocês!

Link para o comentário
Compartilhar em outros sites

Eaii irmão,

Tava vendo seu esquemático, que valores de resistores de pullup do SDA e SCL você ta colocando na hora de monta no protoboard? parece ser de 10k no esquemático. O datasheet do RTC não sugere um valor para estes resistores de pullup (Rpu), porém lembro que quando montei tive problemas com 10k de pullup, as vezes os valores lidos davam umas loucuras e voltavam ao normal. Testei com 4k7 e 5k6, ambos funcionaram sem problemas. ( deixava o RTC funcionando dias). Adotei como padrão de pullup para tensão de 5V 4k7 e 5k6.

Outra coisa importante é você garantir o tempo mínimo de transmissão dos dados especificado no datasheet (datasheet Maxim DALLAS - AC Electrical Characteristics pg.3) o proteus muitas das vezes ignora estas especificações. Como está usando i²C em Hardware ( #use i2c ) coloque na diretiva a especificação da frequencia. talvez ela esteja muito alta como está usando um cristal em Mhz ( fmax do rtc = 100 khz )

tente colocar:

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FAST = 100000) // frequencia em 100khz

Abraço!!!

Link para o comentário
Compartilhar em outros sites

Valeu rafael.luc pela dica, mas pena que já tinha visitado essa página, foi de uma página desse tipo que tive a ideia de usar o RTC que antes eu nem conhecia.

Ao AlyssonMachado, os resistores eram de 10K mesmo, mudei aqui para 4K7 e depois para 5K6 e não funcionou, mudei também a frequencia como você pediu, mas também não funcionou; Só não montei no protoboard ainda porque tô esperando os componentes chegarem. sei que não dá pra confiar só no Proteus, mas era pra pelo menos dar algum sinal, você não acha, pois para gravar dá certo; ou será que é falha do Proteus, porque se for, aí que não confio nele mesmo!

Ah, outra coisa, você viu a função de ler o rtc? Minha desconfiança maior é nela, será que a conversão que é feita na função está correta? não entendi direito essa conversão. Afinal, ela converte de qual código BCD?

Tomara que os componentes cheguem esse fim-de-semana que aí testo tudo na prática.

Obrigado!!!

Link para o comentário
Compartilhar em outros sites

ou Alysson, Beleza!

Meus componentes chegaram ontem.

Ai montei no protoboard mas não funciona o danado do circuito. tá igual no proteus. So que não dá pra ver se gravou no rtc. Do mesmo jeito que funciona as funções no proteus também funciona no protoboard, só leio zeros!

Tá osso fazer isso funcionar. Será o que que é em...

Link para o comentário
Compartilhar em outros sites

Boa tarde galera!

Estava comparando a biblioteca que tenho aqui com a que o MatheusLPS falou pra mim dar uma olhada e reparei as seguintes diferenças:

Minha biblioteca:


#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3

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

A outra biblioteca:


#define RTC_SDA PIN_b2
#define RTC_SCL PIN_b1

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, fast = 100000)
#use i2c(sda=PIN_b2, scl=PIN_b1, stream=I2C_HW)

e também essas funções na minha:


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();

}

pra outra:


void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, 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
day = bcd2bin(i2c_read() & 0x3f); // REG 4
mth = bcd2bin(i2c_read() & 0x1f); // REG 5
year = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

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

}

feito do jeito da segunda, consegui ler os valores do rtc diferentes de zero (:aplausos:viva!!!).

Só que não estou conseguindo ler a data corretamente:

quando gravo 00/00/00 - 0 (dia/mes/ano - dia da semana) e depois leio, aparece:00/10/-9. outro ex.:

quando gravo 05/05/05 - 05 (dia/mes/ano - dia da semana) e depois leio, é mostrado no display: 05/10/-9.

Parece que apenas o dia é mostrado corretamente, mas o ano e o mês aparece diferente.

Também estava pensando em colocar a saída sqw/out oscilando em um Hertz, que aí por meio de interrupção externa atualizo o display.

Vi na seguinte função que esse pino é configurado para não oscilar:


void ds1307_init(void)
{
BYTE seconds = 0;

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

delay_us(3);

i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x00); // REG 0
i2c_write(bin2bcd(seconds)); // Start oscillator with current "seconds value
i2c_start();
i2c_write(0xD0); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x10); // Disable squarewave output pin [COLOR="Red"]aqui desliga a saída [/COLOR]
i2c_stop();

}

O que devo colocar pra acionar a saída sqw/out em 1Hz?

Não entendi nem de onde que veio esse 0x10...

Estava fazendo os testes com o PIC16F877A no Proteus e no protoboard, só que minha programação ficou meio grande e vou ter que passar pro PIC18F452.

Vou trocar o microcontrolador do esquema no proteus pra testar lá também.

Valeu Matheus pela força, Agora tá quase!!!

Abs.

Link para o comentário
Compartilhar em outros sites

Pessoal, bom dia!

Agora acho que entendi o 0x10 que destaquei acima: ele que é o byte gravado no registrador de controle, e convertido para binário dá 0b00010000. Setando apenas o bit4(SQWE).

O engraçado é que apenas o bit 4 setado configura a saida ativada e com o clock em 1Hz (pelo menos foi o que entendi).

Mas mesmo desse jeito a saída não está ativada. O que será que é então?

Estou testando no Proteus e no protoboard e tá do mesmo jeito.

Vou dar uma organizada aqui no meu novo código pra te mostrarem.

Da uma força aí galera, porque sou iniciante em programação e tô aprendendo sozinho.

Até +!

Galera, desisti do meu código depois de ficar o final de semana inteiro procurando o entender o porque de não estar conseguindo ler a data corretamente.

Decidi então alterar o código que o Matheus me mostrou para minha aplicação e nada, mas deu pra perceber que o problema está na leitura do da data(antes desconfiava de ser algum bug no meu código).

Além de ficar menor, o programa já aciona a saída SQWE, que através dela atualizo o tempo no display.

Agora tô precisando de uma força é para acertar a leitura da data.

Segue meu novo código fonte:


#include"18F452.h"

#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //Clock >4Mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=12M)

#include"ds1307.c"
#include"lcd.c"

#define botao_incremento PIN_A0
#define botao_decremento PIN_A1
#define troca_modo PIN_A2

BYTE sec;
BYTE mim;
BYTE hrs;
BYTE day;
BYTE month;
BYTE yr;
BYTE dow;

int8 modo;
//int16 adc;
//float temperatura;

char dia_da_semana[7][8]=
{
"DOMINGO",
"SEGUNDA",
"TERCA",
"QUARTA",
"QUINTA",
"SEXTA",
"sábado",
};

#int_ext
void trata_ext()
{
ds1307_get_date(day,month,yr,dow);
ds1307_get_time(hrs,mim,sec);
delay_ms(50);
printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[dow-1],hrs,mim,sec,day,month,yr);
delay_ms(50);
}


void main()
{

enable_interrupts (global | int_ext);
ds1307_init();
lcd_ini();
ds1307_get_date(day,month,yr,dow);
ds1307_get_time(hrs,mim,sec);
delay_ms(50);
printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[dow-1],hrs,mim,sec,day,month,yr);
delay_ms(5000);
modo = 0;

while(1)
{
switch (modo)
{
case 1:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
yr++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
yr--;
}

if (yr > 99 )
{
yr = 1;
}

if (yr == 0 )
{
yr = 99;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fAjustar Ano:\n%u",yr);
delay_ms (100);
break;

}

case 2:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
month++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
month--;
}

if (month > 12 )
{
month = 1;
}

if (month == 0 )
{
month = 12;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fAjustar Mes:\n%u",month);
delay_ms (100);
break;

}

case 3:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
day++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
day--;
}

if (day > 31 )
{
day = 1;
}

if (day == 0 )
{
day = 31;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fDia do Mes:\n%u",day);
delay_ms (100);
break;

}

case 4:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
dow++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
dow--;
}

if (dow > 7 )
{
dow = 1;
}

if (dow == 0)
{
dow = 7;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fDia da Semana:\n%s",dia_da_semana[dow-1]);
delay_ms (100);
break;
}

case 5:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
hrs++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
hrs--;
}

if (hrs > 23 )
{
hrs = 0;
}

if (hrs == 255 )
{
hrs = 23;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fAjustar Hora:\n%u",hrs);
delay_ms (100);
break;

}

case 6:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
mim++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
mim--;
}

if (mim > 59 )
{
mim = 0;
}

if (mim == 255 )
{
mim = 59;
}
if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fAjustar Minutos:\n%u",mim);
delay_ms (100);
break;
}

case 7:
{
if (input(BOTAO_INCREMENTO))
{
delay_ms (75);
sec++;
}

if (input(BOTAO_DECREMENTO))
{
delay_ms (75);
sec--;
}

if (sec > 59 )
{
sec = 0;
}

if (sec == 255 )
{
sec = 59;
}
if(input(TROCA_MODO))
{
modo++;
ds1307_set_date_time(day,month,yr,dow,hrs,mim,sec);
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
printf(lcd_escreve,"\fAjustar Segundos:\n%u",sec);
delay_ms (100);
break;
}

default:
{

if(input(TROCA_MODO))
{
modo++;
while(input(TROCA_MODO));
if (modo > 7 )
{
modo = 0;
}
}
}
}
}
}

E a nova biblioteca do RTC:


////////////////////////////////////////////////////////////////////////////////
/// 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(day,mth,year,dow,hour,mim,sec) Set the date/time ///
/// ///
/// ds1307_get_date(day,mth,year,dow) Get the date ///
/// ///
/// ds1307_get_time(hr,mim,sec) Get the time ///
/// ///
////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_B2
#define RTC_SCL PIN_B1

#use i2c(master, sda=RTC_SDA, scl=RTC_SCL)
#use i2c(sda=PIN_B2, scl=PIN_B1, stream=I2C_HW)

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

void ds1307_init(void)
{
BYTE seconds = 0;

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

delay_us(3);

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

}

void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE mim, BYTE sec)
{
sec &= 0x7F;
hr &= 0x3F;

i2c_start();
i2c_write(0xD0); // I2C write address
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_write(bin2bcd(sec)); // REG 0
i2c_write(bin2bcd(mim)); // REG 1
i2c_write(bin2bcd(hr)); // REG 2
i2c_write(bin2bcd(dow)); // REG 3
i2c_write(bin2bcd(day)); // REG 4
i2c_write(bin2bcd(mth)); // REG 5
i2c_write(bin2bcd(year)); // REG 6
i2c_write(0x10); // REG 7 - Disable squarewave output pin
i2c_stop();
}

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, 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
day = bcd2bin(i2c_read() & 0x3f); // REG 4
mth = bcd2bin(i2c_read() & 0x1f); // REG 5
year = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}

void ds1307_get_time(BYTE &hr, BYTE &mim, BYTE &sec)
{
i2c_start();
i2c_write(0xD0);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(0xD1);
sec = bcd2bin(i2c_read() & 0x7f);
mim = bcd2bin(i2c_read() & 0x7f);
hr = bcd2bin(i2c_read() & 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));
}

Alguém tem alguma ideia?

Link para o comentário
Compartilhar em outros sites

Obrigado Edu. pela observação; só que já estou usando os resistores de pull-up.

O meu problema é de software mesmo, pois consigo gravar as horas e a data também, mas na hora de ler, só as horas que leio certo, a data mostra uns valores que não variam com o passar do tempo e diferente do que gravei. estou testando no protoboard e no proteus, e tá a mesma coisa. E no proteus mostra que a data no RTC fica diferente do que a que estou lendo.

você num sabe o que é não?

Meu código ta aí em cima, se der, dá uma olhada.

Até +!

Link para o comentário
Compartilhar em outros sites

Vamos com calma, nao tenho tempo pra ler todo o código mas com base nos sintomas vamos tentar algum medicamento ae ;]

Você ja deu uma olhada no bit CH (clock halt), ele indica quando há alguma falha na contagem. Se nao me engano ele fica embutido com os segundos. Há outros bits que também estão anexos nos registradores e devem ser ignorados na hora de se fazer a leitura. Tens como postar o hardware atualizado? Vou dar uma lida no ultimo codigo que postastes e ver se encontro algo.

EDIT 1:

Cara não ta errado essa declaração dos ponteiros na função de leitura? Está sendo usado o & para criar o ponteiro quando o correto seria um *. Assim como no código para fazer menção ao conteúdo dos mesmo deve-se usar o * também. Não sou muito bom com o CCS, mas em qualquer compilador normal de C eu faria assim:

void get_time( char *hr, char *min, char *seg)

{

*hr = ...;

*min = ...;

*seg = ...;

}

E no main chamaria desse modo:

get_time( &mhr, &mmin, &mseg );

Deste modo eu passo para a função o endereço do registrador e ela utiliza como um ponteiro. O CCS é cheio das maluquices e teria que saber mais a fundo como ele se comporta com relação aquele trecho mas no HI-TECH (normalmente uso) teria que utilizar os ponteiros da forma acima.

EDIT 2:

A função de conversão de BCD para decimal também me parece meio estranha. Aqueles shifts e tudo mais não me parecem certos. Teria que ver um modo mais claro de fazer a conversão. No codigo que postei acima tem ambas as logicas de conversão e é garantido.

Link para o comentário
Compartilhar em outros sites

Pois é MatheusLPS, na resposta n°11 coloquei os códigos que estou usando, que foi o que você me passou com as modificações nescessárias, só que não entendo porque está tão difícil colocar essa programação toda pra funcionar; quando consigo ler a data, a hora sai errada e vice-versa. Ai depois de muito tempo consegui ler as duas corretamente desse jeito:

Só que aí não tá dando pra gravar o danado do RTC!

#int_ext
void trata_ext()
{
teste=1;
if(teste)
{
ds1307_get_time(horas,minutos,segundos);
//delay_ms(50);
ds1307_get_date(dia,mes,ano,semana);
delay_ms(50);
//printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[semana-1],horas,minutos,segundos,dia,mes,ano);
}
if(teste)
{
ds1307_get_date(day,month,yr,dow);
ds1307_get_time(hrs,mim,sec);
delay_ms(50);
printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[dow-1],hrs,mim,sec,day,month,yr);
}
//printf(lcd_escreve,"\f%s %02d:\%02d:\%02d",dia_da_semana[dow],hrs,mim,sec);
//delay_ms(50);
//printf(lcd_escreve,"\n%02d/\%02d/\%02d ",day,month,yr);
}

Essa parte é uma interrupção externa no pino B0 de um PIC18F452, acionada pela própria saída SQWE do RTC.

Note que pra conseguir ler a data e a hora corretamente, tive que ler duas vezes o RTC, gravando os valores em variáveis diferentes, pois só assim funcionou.

E aquela variável "teste" foi só um teste que fiz antes de conseguir fazer funcionar, portanto, ignore-a.

Se você quiser, te mando a programação com todas as bibliotecas que estou usando e o arquivo de simulação no Proteus.

Link para o comentário
Compartilhar em outros sites

Testei sim no protoboard, tá do mesmo jeito.

O edu. falou que umas partes do código que estou usando tá meio estranho, só que antes eu tava usando mais ou menos do jeito que ele falou e não lia nada, só zeros.

você tem alguma ideia do q pode ser???

Agora como disse, consigo ler tudo, mas num grava nada.

Isso tudo só funciona em partes, o problema é que tá difícil de entender o que tá acontecendo aqui.

Link para o comentário
Compartilhar em outros sites

Veja bem, você está desconsiderando um bit muito importante no RTC. O bit CH no registrador dos segundos informa se o valor dos demais registradores está correto ou errado. No seu programa, na parte de inicialização ele simplesmente lê os segundos e depois zera o bit e volta a escrever, desse modo, ele ignora se os valores são validos ou não. No meu programa você precisa verificar se esse bit está setado e então zerar ele, caso contrário a contagem não inicia e ele permanece no 0. Enquanto esse bit estiver em 1 não haverá contagem. Também tens de cuidar com o pino Vbat, ele não serve para carregar/descarregar a bateria, ele somente serve de entrada de alimentação. Se desejas que a bateria seja carregada para depois alimentar o RTC deves colocar um diodo e um resistor de uma fonte de 3V3 para que sempre que o circuito estiver alimentado carregar a bateria. Leia o datasheet atenciosamente e veja melhor o funcionamento do bit CH e depois reveja seu código. Vou procurar aqui o trecho de inicialização que utilizei na aplicação que desenvolvi com aquelas bibliotecas.

EDIT:

	//init rtc
RTCGetCalendar( &calendario );
if( calendario.CH )
{
RTCReset();
}

Link para o comentário
Compartilhar em outros sites

Boa noite edu.!

estou tentando usar suas bibliotecas mais dá um monte de erros na hora de compilar. veja a imagem:

outputd.jpg

Tá faltando alguma outra biblioteca ou são só essas mesmas?

Tem alguns erros do tipo:

"Expecting a("

que significa que está faltando fechar os parenteses, Posso fechá-los? Qual compilador você usa? aqui eu uso o CCS C (PCW).

Vou ir tentando aqui, mas se você tiver um exemplo usando-as tem como postar?

Vai dar uma clareada boa!

Como eu disse, sou um leigo quando o assunto é programação e estou aprendendo agora.

Outra coisa, eu uso os pinos RD1 para SCL e RD0 para SDA, como configuro esses pinos na sua biblioteca?

Até mais!

Ah, já ia me esquecendo de postar minha programação.

Na resposta #16 você me pediu, então la vai:

#include"18F452.h"

#FUSES NOWDT //No Watch Dog Timer

#FUSES HS //Clock >4Mhz

#FUSES PUT //Power Up Timer

#FUSES NOPROTECT //Code not protected from reading

#FUSES NOBROWNOUT //No brownout reset

#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O

#FUSES NOCPD //No EE protection

#use delay(clock=12M)

#include"ds1307.c"

#include"lcd.c"

#define botao_incremento PIN_A3

#define botao_decremento PIN_A2

#define troca_modo PIN_A1

#define led_lcd pin_d6

#define rele pin_c3

#define buzzer pin_b5

BYTE sec;

BYTE mim;

BYTE hrs;

BYTE day;

BYTE month;

BYTE yr;

BYTE dow;

int segundos=0;

int minutos=0;

int horas=0;

int dia=0;

int mes=0;

int ano=0;

int semana=0;

short teste=0;

int8 modo;

//int16 adc;

//float temperatura;

char dia_da_semana[7][8]=

{

"DOMINGO",

"SEGUNDA",

"TERCA",

"QUARTA",

"QUINTA",

"SEXTA",

"sábado",

};

#int_ext

void trata_ext()

{

teste=1;

if(teste)

{

ds1307_get_time(horas,minutos,segundos);

//delay_ms(50);

ds1307_get_date(dia,mes,ano,semana);

delay_ms(50);

//printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[semana-1],horas,minutos,segundos,dia,mes,ano);

}

if(teste)

{

ds1307_get_date(day,month,yr,dow);

ds1307_get_time(hrs,mim,sec);

delay_ms(50);

printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[dow-1],hrs,mim,sec,day,month,yr);

}

//printf(lcd_escreve,"\f%s %02d:\%02d:\%02d",dia_da_semana[dow],hrs,mim,sec);

//delay_ms(50);

//printf(lcd_escreve,"\n%02d/\%02d/\%02d ",day,month,yr);

}

void main()

{

ds1307_init();

lcd_ini();

ds1307_get_date(day,month,yr,dow);

ds1307_get_time(hrs,mim,sec);

output_bit(buzzer,1);

delay_ms(500);

output_bit(led_lcd,1);

output_bit(buzzer,0);

printf(lcd_escreve,"\f%s %02d:\%02d:\%02d\n%02d/\%02d/\%02d ",dia_da_semana[dow-1],hrs,mim,sec,dia,month,yr);

delay_ms(5000);

enable_interrupts(global | int_ext);

modo = 0;

while(1)

{

switch (modo)

{

case 1:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

yr++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

yr--;

}

if (yr > 99 )

{

yr = 1;

}

if (yr == 0 )

{

yr = 99;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fAjustar Ano:\n%02d",yr);

delay_ms (100);

break;

}

case 2:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

month++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

month--;

}

if (month > 12 )

{

month = 1;

}

if (month == 0 )

{

month = 12;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fAjustar Mes:\n%02d",month);

delay_ms (100);

break;

}

case 3:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

day++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

day--;

}

if (day > 31 )

{

day = 1;

}

if (day == 0 )

{

day = 31;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fDia do Mes:\n%02d",day);

delay_ms (100);

break;

}

case 4:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

dow++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

dow--;

}

if (dow > 7 )

{

dow = 1;

}

if (dow == 0)

{

dow = 7;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fDia da Semana:\n%s",dia_da_semana[dow-1]);

delay_ms (100);

break;

}

case 5:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

hrs++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

hrs--;

}

if (hrs > 23 )

{

hrs = 0;

}

if (hrs == 255 )

{

hrs = 23;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fAjustar Hora:\n%02d",hrs);

delay_ms (100);

break;

}

case 6:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

mim++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

mim--;

}

if (mim > 59 )

{

mim = 0;

}

if (mim == 255 )

{

mim = 59;

}

if(input(TROCA_MODO))

{

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

printf(lcd_escreve,"\fAjustar Minutos:\n%02d",mim);

delay_ms (100);

break;

}

case 7:

{

if (input(BOTAO_INCREMENTO))

{

delay_ms (75);

sec++;

}

if (input(BOTAO_DECREMENTO))

{

delay_ms (75);

sec--;

}

if (sec > 59 )

{

sec = 0;

}

if (sec == 255 )

{

sec = 59;

}

if(input(TROCA_MODO))

{

modo++;

ds1307_set_date_time(day,month,yr,dow,hrs,mim,sec);

while(input(TROCA_MODO));

delay_ms (100);

if (modo > 7 )

{

modo = 0;

}

enable_interrupts(global | int_ext);

}

printf(lcd_escreve,"\fAjustar Segundos:\n%02d",sec);

delay_ms (100);

break;

}

default:

{

if(input(TROCA_MODO))

{

disable_interrupts(global | int_ext);

modo++;

while(input(TROCA_MODO));

if (modo > 7 )

{

modo = 0;

}

}

}

}

}

}

////////////////////////////////////////////////////////////////////////////////

/// 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(day,mth,year,dow,hour,mim,sec) Set the date/time ///

/// ///

/// ds1307_get_date(day,mth,year,dow) Get the date ///

/// ///

/// ds1307_get_time(hr,mim,sec) Get the time ///

/// ///

////////////////////////////////////////////////////////////////////////////////

#define RTC_SDA PIN_d0

#define RTC_SCL PIN_d1

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

#use i2c(sda=PIN_d0, scl=PIN_d1, stream=I2C_HW)

BYTE bin2bcd(BYTE binary_value);

BYTE bcd2bin(BYTE bcd_value);

void ds1307_init(void)

{

BYTE seconds = 0;

i2c_start();

i2c_write(0xD0); // WR to RTC

i2c_write(0x00); // REG 0

i2c_start();

i2c_write(0xD1); // RD from RTC

seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in DS1307

i2c_stop();

seconds &= 0x7F;

delay_us(3);

i2c_start();

i2c_write(0xD0); // WR to RTC

i2c_write(0x00); // REG 0

i2c_write(bin2bcd(seconds)); // Start oscillator with current "seconds value

i2c_start();

i2c_write(0xD0); // WR to RTC

i2c_write(0x07); // Control Register

i2c_write(0x10); // Disable squarewave output pin

i2c_stop();

}

void ds1307_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE mim, BYTE sec)

{

sec &= 0x7F;

hr &= 0x3F;

i2c_start();

i2c_write(0xD0); // I2C write address

i2c_write(0x00); // Start at REG 0 - Seconds

i2c_write(bin2bcd(sec)); // REG 0

i2c_write(bin2bcd(mim)); // REG 1

i2c_write(bin2bcd(hr)); // REG 2

i2c_write(bin2bcd(dow)); // REG 3

i2c_write(bin2bcd(day)); // REG 4

i2c_write(bin2bcd(mth)); // REG 5

i2c_write(bin2bcd(year)); // REG 6

i2c_write(0x10); // REG 7 - Disable squarewave output pin

i2c_stop();

}

void ds1307_get_date(BYTE &day, BYTE &mth, BYTE &year, 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

day = bcd2bin(i2c_read() & 0x3f); // REG 4

mth = bcd2bin(i2c_read() & 0x1f); // REG 5

year = bcd2bin(i2c_read(0)); // REG 6

i2c_stop();

}

void ds1307_get_time(BYTE &hr, BYTE &mim, BYTE &sec)

{

i2c_start();

i2c_write(0xD0);

i2c_write(0x00); // Start at REG 0 - Seconds

i2c_start();

i2c_write(0xD1);

sec = bcd2bin(i2c_read() & 0x7f);

mim = bcd2bin(i2c_read() & 0x7f);

hr = bcd2bin(i2c_read() & 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));

}

Do jeito que tá está lendo direitinho o RTC, mas não esta gravando os valores.

Link para o comentário
Compartilhar em outros sites

Como você sabe se gravou certo se não consegue ler? E vice vera? As minhas bibliotecas não vão funcionar, foram feitas para PIC32MX no compilador C32, completamente diferente do que estas usando, mas a lógica é correta. Acho melhor trabalhar em cima do que tens. Em primeiro lugar, lestes o datasheet do componente? Ele tem um seção dedicada a I2C que informa qual deve ser o procedimento para leitura ou escrita de um byte no RTC. Faça no main mesmo um codigo direto na I2C lendo e jogando no LCD, se funcionar passe para uma função e depois para uma biblioteca. Sair pegando tudo pronto e juntando não é garantia que funciona. Vou exemplificar a lógica básica que utilizei no meu programa:

Inicializa I2C

Lê registrador dos segundo

Se bit CH=1

-Reseta os registradores do RTC

-Ajusta hora padrão

Se bit CH=0

-Segue o programa normal

No programa principal poder ler o valor do RTC periodicamente (nem que seja um timer, e escrever no LCD). Quando recem ligares o circuito o RTC será carregado com a data padrão, dali em diante ele deve manter os valores corretos. Faça o simples e foque em cima do problema, tire os penduricalhos do programa e deixe só o RTC até que funcione, depois adicione o resto.

Link para o comentário
Compartilhar em outros sites

E ai edu.!

Sei que estava gravando certo porque também estou simulando no Proteus.

Estava fazendo como você me sugeriu quando lembrei de uma coisa na configuração do PIC

Cara, estava tentando entender porque num funciona tudo junto, hora funciona uma coisa, hora outra. Aí lembrei de colocar uma linha em meu programa que parece que resolveu:

setup_adc_ports(no_analog);

Depois que fiz isso, está lendo e gravando corretamente. Ainda num testei direito porque já tava na hora de largar serviço, mas amanhã vou testar direitinho e depois coloco aqui se deu certo ou não.

você sabe o porque disso? Pois quando não definimos nada, o compilador (PCW) por padrão já deveria definir todos os pinos como digitais num é.

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

Pessoal, tinha dado uma sumida mais agora eu tô aí.:D

Depois da grande ajuda de todos vocês consegui resolver meu problema.

Aprendi bastante coisa sobre esse RTC e comunicação I2C.

Meu problema era na leitura dos valores mesmo. Exatamente como o edu. me falou:

get_time( &mhr, &mmin, &mseg );

Demorou pra cair a ficha aqui, mas acontece que entendo muito pouco de programação.

Agora tá tudo Ok aqui! Valeu mesmo galera!

Até +!!!

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...