|
|
View previous topic :: View next topic |
Author |
Message |
pyu
Joined: 04 Feb 2009 Posts: 51
|
DS1307 problem. |
Posted: Mon Oct 05, 2009 1:41 pm |
|
|
Hi all.
I have a problem with my digital clock (pic16f887 and DS1307).
The schematic, DS1307:
pin 1: Crystal 32.768Khz
pin 2: Crystal 32.768Khz
pin 3: V + bat
pin 4: GND
pin 5: SDA (pic16f887 pin 23) and a pull-up resistor 4.7 K resistor to +5V
pin 6: SCL (pic16f887 pin 18) and a pull-up resistor 4.7 K to +5V
pin 7: NC
pin 8: +5V
Vbat is 2.8 - 3.0 V.
I use the following code (from this forum):
ds1307.c:
Code: |
//=========================================
// ds1307.c -- Functions for the Dallas Semiconductor DS1307
// real time clock and NVRAM chip.
//
// The DS1307 uses BCD as its internal format, but we use it
// in binary format, outside of this module. So we have code
// to convert to/from BCD to binary in the functions below.
//----------------------------------------------------------------------
// Set the date and time.
/*
The registers inside the ds1307 are in this format. The values are in BCD.
DS1307_SECONDS_REG 0
DS1307_MINUTES_REG 1
DS1307_HOURS_REG 2
DS1307_DAY_OF_WEEK_REG 3 // We don't use this register. Set it to 0.
DS1307_DATE_REG 4
DS1307_MONTH_REG 5
DS1307_YEAR_REG 6
*/
#define DS1307_I2C_WRITE_ADDR 0xd0
#define DS1307_I2C_READ_ADDR 0xd1
// DS1307 register offsets
#define DS1307_SECONDS_REG 0
#define DS1307_MINUTES_REG 1
#define DS1307_HOURS_REG 2
#define DS1307_DAY_OF_WEEK_REG 3
#define DS1307_DATE_REG 4
#define DS1307_MONTH_REG 5
#define DS1307_YEAR_REG 6
#define DS1307_CONTROL_REG 7
#define DS1307_DATE_TIME_BYTE_COUNT 7 // Includes bytes 0-6
#define DS1307_NVRAM_START_ADDR 8
// We disable the SQWV output, because it uses
// a lot of battery current when it's enabled.
// Disable it by setting Out = Open Collector.
#define DS1307_CONTROL_REG_INIT_VALUE 0x80
char gca_ds1307_regs[DS1307_DATE_TIME_BYTE_COUNT];
void ds1307_set_date_time(void);
void ds1307_read_date_time(void);
char ds1307_read_byte(char addr);
char bcd2bin(char bcd_value);
char bin2bcd(char bin_value);
void ds1307_write_byte(char addr, char value);
void ds1307_set_date_time(void)
{
char i;
// Convert the binary ds1307 data, which is passed in a global array,
// into bcd data. Store it in the same array.
for(i = 0; i < 7; i++)
{
gca_ds1307_regs[i] = bin2bcd(gca_ds1307_regs[i]);
}
// There are two control bits embedded in the following data.
// The Clock Halt bit is in bit 7 of the DS1307 Seconds register.
// We need to make sure that it's = 0, to make the clock run.
// The other bit is the 24/12 hour clock format bit, in bit 6 of
// the DS1307 Hours register. We need 24 hour mode, so set it = 0.
gca_ds1307_regs[DS1307_SECONDS_REG] &= 0x7f;
gca_ds1307_regs[DS1307_HOURS_REG] &= 0x3f;
// Now write the 7 bytes of BCD data to the ds1307,
// using inline code for speed.
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1307_I2C_WRITE_ADDR);
// Start reading at the Seconds register.
i2c_write(DS1307_SECONDS_REG);
// Write 7 bytes, to registers 0 to 6.
for(i = 0; i < 7; i++)
{
i2c_write(gca_ds1307_regs[i]);
}
// After setting the time in registers 0-6, also set the
// Control register. (index = 7)
// This just turns off the squarewave output pin.
// Doing it here, every time we set the clock registers,
// seems less risky than setting it near the
// start of the program, every time the unit powers-up.
i2c_write(DS1307_CONTROL_REG_INIT_VALUE);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------------------------------
// Read the date and time.
// The registers inside the ds1307 are in this order.
// The values inside the registers are in BCD.
// DS1307_SECONDS_REG_ADDR 0
// DS1307_MINUTES_REG_ADDR 1
// DS1307_HOURS_REG_ADDR 2
// DS1307_DAY_OF_WEEK_REG_ADDR 3
// DS1307_DATE_REG_ADDR 4
// DS1307_MONTH_REG_ADDR 5
// DS1307_YEAR_REG_ADDR 6
// We return the data in a global array. The data in is binary.
// seconds // 0-59 seconds
// minutes // 0-59 minutes
// hours // 0-23 hours
// day_of_week // 1-7
// date // 1-31 date
// month // 1-12 month
// year // 00-99 year (based on year 2000)
void ds1307_read_date_time(void)
{
char i;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1307_I2C_WRITE_ADDR);
// Start reading at the Seconds register.
i2c_write(DS1307_SECONDS_REG);
i2c_start();
i2c_write(DS1307_I2C_READ_ADDR);
// Read the 7 bytes from the ds1307. Mask off the unused bits.
gca_ds1307_regs[DS1307_SECONDS_REG] = i2c_read() & 0x7f;
gca_ds1307_regs[DS1307_MINUTES_REG] = i2c_read() & 0x7f;
gca_ds1307_regs[DS1307_HOURS_REG] = i2c_read() & 0x3f;
gca_ds1307_regs[DS1307_DAY_OF_WEEK_REG] = i2c_read() & 0x07;
gca_ds1307_regs[DS1307_DATE_REG] = i2c_read() & 0x3f;
gca_ds1307_regs[DS1307_MONTH_REG] = i2c_read() & 0x1f;
gca_ds1307_regs[DS1307_YEAR_REG] = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
// Now convert the data from BCD to binary.
// Do it after reading the bytes, so that
// the i2c reads can be done quickly.
for(i = 0; i < 7; i++)
{
gca_ds1307_regs[i] = bcd2bin(gca_ds1307_regs[i]);
}
}
//------------------------------------------------------------------------
// Read one byte at the specified address.
// This function is used to access the control byte
// or the NVRAM bytes.
char ds1307_read_byte(char addr)
{
char retval;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1307_I2C_WRITE_ADDR);
i2c_write(addr);
i2c_start();
i2c_write(DS1307_I2C_READ_ADDR);
retval = i2c_read(0); // Don't ACK the last byte read
i2c_stop();
enable_interrupts(GLOBAL);
return(retval);
}
//----------------------------------------------------------------------
// Write one byte to the DS1307.
// This function is used to access the control byte
// or the NVRAM bytes.
void ds1307_write_byte(char addr, char value)
{
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1307_I2C_WRITE_ADDR);
i2c_write(addr);
i2c_write(value);
i2c_stop();
enable_interrupts(GLOBAL);
}
//-------------------------------------------------------------
// This function converts an 8 bit binary value
// to an 8 bit BCD value.
// The input range must be from 0 to 99.
char bin2bcd(char binary_value)
{
char temp;
char 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);
}
//--------------------------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.
char bcd2bin(char bcd_value)
{
char 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));
}
|
And main.c:
Code: |
#include <16F887.H>
#include <math.h>
#fuses HS,NOWDT,NOLVP,PUT,NOPROTECT,NOBROWNOUT,NOWRT
#use delay(clock = 20000000)
#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3
#use I2C(MULTI_MASTER,sda=RTC_SDA, scl=RTC_SCL)
#include "DS1307.c"
#include "Flex_LCD420.c"
void ds1307_set_date_time(void);
void ds1307_read_date_time(void);
void ds1307_write_byte(char addr, char value);
char ds1307_read_byte(char addr);
char bin2bcd(char binary_value);
char bcd2bin(char bcd_value);
void main(void)
{
char sec;
char min;
char hrs;
char day;
char date;
char month;
char yr;
lcd_init();
printf(lcd_putc, "\f");
printf(lcd_putc, "\fTest program");
delay_ms(500);
// Put some date and time values into the global date & time array.
gca_ds1307_regs[DS1307_SECONDS_REG] = 10; // 10 seconds
gca_ds1307_regs[DS1307_MINUTES_REG] = 10; // 10 minutes
gca_ds1307_regs[DS1307_HOURS_REG] = 8; // 8 AM
gca_ds1307_regs[DS1307_DAY_OF_WEEK_REG]= 0; // Skip this.
gca_ds1307_regs[DS1307_DATE_REG] = 4; // 4
gca_ds1307_regs[DS1307_MONTH_REG] = 9; // Sept
gca_ds1307_regs[DS1307_YEAR_REG] = 9; // 2009
// Write these values to the DS1307, for testing.
ds1307_set_date_time();
printf(lcd_putc, "\fAfter set time");
delay_ms(1000);
while(1)
{
delay_ms(1000);
// Get these into variables with shorter names, so I can
// put them into printf more easily.
sec = gca_ds1307_regs[DS1307_SECONDS_REG];
min = gca_ds1307_regs[DS1307_MINUTES_REG];
hrs = gca_ds1307_regs[DS1307_HOURS_REG];
day = gca_ds1307_regs[DS1307_DAY_OF_WEEK_REG];
date = gca_ds1307_regs[DS1307_DATE_REG];
month = gca_ds1307_regs[DS1307_MONTH_REG];
yr = gca_ds1307_regs[DS1307_YEAR_REG];
printf(lcd_putc, "\f\%02d/\%02d/\%02d\r\n",day,month,yr);
printf(lcd_putc, "\%02d:\%02d:\%02d", hrs,min,sec);
}
}
|
And the result:
00/09/09
08:16:16
and is not ticking.
Can somebody please help me, is something wrong in my code?
Thanks. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Oct 05, 2009 1:51 pm |
|
|
Look at the code in the example here:
http://www.ccsinfo.com/forum/viewtopic.php?t=19926
You're missing the call to ds1307_read_date_time(). Add the line in
shown in bold below, to your program:
Quote: |
while(1)
{
delay_ms(1000);
ds1307_read_date_time();
// Get these into variables with shorter names, so I can
// put them into printf more easily.
sec = gca_ds1307_regs[DS1307_SECONDS_REG];
min = gca_ds1307_regs[DS1307_MINUTES_REG];
hrs = gca_ds1307_regs[DS1307_HOURS_REG];
day = gca_ds1307_regs[DS1307_DAY_OF_WEEK_REG];
date = gca_ds1307_regs[DS1307_DATE_REG];
month = gca_ds1307_regs[DS1307_MONTH_REG];
yr = gca_ds1307_regs[DS1307_YEAR_REG];
printf(lcd_putc, "\f\%02d/\%02d/\%02d\r\n",day,month,yr);
printf(lcd_putc, "\%02d:\%02d:\%02d", hrs,min,sec);
}
} |
|
|
|
pyu
Joined: 04 Feb 2009 Posts: 51
|
|
Posted: Mon Oct 05, 2009 2:25 pm |
|
|
Yes.
Thanks allot for your help, PCM Programmer
I found another small issue (reading day of week instead date)
Code: | printf(lcd_putc, "\f\%02d/\%02d/\%02d\n",date,month,yr);
printf(lcd_putc, "\%02d:\%02d:\%02d\n", hrs,min,sec);
printf(lcd_putc, "Day of week: \%02d", day); |
With this changes, my clock work fine |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|