/* ------------- Real Time Clock and 56 byte NVRAM ------------- */
#include <intrins.h>
#include "ds1307.h"
#include "display.h"
#include "serial.h"
sbit SDA = 0xE9; /* P4.1 DS1307 serial data */
sbit SCL = 0xEA; /* P4.2 DS1307 serial clock */
#define NOP5() _nop_();_nop_();_nop_();_nop_();_nop_()
#define SCL_HIGH(errmsg) {unsigned char i = 10; SCL = 1; while(!SCL)\
if(i-- == 0) halt(13, errmsg);}
bit
ds1307_send(unsigned char value)
{
unsigned char i = 8;
bit ack;
while(i--)
{
SDA = value & 0x80 ? 1 : 0;
value = value << 1;
SCL_HIGH("SCL ds1307_send()\n#1");
NOP5();
SCL = 0;
NOP5();
}
SDA = 1;
SCL_HIGH("SCL ds1307_send()\n#2");
ack = SDA;
SCL = 0;
return ack;
}
unsigned char
ds1307_receive(bit ack)
{
unsigned char buf, i = 8;
SDA = 1;
NOP5();
while(i--)
{
SCL_HIGH("ds1307_receive()\n#1");
NOP5();
buf = buf << 1 | SDA;
SCL = 0;
NOP5();
}
SDA = ack; /* ack */
SCL_HIGH("ds1307_receive()\n#2");
NOP5();
SCL = 0;
return buf;
}
void
ds1307_start()
{
SDA = 1;
SCL_HIGH("ds1307_start()\n#1");
if(!SDA)
halt(14, "ds1307_start()\n#2 SDA fault");
SDA = 0;
NOP5();
SCL = 0;
}
void
ds1307_stop()
{
SDA = 0;
SCL_HIGH("ds1307_stop()\nSCL fault");
NOP5();
SDA = 1;
}
unsigned char
ds1307_get_byte(unsigned char num)
{
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\non writing");
if(ds1307_send(num))
halt(24, "DS1307 no ACK\non writing");
ds1307_stop();
NOP5();
ds1307_start();
if(ds1307_send(0xD1))
halt(25, "DS1307 no ACK\non reading");
return ds1307_receive(1);
ds1307_stop();
}
void
ds1307_set_byte(unsigned char addr, unsigned char value)
{
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\in set_byte() #1");
if(ds1307_send(addr))
halt(23, "DS1307 no ACK\in set_byte() #2");
if(ds1307_send(value))
halt(23, "DS1307 no ACK\in set_byte() #3");
ds1307_stop();
}
void
ds1307_set_ulong(unsigned char addr, unsigned long value)
{
unsigned char i = 4;
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\in set_ulong() #1");
if(ds1307_send(addr))
halt(23, "DS1307 no ACK\in set_ulong() #2");
while (i--)
{
if(ds1307_send(value & 0xFFUL))
halt(23, "DS1307 no ACK\in set_ulong() #3");
value >>= 8;
}
ds1307_stop();
}
unsigned long
ds1307_get_ulong(unsigned char addr)
{
unsigned long value;
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\non writing");
if(ds1307_send(addr))
halt(24, "DS1307 no ACK\non writing");
ds1307_stop();
NOP5();
ds1307_start();
if(ds1307_send(0xD1))
halt(25, "DS1307 no ACK\non reading");
value = ds1307_receive(0);
value |= (unsigned long)ds1307_receive(0) << 8 ;
value |= (unsigned long)ds1307_receive(0) << 16 ;
value |= (unsigned long)ds1307_receive(1) << 24 ;
ds1307_stop();
return value;
}
void
ds1307_set_int(unsigned char addr, int value)
{
unsigned char i = 2;
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\in set_int() #1");
if(ds1307_send(addr))
halt(23, "DS1307 no ACK\in set_int() #2");
while (i--)
{
if(ds1307_send(value & 0xFFUL))
halt(23, "DS1307 no ACK\in set_int() #3");
value >>= 8;
}
ds1307_stop();
}
int
ds1307_get_int(unsigned char addr)
{
int value;
ds1307_start();
if(ds1307_send(0xD0))
halt(23, "DS1307 no ACK\non writing");
if(ds1307_send(addr))
halt(24, "DS1307 no ACK\non writing");
ds1307_stop();
NOP5();
ds1307_start();
if(ds1307_send(0xD1))
halt(25, "DS1307 no ACK\non reading");
value = ds1307_receive(0);
value |= (unsigned long)ds1307_receive(1) << 8 ;
ds1307_stop();
return value;
}
void
ds1307_init()
{
unsigned char tmp;
ds1307_receive(1); /* clear the buffer */
SCL_HIGH("ds1307_init()\nSCL FAULT #1");
NOP5();
SDA = 1;
NOP5();
if (!SDA)
halt(12, "ds1307_init()\nSDA line FAULT");
tmp = ds1307_get_byte(0x02);
if (tmp & 0x40) /* 12hr selected ? */
ds1307_set_byte(0x02, tmp & 0x3F); /* 24hr */
tmp = ds1307_get_byte(0x00);
if(tmp & 0x80) /* clock running ?*/
ds1307_set_byte(0x00, tmp & 0x7F);
ds1307_set_byte(0x07, 0x90); /* enable 1Hz SQW signal */
}
void
ds1307_set_date_time(char yy, char mm, char dd, char h, char m, char dow)
{
ds1307_start();
if(ds1307_send(0xD0))
halt(30, "DS1307 no ACK\nset_date() #1");
if(ds1307_send(0x00))
halt(30, "DS1307 no ACK\nset_date() #2");
ds1307_send(0); /* seconds to zero. Start clock also */
ds1307_send(((m/10) << 4) | m%10);
ds1307_send(((h/10) << 4) | h%10);
ds1307_send(dow);
ds1307_send(((dd/10) << 4) | dd%10);
ds1307_send(((mm/10) << 4) | mm%10);
ds1307_send(((yy/10) << 4) | yy%10);
ds1307_stop();
}
void
show_time(void)
{
unsigned char h, m, s;
ds1307_start();
if(ds1307_send(0xD0))
halt(31, "DS1307 no ACK\nshow_time() #1");
if(ds1307_send(0x00))
halt(31, "DS1307 no ACK\nshow_time() #2");
ds1307_stop();
NOP5();
ds1307_start();
if(ds1307_send(0xD1))
halt(31, "DS1307 no ACK\nshow_time() #3");
s = ds1307_receive(0);
m = ds1307_receive(0);
h = ds1307_receive(1);
ds1307_stop();
lcd_send(0, 0x80 | 0x08); /* set DDRAM address */
lcd_send(1, (h>>4) + '0');
lcd_send(1, (h & 0x0F) + '0');
lcd_send(1, ':');
lcd_send(1, (m >> 4) + '0');
lcd_send(1, (m & 0x0F) + '0');
}
/* Fills the buffer with current time and date */
void
syslog_time(void)
{
unsigned char h, m, s;
ds1307_start();
if(ds1307_send(0xD0))
halt(31, "DS1307 no ACK\nshow_time() #1");
if(ds1307_send(0x00))
halt(31, "DS1307 no ACK\nshow_time() #2");
ds1307_stop();
NOP5();
ds1307_start();
if(ds1307_send(0xD1))
halt(31, "DS1307 no ACK\nshow_time() #3");
s = ds1307_receive(0);
m = ds1307_receive(0);
h = ds1307_receive(0);
push_char((h>>4) + '0');
push_char((h & 0x0F) + '0');
push_char(':');
push_char((m >> 4) + '0');
push_char((m & 0x0F) + '0');
#ifdef LONG_TIME
push_char('.');
push_char((s >> 4) + '0');
push_char((s & 0x0F) + '0');
#endif
push_char(' ');
ds1307_receive(0); /* DOW */
s = ds1307_receive(0); /* day */
m = ds1307_receive(0); /* month */
h = ds1307_receive(1); /* year */
ds1307_stop();
#ifdef LONG_TIME
push_char((h>>4) + '0');
push_char((h & 0x0F) + '0');
push_char('/');
#endif
push_char((m >> 4) + '0');
push_char((m & 0x0F) + '0');
push_char('/');
push_char((s >> 4) + '0');
push_char((s & 0x0F) + '0');
push_char(' ');
}