![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
Can't get DS1306 alarm to operate |
Posted: Wed Mar 08, 2006 5:55 am |
|
|
Hello.
I have produced the following code to test using the DS1306 RTC as an alarm to trigger an interrupt. The device is using the SPI port and communication appears to work well enough (i.e. I can read and write all of the memory addresses) but I can't seem to get the interrupt pin INT1 (pin 6) on the DS1306 to activate. I was wondering whether there was anything blatently obvious that I have missed that would make it work.
Thanks in advance,
Simon.
main.c
Code: | // PIC Code for the Autonomous Water Sampling System timer circuit.
// By Simon Ayers
// Software version 0.01 (08/02/2006)
//
#include <18F252.h>
#include <math.h>
#include <ds1306.c>
#use delay(clock=8192000)
#fuses HS, NOWDT, NOPROTECT, NOBROWNOUT
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#include <useful.h>
int1 rb_pin = 0;
#INT_EXT1
void ext1_isr()
{
rb_pin = 1;
}
void main()
{
int8 hour, minute, second, day, date, month, year, control;
char str[10], c;
enable_interrupts(INT_EXT1);
ext_int_edge(1, L_TO_H);
disable_interrupts(global);
rb_pin = 0;
output_float(PIN_B1);
//output_a(0);
//output_b(0);
//output_c(0);
ds1306_init();
ds1306_writebyte(0x8F, 0x00);
delay_us(10);
ds1306_writebyte(0x8F, 0x02);
control = ds1306_readbyte(0x0F);
printf("Control byte value is %X\r\n", control);
/* printf("enter hour (0 - 23).\r\n");
hour = getnumber(str);
printf("enter minute (0 - 60).\r\n");
minute = getnumber(str);
printf("enter second (0 - 60).\r\n");
second = getnumber(str);
printf("enter day (1=monday, 2=tuesday, etc).\r\n");
day = getnumber(str);
printf("enter day of month (1 - 31).\r\n");
date = getnumber(str);
printf("enter month (1 - 12).\r\n");
month = getnumber(str);
printf("enter year 20XX (0 - 99).\r\n");
year = getnumber(str);*/
ds1306_settime_24hr(15, 20, 15);
ds1306_setdate(4, 23, 2, 6);
ds1306_setalarm1_24hr(15, 22, 00, 4);
enable_interrupts(global);
printf("Press 't' to retrieve the time and 'd' to retrieve the date.\r\n");
while(rb_pin == 0)
{
c = getc();
if ((c == 't') || (c == 'T'))
{
second = bcd2bin(ds1306_readbyte(0x00));
minute = bcd2bin(ds1306_readbyte(0x01));
hour = bcd2bin(ds1306_readbyte(0x02));
printf("Time = ");
if (hour < 10)
printf("0%d:", hour);
else
printf("%d:", hour);
if (minute < 10)
printf("0%d:", minute);
else
printf("%d:", minute);
if (second < 10)
printf("0%d", second);
else
printf("%d", second);
printf("\r\n");
}
c = getc();
if ((c == 'a') || (c == 'A'))
{
second = bcd2bin(ds1306_readbyte(0x0B));
minute = bcd2bin(ds1306_readbyte(0x0C));
hour = bcd2bin(ds1306_readbyte(0x0D));
printf("Alarm time = ");
if (hour < 10)
printf("0%d:", hour);
else
printf("%d:", hour);
if (minute < 10)
printf("0%d:", minute);
else
printf("%d:", minute);
if (second < 10)
printf("0%d", second);
else
printf("%d", second);
printf("\r\n");
}
if ((c == 'd') || (c == 'D'))
{
day = bcd2bin(ds1306_readbyte(0x03));
date = bcd2bin(ds1306_readbyte(0x04));
month = bcd2bin(ds1306_readbyte(0x05));
year = bcd2bin(ds1306_readbyte(0x06));
printf("Date = ");
switch(day)
{
case 1: printf("Monday");
break;
case 2: printf("Tuesday");
break;
case 3: printf("Wednesday");
break;
case 4: printf("Thursday");
break;
case 5: printf("Friday");
break;
case 6: printf("Saturday");
break;
case 7: printf("Sunday");
break;
}
printf(", ");
if (date < 10)
printf("0%d/", date);
else
printf("%d/", date);
if (month < 10)
printf("0%d/", month);
else
printf("%d/", month);
if (year < 10)
printf("0%d", year);
else
printf("%d", year);
printf("\r\n");
}
}
printf("\r\nInterrupt activated. ");
second = bcd2bin(ds1306_readbyte(0x00));
minute = bcd2bin(ds1306_readbyte(0x01));
hour = bcd2bin(ds1306_readbyte(0x02));
printf("Time = ");
if (hour < 10)
printf("0%d:", hour);
else
printf("%d:", hour);
if (minute < 10)
printf("0%d:", minute);
else
printf("%d:", minute);
if (second < 10)
printf("0%d", second);
else
printf("%d", second);
printf("\r\n");
}
|
ds1306.c
Code: | // Drivers for the DS1306 Real-Time Clock chip running in SPI mode.
// Simon Ayers - 08/02/2006
//
// ds1306_init(); Call before the other functions are used.
//
// ds1306_writebyte(addr, data); Write a single byte to address addr
//
// data = ds1306_readbyte(addr); Read a single byte from address addr
//
// ds1306_settime_12hr(hour, minute, second, ampm);
// - Set the RTC time when in 12hr mode (ampm = 1 when PM)
//
// ds1306_settime_24hr(hour, minute, second);
// - Set the RTC time when in 24hr mode
//
// ds1306_setdate(day, date, month, year);
// - day = 1-7 (1 = monday, 7 = sunday), date = 1-31, month 1-12, year = 0-99
//
// ds1306_setalarm0_12hr(hour, minute, second, ampm, day, mask)
// - sets alarm 0 when in 12hr mode (ampm = 1 when PM)
// - mask (datasheet page 7) msb = seconds, lsb = days
//
// ds1306_setalarm0_24hr(hour, minute, second, day, mask); As above but 24hr
//
// ds1306_setalarm1_12hr(hour, minute, second, ampm, day, mask): as ...alarm0_12hr
//
// ds1306_setalarm1_24hr(hour, minute, second, day, mask); As above but 24hr
//
#define DS1306_CE PIN_B2
#define DS1306_DO PIN_C5
#define DS1306_DI PIN_C4
#define DS1306_CLK PIN_C3
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));
}
void ds1306_init()
{
short int i;
output_low(DS1306_DO);
output_low(DS1306_CLK);
output_low(DS1306_CE);
i=input(DS1306_DI);
//setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_64);
return;
}
void ds1306_writebyte(int8 addr, int8 data)
{
output_high(DS1306_CE);
spi_write(addr);
spi_write(data);
output_low(DS1306_CE);
}
int8 ds1306_readbyte(int8 addr)
{
int8 data;
output_high(DS1306_CE);
spi_write(addr);
data = spi_read(0);
output_low(DS1306_CE);
return data;
}
void ds1306_settime_12hr(int8 hour, int8 minute, int8 second, int1 ampm)
{
/*hour = hour & 0x1F;
hour += (ampm * 0x20);
hour += 0x40;
minute = minute & 0x7F;
second = second & 0x7F;*/
output_high(DS1306_CE);
spi_write(0x80);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
output_low(DS1306_CE);
return;
}
void ds1306_settime_24hr(int8 hour, int8 minute, int8 second)
{
/*hour = hour & 0x3F;
minute = minute & 0x7F;
second = second & 0x7F;*/
output_high(DS1306_CE);
spi_write(0x80);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
output_low(DS1306_CE);
return;
}
void ds1306_setdate(int8 day, int8 date, int8 month, int8 year)
{
/*day = day & 0x07;
date = date & 0x3F;
month = month & 0x3F;
year = year & 0x7F;*/
output_high(DS1306_CE);
spi_write(0x83);
spi_write(bin2bcd(day));
spi_write(bin2bcd(date));
spi_write(bin2bcd(month));
spi_write(bin2bcd(year));
output_low(DS1306_CE);
return;
}
void ds1306_setalarm0_12hr(int8 hour, int8 minute, int8 second, int1 ampm, int8 day, int8 mask)
{
/*hour = hour & 0x1F;
hour += (ampm * 0x20);
hour += 0x40;
minute = minute & 0x7F;
second = second & 0x7F;
day = day &0x07;
second += (mask & 0x08);
minute += (mask & 0x04);
hour += (mask & 0x02);
day += (mask & 0x01);*/
output_high(DS1306_CE);
spi_write(0x87);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
spi_write(bin2bcd(day));
output_low(DS1306_CE);
return;
}
void ds1306_setalarm0_24hr(int8 hour, int8 minute, int8 second, int8 day)
{
/*hour = hour & 0x3F;
minute = minute & 0x7F;
second = second & 0x7F;
day = day &0x07;
second += (mask & 0x08);
minute += (mask & 0x04);
hour += (mask & 0x02);
day += (mask & 0x01);*/
output_high(DS1306_CE);
spi_write(0x87);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
spi_write(bin2bcd(day));
output_low(DS1306_CE);
return;
}
void ds1306_setalarm1_12hr(int8 hour, int8 minute, int8 second, int1 ampm, int8 day, int8 mask)
{
/*hour = hour & 0x1F;
hour += (ampm * 0x20);
hour += 0x40;
minute = minute & 0x7F;
second = second & 0x7F;
day = day &0x07;
second += (mask & 0x08);
minute += (mask & 0x04);
hour += (mask & 0x02);
day += (mask & 0x01);*/
output_high(DS1306_CE);
spi_write(0x8B);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
spi_write(bin2bcd(day));
output_low(DS1306_CE);
return;
}
void ds1306_setalarm1_24hr(int8 hour, int8 minute, int8 second, int8 day)
{
/*hour = hour & 0x3F;
minute = minute & 0x7F;
second = second & 0x7F;
day = day &0x07;
second += (mask & 0x08);
minute += (mask & 0x04);
hour += (mask & 0x02);
day += (mask & 0x01);*/
output_high(DS1306_CE);
spi_write(0x8B);
spi_write(bin2bcd(second));
spi_write(bin2bcd(minute));
spi_write(bin2bcd(hour));
spi_write(bin2bcd(day));
output_low(DS1306_CE);
return;
}
|
|
|
![](templates/subSilver/images/spacer.gif) |
Humberto
Joined: 08 Sep 2003 Posts: 1215 Location: Buenos Aires, La Reina del Plata
|
|
Posted: Wed Mar 08, 2006 7:13 am |
|
|
Quote: |
but I can't seem to get the interrupt pin INT1 (pin 6) on the DS1306 to activate
|
I don't see in your code where do you activate the bit1 (AIE1) in the DS1306 Control Register. It is vital to assert INT1.
Code: |
if (hour < 10)
printf("0%d:", hour);
else
printf("%d:", hour);
|
You can replace with:
Code: |
printf("%02d:", hour);
|
Humberto
Last edited by Humberto on Wed Mar 08, 2006 7:16 am; edited 2 times in total |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Mar 08, 2006 7:15 am |
|
|
Reading the DS1306 datasheet I noted two things in the following paragraph Quote: | IRQF1 (Interrupt 1 Request Flag) – A logic 1 in the interrupt request flag bit indicates that the current
time has matched the Alarm 1 registers. If the AIE1 bit is also a logic 1, the INT1 pin generates a 62.5ms
active-high pulse. IRQF1 is cleared when the address pointer goes to any of the alarm 1 registers during a
read or write. IRQF1 is activated only when the device is powered by VCC2 or VBAT. |
1) The IRQF1 flag is not automatically cleared, you will have to add this code in your interrupt handler.
2) It might be an error in the datasheet but here it explicitly mentions power must come from VCC2 or VBAT. For IRQF0 you have a choice out of three: VCC1, VCC2, or VBAT. |
|
![](templates/subSilver/images/spacer.gif) |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
|
Posted: Wed Mar 08, 2006 8:45 am |
|
|
Humberto wrote: |
I don't see in your code where do you activate the bit1 (AIE1) in the DS1306 Control Register. It is vital to assert INT1.
|
Sorry, I didn't remember to comment on my code. The following couple of lines should activate the AIE1 bit (hidden in the top of main.c).
Code: |
ds1306_init();
ds1306_writebyte(0x8F, 0x00); // Clear the configuration register (switch off write protection)
delay_us(10);
ds1306_writebyte(0x8F, 0x02); // Set AIE1 bit high
|
|
|
![](templates/subSilver/images/spacer.gif) |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
|
Posted: Wed Mar 08, 2006 8:47 am |
|
|
ckielstra wrote: | Reading the DS1306 datasheet I noted two things in the following paragraph Quote: | IRQF1 (Interrupt 1 Request Flag) – A logic 1 in the interrupt request flag bit indicates that the current
time has matched the Alarm 1 registers. If the AIE1 bit is also a logic 1, the INT1 pin generates a 62.5ms
active-high pulse. IRQF1 is cleared when the address pointer goes to any of the alarm 1 registers during a
read or write. IRQF1 is activated only when the device is powered by VCC2 or VBAT. |
1) The IRQF1 flag is not automatically cleared, you will have to add this code in your interrupt handler.
2) It might be an error in the datasheet but here it explicitly mentions power must come from VCC2 or VBAT. For IRQF0 you have a choice out of three: VCC1, VCC2, or VBAT. |
Ah, that could be the problem. I'll try powering the device from VCC2. |
|
![](templates/subSilver/images/spacer.gif) |
monkeytennis
Joined: 18 Feb 2004 Posts: 16 Location: UK
|
|
Posted: Mon Mar 13, 2006 7:26 am |
|
|
Powering the device from VCC2 seemed to solve the problem. Thanks. I knew it would be something stupid like that! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|