SimpleIDE Code Examples For The DS1302 Module (New Sample Posted 04/05/2020)
idbruce
Posts: 6,197
Hello Everyone
My initial intent was to create a library for the DS1302, but after coming to the conclusion that is not what I wanted or needed, I simply created two projects, one for writing to the DS1302 and one for reading from the DS1302. I additionally came to the conclusion that the DS1302 has too much time drift for my requirements. However, since I had the DS1302 on hand and since I needed additional logical code for my project, I figured I would work on these two sections and post it when I thought it was a little worthy.
@Ken - I did not create a library for you, but I am fairly certain that the attached code samples will be of great use to many of your customers, and your minions should be able to create a decent library, using the examples provided here.
These code examples were built using a PropBOE Without drawing this out with a lengthy discussion, the main thing that needs to be done, is altering the Propeller I/O pin constants at the top of each C file.
I am going to post the code and also attach zipped project files.
EDIT: Please note that the following variables can be removed from the top of the main() function of the Read_The_DS1302.c file.
My initial intent was to create a library for the DS1302, but after coming to the conclusion that is not what I wanted or needed, I simply created two projects, one for writing to the DS1302 and one for reading from the DS1302. I additionally came to the conclusion that the DS1302 has too much time drift for my requirements. However, since I had the DS1302 on hand and since I needed additional logical code for my project, I figured I would work on these two sections and post it when I thought it was a little worthy.
@Ken - I did not create a library for you, but I am fairly certain that the attached code samples will be of great use to many of your customers, and your minions should be able to create a decent library, using the examples provided here.
These code examples were built using a PropBOE Without drawing this out with a lengthy discussion, the main thing that needs to be done, is altering the Propeller I/O pin constants at the top of each C file.
I am going to post the code and also attach zipped project files.
// Set_The_DS1302.c #include "simpletools.h" ////////////////////////////////////////////////////////////////// // OVERVIEW // This code is intended to set your DS1302 time and date according // the time it is complied and run on your PC, and should be run // seperately from your other firmware. Please note that DS1302 // has time drift issues. ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #1 // Before running this code, set your PC time clock to the highest // accuracy that you can possibly achieve. ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #2 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // CE pin. #define DS1302_CE 0 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #3 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // SCLK pin. #define DS1302_SCLK 1 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #4 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // I/O pin. #define DS1302_IO 2 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #5 - Adjust as necessary // Adjust for the difference between compile time and runtime. // This is the number of seconds between the compilation time and // the amount of time that it takes to write the date and time to // the DS1302 registers. #define OFFSET_SECONDS 4 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #6 - Run with terminal // If your DS1302 is inaccurate compared to your PC's time clock, // then repeat Step #5 and Step #6 until the DS1302 time and your // PC's time clock are synchronized. ////////////////////////////////////////////////////////////////// int second; int minute; int hour; int weekday; int month; int date; int year; int second_bcd; int minute_bcd; int hour_bcd; int weekday_bcd; int month_bcd; int date_bcd; int year_bcd; // Reset and enable the DS1302 void Reset() { low(DS1302_SCLK); low(DS1302_CE); high(DS1302_CE); } // Convert integer to binary coded decimal int DecimalToBCD(int Decimal) { return (((Decimal / 10) << 4) | (Decimal % 10)); } // Get the weekday... 0 = Sunday, 1 = Monday, etc. int GetTheWeekday() { int Weekday; int Month; int Date; int Year; Month = month; Date = date; Year = year; Weekday = ((Date += (Month < 3 ? Year-- :(Year - 2))), (23 * Month / 9 + Date + 4 + Year / 4 - Year / 100 + Year / 400)) % 7; return Weekday; } // Write all clock and calender registers in burst mode void Set_DS1302_Time() { Reset(); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, 0xBE); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, second_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, minute_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, hour_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, date_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, month_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, weekday_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, year_bcd); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, 0); Reset(); } // Read all clock and calender registers in burst mode void Get_DS1302_Time() { Reset(); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, (int)0xBF); second = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); minute = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); hour = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); date = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); month = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); weekday = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); year = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); Reset(); } int main() { const char *pCharacterPointer; char chMonth[4]; char chDate[3]; char chYear[5]; char chWeekday[2]; char chHour[3]; char chMinute[3]; char chSecond[3]; int previous_second; if(strstr(__DATE__, "Jan") != NULL) { month = 1; } else if(strstr(__DATE__, "Feb") != NULL) { month = 2; } else if(strstr(__DATE__, "Mar") != NULL) { month = 3; } else if(strstr(__DATE__, "Apr") != NULL) { month = 4; } else if(strstr(__DATE__, "May") != NULL) { month = 5; } else if(strstr(__DATE__, "Jun") != NULL) { month = 6; } else if(strstr(__DATE__, "Jul") != NULL) { month = 7; } else if(strstr(__DATE__, "Aug") != NULL) { month = 8; } else if(strstr(__DATE__, "Sep") != NULL) { month = 9; } else if(strstr(__DATE__, "Oct") != NULL) { month = 10; } else if(strstr(__DATE__, "Nov") != NULL) { month = 11; } else if(strstr(__DATE__, "Dec") != NULL) { month = 12; } pCharacterPointer = strstr(__DATE__, " "); if(pCharacterPointer != NULL) { pCharacterPointer += 2; strncpy(chDate, pCharacterPointer, 1); chDate[1] = '\0'; pCharacterPointer += 2; } else { pCharacterPointer = strstr(__DATE__, " "); if(pCharacterPointer != NULL) { pCharacterPointer += 1; strncpy(chDate, pCharacterPointer, 2); chDate[2] = '\0'; pCharacterPointer += 3; } } sprint(chMonth, "%d", month); strncpy(chYear, pCharacterPointer, 4); chYear[4] = '\0'; strncpy(chHour, __TIME__, 2); chHour[2] = '\0'; pCharacterPointer = strstr(__TIME__, ":"); pCharacterPointer += 1; strncpy(chMinute, pCharacterPointer, 2); chMinute[2] = '\0'; pCharacterPointer += 3; strncpy(chSecond, pCharacterPointer, 2); chSecond[2] = '\0'; month = atoi(chMonth); date = atoi(chDate); year = atoi(chYear); hour = atoi(chHour); minute = atoi(chMinute); second = atoi(chSecond); weekday = GetTheWeekday(); sprint(chWeekday, "%d", weekday); second = second + OFFSET_SECONDS; year = year - 2000; weekday = weekday + 1; print("Compile Date: "); print("%s/", chMonth); print("%s/", chDate); print("%s\n", chYear); print("Compile Time: "); print("%s:", chHour); print("%s:", chMinute); print("%s\n\n", chSecond); second_bcd = DecimalToBCD(second); minute_bcd = DecimalToBCD(minute); hour_bcd = DecimalToBCD(hour); weekday_bcd = DecimalToBCD(weekday); month_bcd = DecimalToBCD(month); date_bcd = DecimalToBCD(date); year_bcd = DecimalToBCD(year); Set_DS1302_Time(); previous_second = 0; while(1) { Get_DS1302_Time(); if(second != previous_second) { print("DS1302 Time: "); if(weekday == 1) { print("Sunday"); } else if(weekday == 2) { print("Monday"); } else if(weekday == 3) { print("Tuesday"); } else if(weekday == 4) { print("Wednesday"); } else if(weekday == 5) { print("Thursday"); } else if(weekday == 6) { print("Friday"); } else if(weekday == 7) { print("Saturday"); } print(" "); putHexLen(month,2); print("/"); putHexLen(date,2); print("/"); putHexLen(year,2); print(" "); putHexLen(hour,2); print(":"); putHexLen(minute,2); print(":"); putHexLen(second,2); print("\n"); } previous_second = second; } }
// Read_The_DS1302.c #include "simpletools.h" #include <time.h> ////////////////////////////////////////////////////////////////// // OVERVIEW // This code is intended to read the time and date of your DS1302. // Please note that DS1302 has time drift issues. ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #1 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // CE pin. #define DS1302_CE 0 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #2 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // SCLK pin. #define DS1302_SCLK 1 ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// // Step #3 - One time setting // Define the I/0 pin going from your Propeller chip to the DS1302 // I/O pin. #define DS1302_IO 2 ////////////////////////////////////////////////////////////////// int second; int minute; int hour; int weekday; int month; int date; int year; int second_bcd; int minute_bcd; int hour_bcd; int weekday_bcd; int month_bcd; int date_bcd; int year_bcd; // Reset and enable the DS1302 void Reset() { low(DS1302_SCLK); low(DS1302_CE); high(DS1302_CE); } int BCDToDecimal(int BCD) { return (((BCD >> 4) * 10) + (BCD & 0xF)); } // Get the weekday... 0 = Sunday, 1 = Monday, etc. int GetTheWeekday() { int Weekday; int Month; int Date; int Year; Month = month; Date = date; Year = year; Weekday = ((Date += (Month < 3 ? Year-- :(Year - 2))), (23 * Month / 9 + Date + 4 + Year / 4 - Year / 100 + Year / 400)) % 7; return Weekday; } // Read all clock and calender registers in burst mode void Get_DS1302_Time() { Reset(); shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, (int)0xBF); second = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); minute = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); hour = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); date = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); month = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); weekday = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); year = shift_in(DS1302_IO, DS1302_SCLK, LSBPRE, 8); Reset(); } int main() { const char *pCharacterPointer; char chMonth[4]; char chDate[3]; char chYear[5]; char chWeekday[2]; char chHour[3]; char chMinute[3]; char chSecond[3]; int previous_second; previous_second = 0; while(1) { Get_DS1302_Time(); if(second != previous_second) { print("DS1302 Time: "); if(weekday == 1) { print("Sunday"); } else if(weekday == 2) { print("Monday"); } else if(weekday == 3) { print("Tuesday"); } else if(weekday == 4) { print("Wednesday"); } else if(weekday == 5) { print("Thursday"); } else if(weekday == 6) { print("Friday"); } else if(weekday == 7) { print("Saturday"); } print(" "); putHexLen(month, 2); print("/"); putHexLen(date, 2); print("/"); putHexLen(year, 2); print(" "); putHexLen(hour, 2); print(":"); putHexLen(minute, 2); print(":"); putHexLen(second, 2); print(" "); print("\n"); int converted_second = BCDToDecimal(second); int converted_minute = BCDToDecimal(minute); int converted_hour = BCDToDecimal(hour); int converted_date = BCDToDecimal(date); int converted_month = BCDToDecimal(month) - 1; int converted_year = BCDToDecimal(year) + 2000 - 1900; struct tm current = { converted_second, converted_minute, converted_hour, converted_date, converted_month, converted_year }; time_t current_time = mktime(¤t); printf("Unix time for current time: %ld\n", current_time); struct tm previous = { 0, 0, 20, 29, 2, 120 }; time_t previous_time = mktime(&previous); printf("Unix time for 20:00:00 03/29/2020: %ld\n", previous_time); printf("Seconds of difference: %.f\n", difftime(current_time, previous_time)); // Create file or folder name /////////////////////////////////////////////////////////// char file_folder_name[80]; strftime(file_folder_name, sizeof(file_folder_name), "%Y%m%dT%H%M%S", ¤t); print("File or folder name: %s", file_folder_name); /////////////////////////////////////////////////////////// print("\n\n"); } previous_second = second; } }
EDIT: Please note that the following variables can be removed from the top of the main() function of the Read_The_DS1302.c file.
const char *pCharacterPointer; char chMonth[4]; char chDate[3]; char chYear[5]; char chWeekday[2]; char chHour[3]; char chMinute[3]; char chSecond[3];
Comments
EDIT: I will be providing one more example, which I will be working on today and perhaps tomorrow. This upcoming example will be made by altering the Read_The_DS1302.c file. In this upcoming example, I will be creating a folder and file on an SD card, named from values obtained from the DS1302 module, and then I will be writing UNIX timestamps to the file, with some other information attached. I don't really know how long it will take me, but I guess it shouldn't take that long.
I was almost finished coding the last sample, when I stumbled across this roadblock
I will need a minute or two to think about rearranging the intended naming of the file system.
I think the folders named after the year and month is okay.
I think the previously mentioned folder will now have subfolders created according to the day of the month (1~31).
I further think that I will now name the files located in these subfolders with the format of "HHMMSS.TXT".
I also think that plan will work. Undoubtedly it will be a bit more painful to reach a desired file, but I have to get around the 8.3 format one way or another
In other words, let's say a file is created March 31, 2020 at 20:43:36. The file path would be:
Once again, this makes it a bit more complicated to get at the log files, but I believe in the long run, it is a bit more organized.
200331/204336.TXT
so
YYMMDD/hhmmss.TXT
just saying, good for 100 80 years.
EDIT
sorry I am dumb today, with 8 chars you can do
YYYYMMDD for the Directory.
/EDIT
Mike
Flat structures are bad for humans, say you should not have more then 7 menu entries/buttons/whatever because the usual human can remember 7 things and click out of memory, with more then seven he has to READ all of it again.
Think of the development of menus and sub menus. Keep the number short.
On the other hand for computers flat structures are way more easy.
And for log files this is anyways something you will later on parse with some program for extraction of the problematic ones.
Enjoy!
Mike
Where was this suggestion before I started rewriting the relevant code
This is my latest and last example. To run this example, you will need a DS1302 RTC module, a board that has an SD card holder, an SD card, and two pushbuttons wired up to your board, to set off trigger events. For my testing, I used a PropBOE, activity board or something similar can also be used.
This sample creates timestamps in files on the SD card, according to trigger events.
Anyhow, once again, I don't feel much like talking about it, but I would suggest running the "Set_The_DS1302" example prior to running this one, to help ensure you get good timestamps.
Here is the code, but I am also attaching a zipped project file below:
This can be used for keeping some information while a prop reboots. I used it at some project to transfer a 'commandline' to the next starting P1 program.
And, yes the module has quite a drifting, but it is not that bad, who cares about some seconds per month.
I actually liked your idea to set time/date on loading the program, on a P1 it may not be as usable as on a P2, but with a 64 bit cnt on the P2 you are good for decades.
Anyways, me being a COBOL programmer I naturally hate C programmers - no offence here - but your source code does read nicely compared to most C programs.
Enjoy!
Mike
I must have recieved a lemon, because mine actually gains about 30 seconds per hour However, I recently ordered the Chronodot V2.1, created from the DS3231SN, but I still have not recieved it.
Yea, I stumbled across _DATE_ and _TIME_ accidentally. and I thought wow, I can use these to set the date and time on the RTC with an offset. Then I discovered that someone had already done it with a different RTC module. Of course, I wanted to be the first to come up with idea, but that wasn't the case
I will take that as a compliment I try to make my code easy to read, not so much for others, but for myself. I also usually try to add more comments, but I am getting lazier as I grow older.
After reviewing some firmware for the ChronoDot V2.1, I see they provide an option for writing an ISO 8601 timestamp (E.G.: 2000-01-01T12:34:56).
Is anyone interested in me updating my last example to include this option?
Sure, it would be good to have an ISO 8601 timestamp example as well...
Thank you, I'll check it out when I have a chance.
Thank you idbruce! I found this thread very helpful while using the DS1302 on my Propeller Pro Dev Board. For completeness, I wanted to add two things that I discovered while working on my project.
1) If you want to stop the clock, in the file Set_The_DS1302.c, find the line
<=shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, second_bcd);
modify the line to read
<=shift_out(DS1302_IO, DS1302_SCLK, LSBFIRST, 8, second_bcd + 128);
to set the CH (Clock Halt) bit. I'm not sure why you would want to set the time AND stop the clock, but that's your business. This is only included for your inspiration.
2) If you are using the PPDB (p/n 32111 RevB), I found that on my board, the battery connection terminals aren't connected to the DS1302 regardless of the J13 jumper positions. I only had a battery backed up clock when I ran a wire from J13 VEXT to the BAT connection on header X22. If your clock isn't keeping time with the battery power, check the DS1302, pin 8 for voltage.
Happy coding!