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.