Attempting To Build A SimpleIDE Library For The DS1302 RTC - Could Use A Little Help :)

I recently purchased a DS1302 module from Parallax for my current project. Of course I am a C and C++ guy, and the documentation for this module and language is somewhat lacking my needs, so I decided to write my own library. I initially started the groundwork for this library, loosely based upon a post by Rsadeika, which can be found here: https://forums.parallax.com/discussion/168949/ds1302-module-c-code
His or her code has resulted in the following:
Hearder file (.h):
And the C file (.c)
Please note that none of this code has been tested yet
I am currently working on the get_unix_time function. As the self describing function clearly states, I am attempting to obtain Unix time. In order to obtain a fairly accurate Unix time (meanwhile ensuring that this library is useful to others), I must determine whether the RTC is in 12 or 24 hour mode. There is other significant code and efforts that are associated with the DS1302 RTC chip, by the greatly missed Chris Savage, but they are for the BASIC Stamp, which can be downloaded from here (https://parallax.com/downloads/ds1302-basic-stamp-demo-code.
A little help writing this last function would surely be appreciated
His or her code has resulted in the following:
Hearder file (.h):
#include "simpletools.h"
#include <time.h> //Included for the get_unix_time function
//DS1302 Pin Usage
#define DS1302_CS 1
#define DS1302_SCK 2
#define DS1302_IO 3
//DS1302 Time Registers
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
//DS1302 Date Registers
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
//DS1302 Day Register
#define DS1302_DAY 0x8A
//Read an individual DS1302 register value
int read_ds1302(int ds1302_register);
//Write an individual DS1302 register value
void write_ds1302(int ds1302_register, int ds1302_value);
//Set the DS1302 Hour register value
void set_ds1302_hour(int hour_register_value);
//Set the DS1302 Minute register value
void set_ds1302_minute(int minute_register_value);
//Set the DS1302 Second register value
void set_ds1302_second(int second_register_value);
//Set the DS1302 Date register value
void set_ds1302_date(int date_register_value);
//Set the DS1302 Month register value
void set_ds1302_month(int month_register_value);
//Set the DS1302 Year register value
void set_ds1302_year(int year_register_value);
//Set the DS1302 Day register value
void set_ds1302_day(int day_register_value);
//Get the DS1302 Hour register value
int get_ds1302_hour();
//Get the DS1302 Minute register value
int get_ds1302_minute();
//Get the DS1302 Second register value
int get_ds1302_second();
//Get the DS1302 Date register value
int get_ds1302_date();
//Get the DS1302 Month register value
int get_ds1302_month();
//Get the DS1302 Year register value
int get_ds1302_year();
//Get the DS1302 Day register value
int get_ds1302_day();
//Get Unix time - The header file "time.h" has been included
//specifically for this function
//
//Please note that in order to obtain fairly accurate
//Unix time, the DS1302 registers must be set according
//Coordinated Universal Time (or UTC), otherwise programming
//must compensate for time zone differences. For further
//information, please research Unix Time
int get_unix_time();
And the C file (.c)
#include "simpletools.h"
int read_ds1302(int ds1302_register)
{
int read_register_value;
int result;
read_register_value = ds1302_register + 1;
high(DS1302_CS);
shift_out(DS1302_IO, DS1302_SCK, LSBFIRST, 8, read_register_value);
result = shift_in(DS1302_IO, DS1302_SCK, LSBPRE, 8);
low(DS1302_CS);
return result;
}
void write_ds1302(int ds1302_register, int ds1302_value)
{
high(DS1302_CS);
shift_out(DS1302_IO, DS1302_SCK, LSBFIRST, 8, ds1302_register);
shift_out(DS1302_IO, DS1302_SCK, LSBFIRST, 8, ds1302_value);
low(DS1302_CS);
}
void set_ds1302_hour(int hour_register_value)
{
write_ds1302(DS1302_HOUR, hour_register_value);
}
void set_ds1302_minute(int minute_register_value)
{
write_ds1302(DS1302_MINUTE, minute_register_value);
}
void set_ds1302_second(int second_register_value)
{
write_ds1302(DS1302_SECOND, second_register_value);
}
void set_ds1302_date(int date_register_value)
{
write_ds1302(DS1302_DATE, date_register_value);
}
void set_ds1302_month(int month_register_value)
{
write_ds1302(DS1302_MONTH, month_register_value);
}
void set_ds1302_year(int year_register_value)
{
write_ds1302(DS1302_YEAR, year_register_value);
}
void set_ds1302_day(int day_register_value)
{
write_ds1302(DS1302_DAY, day_register_value);
}
int get_ds1302_hour()
{
return read_ds1302(DS1302_HOUR);
}
int get_ds1302_minute()
{
return read_ds1302(DS1302_MINUTE);
}
int get_ds1302_second()
{
return read_ds1302(DS1302_SECOND);
}
int get_ds1302_date()
{
return read_ds1302(DS1302_DATE);
}
int get_ds1302_month()
{
return read_ds1302(DS1302_MONTH);
}
int get_ds1302_year()
{
return read_ds1302(DS1302_YEAR);
}
int get_ds1302_day()
{
return read_ds1302(DS1302_DAY);
}
long get_unix_time()
{
struct tm t;
time_t unix_time;
t.tm_year = get_ds1302_year() - 1900;
t.tm_mon = get_ds1302_month();
t.tm_mday = get_ds1302_day();
t.tm_hour = 16;
t.tm_min = get_ds1302_minute();
t.tm_sec = get_ds1302_second();
//Is Daylight Saving Time in effect? -1 = Unknown, 0 = No, 1 = Yes
t.tm_isdst = -1;
unix_time = mktime(&t);
return (long)unix_time;
}
Please note that none of this code has been tested yet

I am currently working on the get_unix_time function. As the self describing function clearly states, I am attempting to obtain Unix time. In order to obtain a fairly accurate Unix time (meanwhile ensuring that this library is useful to others), I must determine whether the RTC is in 12 or 24 hour mode. There is other significant code and efforts that are associated with the DS1302 RTC chip, by the greatly missed Chris Savage, but they are for the BASIC Stamp, which can be downloaded from here (https://parallax.com/downloads/ds1302-basic-stamp-demo-code.
A little help writing this last function would surely be appreciated

Comments
Mike
As far as I can tell, your code does not handle the 12 or 24 hour mode, which is the reason for my post.
Ken Gracey
My goal was and still is to write a simple, easy to understand library, which most users could easily modify to suit their needs, and post it here, with appropriate licensing.
Being "complete" is quite a different issue
I am more of a PC programmer than a microcontroller programmer, so we would need a bit banger or two to jump in here.
However, you are certainly welcome to the end result whatever it may become, "complete" or incomplete
www.maximintegrated.com/en/products/analog/real-time-clocks/DS1302.html
https://datasheets.maximintegrated.com/en/ds/DS1302.pdf
Table 3 shows the layout of the registers. The values are in BCD format.
I have some SPIN code I wrote for a larger project if your interested. It reads and writes most the clock registers. Has a simple terminal interface for setting the date/time interactively and a somewhat unique method for displaying the data/time string.
It's still a work in progress.
I looked at the burst mode and memory functions that seem nice but offer very little to the product. It's not like it's an IMU and we need to constantly read the values in a timely manner.
Mike
Thanks for the heads up on the accuracy. I just purchased the DS1302 module from Parallax, so I think I will work on the code and experiment with that a little before swapping it out.
Ken
I have been looking very closely at Chris Savage's example code for the DS1302 and I now believe that it should be very easy to port it to the Propeller, in fact I have just started to swap the code. The main difference between his code and what I was attempting is that he used the burst mode for both his read from and writes to the DS1302, which should be perfectly fine for your customers.
For inside a home, the unit is relatively reliable, after you do the initial recalibration via the program code. For your general testing and code development, it should suffice.
Ray
Also my logging project shows how it can be used.
Mike
Mike
Not sure if there are any revelations in the following but I just stumbled across it.
The code examples are in line-numbered BASIC but easy enough to follow and I'm sure easily downgraded converted to c.
6 ' Interface to a DS1302 RTC 10 ce=20 ' clock enable pin 12 clk=19 ' clock pin 14 din = 18 ' read pin 16 dout = 18 ' write pin. normally is same as din 18 SETPIN ce,9 20 SETPIN clk,9 22 ' SETPIN din,2 'only required for different din/dout 24 SETPIN dout,9 26 PIN(ce)=0 28 PIN(clk)=0 30 PIN(dout)=0 32 INPUT "(r)ead and set time/date (rb)read byte (w)rite (e)nd";inp$ 34 IF inp$="r" THEN GOSUB 200 36 IF inp$="w" THEN GOSUB 2000 38 IF inp$="rb" THEN GOSUB 400 40 IF inp$="e" THEN END 42 GOTO 32 44 ' 200 ' ----- read ------- 202 PRINT "old time ";TIME$ 205 bitdata$="10000101":GOSUB 250: hr$=hi$+lo$ 210 bitdata$="10000011":GOSUB 250: min$=hi$+lo$ 215 bitdata$="10000001":GOSUB 250: sec$=hi$+lo$ 220 TIME$ = hr$+":"+min$+":"+sec$ : PRINT "new time ";TIME$ 225 bitdata$="10000111":GOSUB 250: dat$=hi$+lo$ 230 bitdata$="10001001":GOSUB 250: mnt$=hi$+lo$ 235 bitdata$="10001101":GOSUB 250: year$="20"+hi$+lo$ 240 PRINT dat$;"/";mnt$;"/";year$ : DATE$=dat$+"/"+mnt$+"/"+year$ 245 RETURN 249 ' 250 'read byte required and process 251 'data is in 2 x 4 bit nibbles 254 dataout$ = "" 255 GOSUB 1000 260 FOR p = 1 TO 8 STEP 4 'this sets the first bit to read. 1 or 5 265 REM PRINT MID$(dataout$,p,4); 270 bitval = VAL(MID$(dataout$,p,1)) 275 bitval=bitval + 2 * (VAL(MID$(dataout$,p+1,1))) 280 bitval=bitval + 4 * (VAL(MID$(dataout$,p+2,1))) 285 bitval=bitval + 8 * (VAL(MID$(dataout$,p+3,1))) 290 REM PRINT bitval;" "; 295 IF p=1 THEN lo$=STR$(bitval) ELSE hi$=STR$(bitval) 300 bitval = 0 305 NEXT p 310 RETURN 400 ' ----- read single byte only ---- 405 INPUT "read byte";bitdata$ 410 GOSUB 250 415 PRINT hi$;lo$;" "; 420 FOR i = 8 TO 1 STEP -1 425 PRINT MID$(dataout$,i,1); 430 NEXT i 435 PRINT 440 RETURN 445 END 1000 ' ------ read from RTC -------- 1005 PIN(ce)=1 1009 'step 1. write address to read 1010 FOR i = 8 TO 1 STEP -1 1015 bit =VAL(MID$(bitdata$,i,1)) 1020 PIN(dout)=bit 1025 PIN(clk)=1 1030 IF i>1 THEN PIN(clk)=0 'must leave clk high on transistion from write to r 1035 NEXT i 1040 PIN(dout)=1 'must leave dout high to be able to read din 1044 'step 2. read data coming back 1045 FOR i = 1 TO 8 1050 PIN(clk)=0 ' read is on the fall of the clock 1055 dataout$=dataout$+STR$(PIN(din)) 1060 PIN(clk)=1 1065 NEXT i 1070 PIN(ce)=0 1075 PIN(dout)=0 1080 PIN(clk)=0 1085 RETURN 1090 REM 2000 REM ------ write to RTC -------- 2005 PIN(ce)=1 2010 PIN(clk)=0 2015 INPUT "write address";bitdata$ 2020 INPUT "data";wbitdata$ 2025 FOR c = 1 TO 2 '2 bytes to write 2030 FOR i = 8 TO 1 STEP -1 2035 bit=VAL(MID$(bitdata$,i,1)) 2040 PIN(dout)=bit 2045 PIN(clk)=1 2050 PIN(clk)=0 2055 NEXT i 2060 bitdata$=wbitdata$ 2065 NEXT c 2070 PAUSE 10 2075 PIN(ce)=0 2080 PIN(dout)=0 2085 PIN(clk)=0 2090 RETURN
At this point, I have a fairly decent grasp of what is required, and I have written four functions, burst write, burst read, individual value write, and individual value read. The functions are currently working, except for having the data in the proper format. I know this is true, by testing with other firmware.
I am currently sidetracked from setting the proper format because I recently learned of the compiler's preprocessor macros for _DATE_ and _TIME_. I want to use these values to set the RTC, so that people will not have to code it manually. In other words, just compile the program, run the program, and the RTC will be set according to the PCs clock. However, before compiling and running the program, the user will have constants that can be modified to meet their particular requirements. Additionally, I am sure there will be a need for a time offset to adjust for the difference between compile and runtime, and this will also be a constant that can be modified. That is providing I find a way to copy these values
Anyhow, as always, I do appreciate your input.
EDIT: This works and the compiler does not complain
char strDate[12]; char strTime[9]; strcpy(strDate, __DATE__); strcpy(strTime, __TIME__); printf("%s\n", strDate); printf("%s\n", strTime);
I believe my previous post indicated this fact. At this point, my "time offset" would need to be about 2~3 seconds, but that will change.