Shop OBEX P1 Docs P2 Docs Learn Events
SimpleIDE Code Examples For The DS1302 Module (New Sample Posted 04/05/2020) — Parallax Forums

SimpleIDE Code Examples For The DS1302 Module (New Sample Posted 04/05/2020)

idbruceidbruce Posts: 6,197
edited 2020-04-05 11:18 in Propeller 1
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.
// 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(&current);
      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", &current);

      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

  • idbruceidbruce Posts: 6,197
    edited 2020-03-30 11:31
    I tried editing my previous post, but for some reason that is not working, so I am posting the additional information here.


    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.
  • idbruceidbruce Posts: 6,197
    edited 2020-03-31 18:20
    Here is some comments from the upcoming example that I am currently working on. This should give you a pretty good idea of what the next example will be doing.
          ///////////////////////////////////////////////////////////      
          // Create folder name
          // For my purposes, one folder per month is sufficient,so
          // the folders will be named according to the current year
          // and month.
          ///////////////////////////////////////////////////////////
          char folder_name[80];
          strftime(folder_name, sizeof(folder_name),
            "%Y%m", &current);
    
          print("Folder name: %s\n", folder_name);
          
          ///////////////////////////////////////////////////////////      
          // Create file name
          // For my purposes, files will be created and written to 
          // according to a beginning trigger event and an ending
          // trigger event.  The beginning trigger event will create
          // and open the file for witing, and the ending trigger
          // event will close the file.  This file will be stored in
          // a folder named according to the current year and month,
          // in which the file was created.  While the file is open
          // for writing, I will be writing UNIX timestamps to the file
          // based on other trigger events.  For the purpose of this
          // example, I will be using two pushbuttons to signal
          // trigger events.  The first button press of the first
          // button will create a folder, based on year and month, if
          // it does not already exist.  Afterwards it will create and
          // and open a file, within the previously mentioned folder,
          // for writing.  With each button press of the second button,
          // a UNIX timestamp will be added to the open file.  A second
          // button press of the first button will indicate that the
          // logging procedure has been completed, and the file will be
          // closed, with no further writing to this specific file.
          // Additionally, it is worth noting that this file will be
          // created and named according to the current date and time
          // of the DS1302.
          ///////////////////////////////////////////////////////////
          char file_name[80];
          strftime(file_name, sizeof(file_name),
            "%Y%m%dT%H%M%S", &current);
    
          print("File name: %s\n", file_name);
          ///////////////////////////////////////////////////////////
    
  • Regarding my last post, I have no option available to me, except to change the file and folder naming conventions that I had originally intended. It has been such a very long time since I have used an SD card in one of my projects, that I forgot that the drivers use short file names, of the 8.3 format.

    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 :(
  • Since no one is providing any input here, about my 8.3 format crisis :) , I now think that I will also seperate the year and the month into different directories. Which essentially means that any files created will all be three (3) directories deep.

    In other words, let's say a file is created March 31, 2020 at 20:43:36. The file path would be:
    2020/03/31/204336.TXT

    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.
  • msrobotsmsrobots Posts: 3,709
    edited 2020-04-01 00:50
    I would go for
    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
  • And NO, it's not more organized, from the computer perspective, doing a simple DIR 202003* gives you the filenames you need. Structure for human vision is not structured for computer use.

    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
  • Mike

    Where was this suggestion before I started rewriting the relevant code :expressionless:
  • However no biggie.... just a few quick changes at this point. I like the plan Mike. Thanks
  • Alrighty My Dear Parallaxians

    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:
    // DS1302_Timestamps.c
    
    #include "simpletools.h"
    #include <time.h>
    #include <stdbool.h>
    
    //////////////////////////////////////////////////////////////////
    // OVERVIEW
    // This code is intended to read the time and date of your DS1302
    // and write timestamps to a file based upon pushbutton trigger
    // events. 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
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #4 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DO (Data Out)
    #define SD_DO 22
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #5 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CLK (Clock)
    #define SD_CLK 23
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #6 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DI (Data In)
    #define SD_DI 24
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #7 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CS (Chip Select)
    #define SD_CS 25
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #8 - One time setting
    // Define the I/0 pin going from your Propeller chip to a pushbutton,
    // which will trigger the creation of a folder if it does not exist
    // and it will create a file for data logging (timestamps).
    #define PB_FOLDER_FILE 13
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #9 - One time setting
    // Define the I/0 pin going from your Propeller chip to a pushbutton,
    // which will trigger the writing of a timestamp to an open file.
    #define PB_TIMESTAMP 4
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #10 - Run with the terminal and push some buttons :)
    //////////////////////////////////////////////////////////////////
    
    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;
    
    int converted_second;
    int converted_minute;
    int converted_hour;
    int converted_date;
    int converted_month;
    int converted_year;
          
    struct tm current;
          
    time_t current_time;
    
    // 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));
    }
    
    // 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();
      
      converted_second = BCDToDecimal(second);
      converted_minute = BCDToDecimal(minute);
      converted_hour = BCDToDecimal(hour);
      converted_date = BCDToDecimal(date);
      converted_month = BCDToDecimal(month) - 1;
      converted_year = BCDToDecimal(year) + 2000 - 1900;
      
      current.tm_sec = converted_second;
      current.tm_min = converted_minute;
      current.tm_hour = converted_hour;
      current.tm_mday = converted_date;
      current.tm_mon = converted_month;
      current.tm_year = converted_year;
      
      current_time = mktime(&current);
    }
    
    int main()
    {
      char folder_name[9];
      char file_name[11];
      char file_path[20];
      char timestamp[15];
      
      bool bLogging;
      
      FILE* file_pointer;
      
      bLogging = false;
      
      sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
      
      print("Press your buttons to create folders, files, and timestamps\n\n");
      
      while(1)
      {
        if(bLogging == false)
        {
          if(input(PB_FOLDER_FILE) == 1)
          {
            Get_DS1302_Time();
            
            strftime(folder_name, sizeof(folder_name), "%Y%m%d", &current);
            
            strftime(file_name, sizeof(file_name), "%H%M%S", &current);
            
            // Add the desired extension to complete the file name
            strcat(file_name, ".txt");
            
            if(mkdir(folder_name, 0) == 0)
            {
              print("Folder Created: %s\n", folder_name);
            }
            else
            {
              print("Folder Must Already Exist: %s\n", folder_name);
            }
            
            // Creating the file path
            strcpy(file_path, folder_name);
            strcat(file_path, "\\");        
            strcat(file_path, file_name);
            
            print("File Path: %s\n", file_path);
            
            sprint(timestamp, "%d", current_time);
            strcat(timestamp, "\r\n");
            
            file_pointer = fopen(file_path, "w");
            
            if(file_pointer != NULL)
            {
              print("File Opened: %s\n", file_name);
              
              fwrite(timestamp, sizeof(char), strlen(timestamp), file_pointer);
              
              printf("Timestamp Written: %d\n", current_time);
              
              memset(timestamp, 0, sizeof(timestamp));
            }
            
            bLogging = true;
            
            pause(200);        
          }
        }
        else
        {
          if(input(PB_FOLDER_FILE) == 1)
          {
            fclose(file_pointer);
            
            bLogging = false;
            
            print("File Closed: %s\n\n", file_name);
            
            memset(folder_name, 0, sizeof(folder_name));
            memset(file_name, 0, sizeof(file_name));
            memset(file_path, 0, sizeof(file_path));
            
            pause(200);
          }
          else if(input(PB_TIMESTAMP) == 1)
          {
            Get_DS1302_Time();
            
            sprint(timestamp, "%d", current_time);
            strcat(timestamp, "\r\n");
            
            fwrite(timestamp, sizeof(char), strlen(timestamp), file_pointer);
            
            printf("Timestamp Written: %d\n", current_time);
            
            memset(timestamp, 0, sizeof(timestamp));
            
            pause(200);
          }        
        }
      }    
    }
    
  • The ds1302 module has some ram one can use, not much bytes, but some.

    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
  • Mike
    And, yes the module has quite a drifting, but it is not that bad, who cares about some seconds per month.

    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.
    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.

    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 :(
    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.

    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.
  • For those of you who may be testing my firmware, in my last example, you will have noticed that I am writing Unix timestamps (E.G.: 1585922355) to the created log files. I coded it this way, to make it easy to calculte time spans, however it certainly is not easy to determine the time and date by looking at it.

    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?
  • idbruce wrote: »
    For those of you who may be testing my firmware, in my last example, you will have noticed that I am writing Unix timestamps (E.G.: 1585922355) to the created log files. I coded it this way, to make it easy to calculate time spans, however it certainly is not easy to determine the time and date by looking at it.

    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...
  • idbruceidbruce Posts: 6,197
    edited 2020-04-05 11:59
    As requested by Francis Bauer, I have altered the DS1302_Timestamps project to now include the option of writing ISO 8601 timestamps, instead of Unix timestamps. You can now select one or the other. The source code is shown below and a zipped project file has been added as well.
    // DS1302_Timestamps.c
    
    #include "simpletools.h"
    #include <time.h>
    #include <stdbool.h>
    
    //////////////////////////////////////////////////////////////////
    // OVERVIEW
    // This code is intended to read the time and date of your DS1302
    // and write timestamps to a file based upon pushbutton trigger
    // events. 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
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #4 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DO (Data Out)
    #define SD_DO 22
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #5 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CLK (Clock)
    #define SD_CLK 23
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #6 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DI (Data In)
    #define SD_DI 24
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #7 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CS (Chip Select)
    #define SD_CS 25
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #8 - One time setting
    // Define the I/0 pin going from your Propeller chip to a pushbutton,
    // which will trigger the creation of a folder if it does not exist
    // and it will create a file for data logging (timestamps). This
    // pushbutton trigger also closes the file.
    #define PB_FOLDER_FILE 13
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #9 - One time setting
    // Define the I/0 pin going from your Propeller chip to a pushbutton,
    // which will trigger the writing of a timestamp to an open file.
    #define PB_TIMESTAMP 4
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #10 - One time setting
    // Define the type of timestamp to be written to the log file by
    // "commenting" and "uncommenting" the "#define(s)" below.  You can
    // only use one or the other, unless you modify the source code.
    //#define WRITE_UNIX_TIMESTAMP // E.G.: 1585922355
    #define WRITE_ISO8601_TIMESTAMP // E.G.: 2000-01-01T12:34:56
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #11 - Run with the terminal and push some buttons :)
    // Please note: All "print" and "printf" instructions may be
    // removed from the following source code, if you do not require
    // the use of a terminal.
    //////////////////////////////////////////////////////////////////
    
    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;
    
    int converted_second;
    int converted_minute;
    int converted_hour;
    int converted_date;
    int converted_month;
    int converted_year;
          
    struct tm current;
          
    time_t current_time;
    
    FILE* file_pointer;
    
    // 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));
    }
    
    // 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();
      
      converted_second = BCDToDecimal(second);
      converted_minute = BCDToDecimal(minute);
      converted_hour = BCDToDecimal(hour);
      converted_date = BCDToDecimal(date);
      converted_month = BCDToDecimal(month) - 1;
      converted_year = BCDToDecimal(year) + 2000 - 1900;
      
      current.tm_sec = converted_second;
      current.tm_min = converted_minute;
      current.tm_hour = converted_hour;
      current.tm_mday = converted_date;
      current.tm_mon = converted_month;
      current.tm_year = converted_year;
      
      current_time = mktime(&current);
    }
    
    // This function will write a timestamp to an opened log file.
    // The type of timestamp written will depend upon the timetamp
    // constant defined at the begiining of this source code.
    // E.G.: #define WRITE_UNIX_TIMESTAMP or WRITE_ISO8601_TIMESTAMP.
    // If you need a prefix, suffix, or both, to be added to the
    // timestamp, this would be the function to modify. The entry
    // written to the opened file, within this function, can easily
    // be modified by using the string functions defined in "string.h".
    // For further information about these string functions, please
    // refer to: http://www.cplusplus.com/reference/cstring/
    void WriteFileData()
    {
      ////////////////////////////////////////////////////////////////////////
      
      #ifdef WRITE_UNIX_TIMESTAMP
    
      char timestamp[15]; // May need modification dependant upon requirements
      
      sprint(timestamp, "%d", current_time);
      
      printf("Timestamp Written: %d\n", current_time);
      
      // Any additional modifications should begin after this point
      
      strcat(timestamp, "\r\n");
      
      fwrite(timestamp, sizeof(char), strlen(timestamp), file_pointer);
      
      ////////////////////////////////////////////////////////////////////////
    
      #elif defined WRITE_ISO8601_TIMESTAMP
    
      char timestamp[24]; // May need modification dependant upon requirements
      
      strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", &current);
      
      print("Timestamp Written: %s", timestamp);
      print("\n");
      
      // Any additional modifications should begin after this point
      
      strcat(timestamp, "\r\n");
      
      fwrite(timestamp, sizeof(char), strlen(timestamp), file_pointer);
      
      ////////////////////////////////////////////////////////////////////////
    
      #endif
    }
    
    int main()
    {
      char folder_name[9];
      char file_name[11];
      char file_path[20];
      
      bool bLogging;
      
      bLogging = false;
      
      sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
      
      print("Press your buttons to create folders, files, and timestamps\n\n");
      
      while(1)
      {
        if(bLogging == false)
        {
          if(input(PB_FOLDER_FILE) == 1)
          {
            Get_DS1302_Time();
            
            strftime(folder_name, sizeof(folder_name), "%Y%m%d", &current);
            
            strftime(file_name, sizeof(file_name), "%H%M%S", &current);
            
            // Add the desired file extension to complete the file name
            strcat(file_name, ".txt");
            
            if(mkdir(folder_name, 0) == 0)
            {
              print("Folder Created: %s\n", folder_name);
            }
            else
            {
              print("Folder Must Already Exist: %s\n", folder_name);
            }
            
            // Creating the file path
            strcpy(file_path, folder_name);
            strcat(file_path, "\\");        
            strcat(file_path, file_name);
            
            print("File Path: %s\n", file_path);
            
            file_pointer = fopen(file_path, "w");
            
            if(file_pointer != NULL)
            {
              print("File Opened: %s\n", file_name);
              
              WriteFileData();
            }
            
            bLogging = true;
            
            pause(200);        
          }
        }
        else
        {
          if(input(PB_FOLDER_FILE) == 1)
          {
            fclose(file_pointer);
            
            bLogging = false;
            
            print("File Closed: %s\n\n", file_name);
            
            memset(folder_name, 0, sizeof(folder_name));
            memset(file_name, 0, sizeof(file_name));
            memset(file_path, 0, sizeof(file_path));
            
            pause(200);
          }
          else if(input(PB_TIMESTAMP) == 1)
          {
            Get_DS1302_Time();
            
            WriteFileData();
            
            pause(200);
          }        
        }
      }    
    }
    
  • idbruce wrote: »
    As requested by Francis Bauer, I have altered the DS1302_Timestamps project to now include the option of writing ISO 8601 timestamps, instead of Unix timestamps. You can now select one or the other. The source code is shown below and a zipped project file has been added 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!

Sign In or Register to comment.