Shop OBEX P1 Docs P2 Docs Learn Events
SimpleIDE Code Examples For The DS3231 RTC (Final Example Added 04/07/2020) — Parallax Forums

SimpleIDE Code Examples For The DS3231 RTC (Final Example Added 04/07/2020)

idbruceidbruce Posts: 6,197
edited 2020-04-07 15:31 in Propeller 1
Hello Everyone

For those of you who have been following along, I have recently posted several project examples for the DS1302 RTC, which can be found here (forums.parallax.com/discussion/171402/simpleide-code-examples-for-the-ds1302-module-new-sample-posted-04-05-2020).

Instead of the DS1302 RTC, in this thread, I will be providing several project examples for the DS3231 RTC. The DS3231 RTC is supposedly a much more accurate timepiece.

Anyhow, I will basically be reusing the majority of the code from the previous thread, simply swapping out several of the functions to the I2C protocol.

Here is the code for the first example and I will be attaching a zipped project file below:
// Set_The_DS3231.c

#include "simpletools.h"

//////////////////////////////////////////////////////////////////
// OVERVIEW
// This code is intended to set your DS3231 time and date according
// the time it is complied and run on your PC, and should be run
// seperately from your other firmware.
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// 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 DS3231
// SDA pin.
#define DS3231_SDA 14
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// Step #3 - One time setting
// Define the I/0 pin going from your Propeller chip to the DS3231
// SCL pin.
#define DS3231_SCL 15
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// Step #4 - 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 DS3231 registers.
#define OFFSET_SECONDS 4
//////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////
// Step #5 - Run with terminal
// If your DS3231 is inaccurate compared to your PC's time clock,
// then repeat Step #4 and Step #5 until the DS3231 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;

i2c *pBus;

// 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;
}

void Set_DS3231_Time()
{
  i2c_start(pBus);
  
  i2c_writeByte(pBus, 0xd0);
  i2c_writeByte(pBus, 0x00);
  i2c_writeByte(pBus, second_bcd);
  i2c_writeByte(pBus, minute_bcd);
  i2c_writeByte(pBus, hour_bcd);
  i2c_writeByte(pBus, weekday_bcd);
  i2c_writeByte(pBus, date_bcd);
  i2c_writeByte(pBus, month_bcd);
  i2c_writeByte(pBus, year_bcd);

  i2c_stop(pBus);
}

void Get_DS3231_Time()
{
  i2c_start(pBus);
  
  i2c_writeByte(pBus, 0xd0);
  i2c_writeByte(pBus, 0);
  
  i2c_start(pBus);
  
  i2c_writeByte(pBus, 0xd0 | 1);
  
  second = i2c_readByte(pBus, 0);
  minute = i2c_readByte(pBus, 0);
  hour = i2c_readByte(pBus, 0);
  weekday = i2c_readByte(pBus, 0);
  date = i2c_readByte(pBus, 0);
  month = i2c_readByte(pBus, 0);
  year = i2c_readByte(pBus, 1);
  
  i2c_stop(pBus);
}

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;
  
  i2c_open(pBus, DS3231_SCL, DS3231_SDA, 0);
  
  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_DS3231_Time();
  
  previous_second = 0;
  
  while(1)
  {  
    Get_DS3231_Time();
    
    if(second != previous_second)
    {  
      print("DS3231 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;
  }    
}

Comments

  • I was surprised to see the DS3231 does not have the 31 bytes of general purpose RAM that the DS1302 has.
  • idbruceidbruce Posts: 6,197
    edited 2020-04-07 00:17
    Publison
    I was surprised to see the DS3231 does not have the 31 bytes of general purpose RAM that the DS1302 has.

    To be honest, it doesn't matter much to me at this moment, because I am only interested in timestamps. However, there may come such a time when it will be important to me. :smile:


    As for everyone else, here is the code for the second example. I will also be attaching a zipped project file below.
    // Read_The_DS3231.c
    
    #include "simpletools.h"
    #include <time.h>
    
    //////////////////////////////////////////////////////////////////
    // OVERVIEW
    // This code is intended to read the time and date of your DS3231.
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #1 - One time setting
    // Define the I/0 pin going from your Propeller chip to the DS3231
    // SDA pin.
    #define DS3231_SDA 14
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #2 - One time setting
    // Define the I/0 pin going from your Propeller chip to the DS3231
    // SCL pin.
    #define DS3231_SCL 15
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #3 - Run with the 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;
    
    i2c *pBus;
    
    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_DS3231_Time()
    {
      i2c_start(pBus);
      
      i2c_writeByte(pBus, 0xd0);
      i2c_writeByte(pBus, 0);
      
      i2c_start(pBus);
      
      i2c_writeByte(pBus, 0xd0 | 1);
      
      second = i2c_readByte(pBus, 0);
      minute = i2c_readByte(pBus, 0);
      hour = i2c_readByte(pBus, 0);
      weekday = i2c_readByte(pBus, 0);
      date = i2c_readByte(pBus, 0);
      month = i2c_readByte(pBus, 0);
      year = i2c_readByte(pBus, 1);
      
      i2c_stop(pBus);
    }
    
    int main()
    {
      int previous_second;
      
      previous_second = 0;
      
      i2c_open(pBus, DS3231_SCL, DS3231_SDA, 0);
      
      while(1)
      {  
        Get_DS3231_Time();
        
        if(second != previous_second)
        {  
          print("DS3231 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 a folder name based upon the current year, current
          // month, and current date.
          ///////////////////////////////////////////////////////////
          char folder_name[9];
          strftime(folder_name, sizeof(folder_name), "%Y%m%d", &current);
    
          print("Folder name: %s\n", folder_name);
          
          ///////////////////////////////////////////////////////////      
          // Create a file name based upon the current hour, current
          // minute, and current second.
          ///////////////////////////////////////////////////////////
          char file_name[7];
          strftime(file_name, sizeof(file_name), "%H%M%S", &current);
    
          print("File name: %s\n", file_name);
          ///////////////////////////////////////////////////////////
          
          print("\n");
        }
        
        previous_second = second;
      }    
    }
    
  • Everything was going smoothly until I started working on the last example, and then I started having some issues. I am tired of programming for today, so the last example will have to wait until tomorrow :neutral:
  • idbruceidbruce Posts: 6,197
    edited 2020-04-12 08:29
    Pertaining to my last post, I am not surprised I was having issues last night. I forgot to add the following instruction to the main function:
    i2c_open(pBus, DS3231_SCL, DS3231_SDA, 0);

    DUH :)

    Anyhow, here is the code for the last example and I have attached a zipped project file below.
    // DS3231_Timestamps.c
    
    #include "simpletools.h"
    #include <time.h>
    #include <stdbool.h>
    
    //////////////////////////////////////////////////////////////////
    // OVERVIEW
    // This code is intended to read the time and date of your DS3231
    // and write timestamps to a file based upon pushbutton trigger
    // events.
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #1 - One time setting
    // Define the I/0 pin going from your Propeller chip to the DS3231
    // SDA pin.
    #define DS3231_SDA 14
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #2 - One time setting
    // Define the I/0 pin going from your Propeller chip to the DS3231
    // SCL pin.
    #define DS3231_SCL 15
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #3 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DO (Data Out)
    #define SD_DO 22
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #4 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CLK (Clock)
    #define SD_CLK 23
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #5 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD DI (Data In)
    #define SD_DI 24
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #6 - One time setting
    // Define the I/0 pin going from your Propeller chip to the
    // SD CS (Chip Select)
    #define SD_CS 25
    //////////////////////////////////////////////////////////////////
    
    //////////////////////////////////////////////////////////////////
    // Step #7 - 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 #8 - 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 #9 - 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 #10 - 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;
    
    i2c *pBus;
    
    FILE* file_pointer;
    
    int BCDToDecimal(int BCD)
    {
       return (((BCD >> 4) * 10) + (BCD & 0xF));
    }
    
    // Read all clock and calender registers in burst mode
    void Get_DS3231_Time()
    {
      i2c_start(pBus);
      
      i2c_writeByte(pBus, 0xd0);
      i2c_writeByte(pBus, 0);
      
      i2c_start(pBus);
      
      i2c_writeByte(pBus, 0xd0 | 1);
      
      second = i2c_readByte(pBus, 0);
      minute = i2c_readByte(pBus, 0);
      hour = i2c_readByte(pBus, 0);
      weekday = i2c_readByte(pBus, 0);
      date = i2c_readByte(pBus, 0);
      month = i2c_readByte(pBus, 0);
      year = i2c_readByte(pBus, 1);
      
      i2c_stop(pBus);
      
      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 timestamp
    // 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[21];
      
      bool bLogging;
      
      bLogging = false;
      
      sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
      
      i2c_open(pBus, DS3231_SCL, DS3231_SDA, 0);
      
      print("Press your buttons to create folders, files, and timestamps\n\n");
      
      while(1)
      {
        if(bLogging == false)
        {
          if(input(PB_FOLDER_FILE) == 1)
          {
            Get_DS3231_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_DS3231_Time();
            
            WriteFileData();
            
            pause(200);
          }        
        }
      }    
    }
    
Sign In or Register to comment.