[EN] Arduino : RTC DS1302

From the article programming Python on Micropython to use RTC number DS1302, this time, we change the programming language to C++ for Arduino by using STM32F030F4P6 Cortex-M0, esp8266 and Arduino Mega as a worker instead of ESP32 as shown in Figures 1, 2 and 6 by show the report on the RS232 port to display the date and time as shown in Figure 4.

(Figure. 1 DS1302 experiment with STM32F30F4_6.)
(Figure. 2 Using the ds1302 module with esp8266.)

Code

Program code for reading and writing date/time with IC ds1302’s RTC is as follows. It is connected to the microcontroller via pins PA2, PA3 and PA4 to SCLK, IO and CE respectively as shown in Figure 3.

(Figure. 3 Shows the pins connected to the DS1302 module.)
// ds1302
// (C) 2021, by JarutEx (https://ww.jarutex.com)
#include <miniSerial.h>

#define PIN_CE PA4
#define PIN_SCLK PA2
#define PIN_IO PA3
#define REG_SECOND  0x80
#define REG_MINUTE  0x82
#define REG_HOUR    0x84
#define REG_DAY     0x86
#define REG_MONTH   0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR    0x8C
#define REG_WP      0x8E
#define REG_CTRL    0x90
#define REG_RAM     0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s

inline void disCe() {
  digitalWrite( PIN_CE, LOW );
}

inline void enaCe() {
  digitalWrite( PIN_CE, HIGH );
}

inline void pulse() {
  digitalWrite( PIN_SCLK, HIGH );
  digitalWrite( PIN_SCLK, LOW );
}

uint8_t dec2bcd(uint8_t n) {
  return ((int)(n / 10) * 16 + (n % 10));
}

uint8_t bcd2dec( uint8_t n ) {
  return ((int)(n / 16 * 10) + (n % 16));
}

void write( uint8_t data ) {
  uint8_t dataBit;
  pinMode( PIN_IO, OUTPUT );
  for (int i = 0; i < 8; i++) {
    dataBit = (data & 0x01);
    data >>= 1;
    digitalWrite( PIN_IO, dataBit );
    pulse();
  }
}

uint8_t read() {
  uint8_t byteData = 0x00;
  uint8_t bitData;
  pinMode( PIN_IO, INPUT );
  for (int i = 0; i < 8; i++) {
    bitData = digitalRead( PIN_IO ) & 0x01;
    bitData <<= i;
    byteData |= bitData;
    pulse();
  }
  return byteData;
}

void set(uint8_t reg, uint8_t value) {
  enaCe();
  write(reg);
  write(value);
  disCe();
}

uint8_t get(uint8_t reg) {
  uint8_t value = 0;
  enaCe();
  write(reg + 1);
  value = read();
  disCe();
  return value;
}

void now() {
  rtc[0] = bcd2dec( get(REG_YEAR) );
  rtc[1] = bcd2dec( get(REG_MONTH) );
  rtc[2] = bcd2dec( get(REG_DAY) );
  rtc[3] = bcd2dec( get(REG_WEEKDAY) );
  rtc[4] = bcd2dec( get(REG_HOUR) );
  rtc[5] = bcd2dec( get(REG_MINUTE) );
  rtc[6] = bcd2dec( get(REG_SECOND) );
}

void adjust(uint8_t day, uint8_t month, uint16_t year,
            uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
  // convert
  year -= 2000;
  year &= 0xff;
  year = dec2bcd((uint8_t)year);
  month = dec2bcd(month);
  day = dec2bcd(day);
  dow = dec2bcd(dow);
  minute = dec2bcd(minute);
  hour = hour & 0x1F;
  hour = dec2bcd(hour);
  second = dec2bcd(second);
  // adjust
  set(REG_YEAR, year);
  set(REG_MONTH, month);
  set(REG_DAY, day);
  set(REG_WEEKDAY, dow);
  set(REG_HOUR, hour);
  set(REG_MINUTE, minute);
  set(REG_SECOND, second);
}

void show() {
  Serial.print( rtc[3] );
  Serial.print(" ");
  Serial.print( rtc[0]+2000 );
  Serial.print("-");
  Serial.print( rtc[1] );
  Serial.print("-");
  Serial.print( rtc[2] );
  Serial.print(" ");
  Serial.print( rtc[4] );
  Serial.print(":");
  Serial.print( rtc[5] );
  Serial.print(":");
  Serial.print( rtc[6] );
  Serial.println("");
}

void setup(void)
{
  Serial.begin(9600);
  // Serial.begin(19200, PA2, PA3);
  // Setting
  pinMode( PIN_IO, OUTPUT );
  pinMode( PIN_SCLK, OUTPUT );
  pinMode( PIN_CE, OUTPUT );
  disCe();
  digitalWrite( PIN_SCLK, LOW );

  adjust( 8, 7, 2021, 4, 13, 53, 0);
}

void loop()
{
  Serial.run();
  now();
  show();
  delay(1000);
}

The result is shown in figure 4.

(Figure. 4 The result of the serial monitor program.)

Example code for esp8266

In the case of using esp8266, we choose pins D1, D2 and D4 or GPIO5, GPIO4 and GPIO2 to connect to pins SCLK, IO and CE to use DS1302. The code is as follows.

// ds1302/esp8266
// (C) 2021, by JarutEx (https://ww.jarutex.com)

#define PIN_CE 2 // D4
#define PIN_SCLK 5 // D1
#define PIN_IO 4 // D2

#define REG_SECOND  0x80
#define REG_MINUTE  0x82
#define REG_HOUR    0x84
#define REG_DAY     0x86
#define REG_MONTH   0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR    0x8C
#define REG_WP      0x8E
#define REG_CTRL    0x90
#define REG_RAM     0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s

inline void disCe() {
  digitalWrite( PIN_CE, LOW );
}

inline void enaCe() {
  digitalWrite( PIN_CE, HIGH );
}

inline void pulse() {
  digitalWrite( PIN_SCLK, HIGH );
  digitalWrite( PIN_SCLK, LOW );
}

uint8_t dec2bcd(uint8_t n) {
  return ((int)(n / 10) * 16 + (n % 10));
}

uint8_t bcd2dec( uint8_t n ) {
  return ((int)(n / 16 * 10) + (n % 16));
}

void write( uint8_t data ) {
  uint8_t dataBit;
  pinMode( PIN_IO, OUTPUT );
  for (int i = 0; i < 8; i++) {
    dataBit = (data & 0x01);
    data >>= 1;
    digitalWrite( PIN_IO, dataBit );
    pulse();
  }
}

uint8_t read() {
  uint8_t byteData = 0x00;
  uint8_t bitData;
  pinMode( PIN_IO, INPUT );
  for (int i = 0; i < 8; i++) {
    bitData = digitalRead( PIN_IO ) & 0x01;
    bitData <<= i;
    byteData |= bitData;
    pulse();
  }
  return byteData;
}

void set(uint8_t reg, uint8_t value) {
  enaCe();
  write(reg);
  write(value);
  disCe();
}

uint8_t get(uint8_t reg) {
  uint8_t value = 0;
  enaCe();
  write(reg + 1);
  value = read();
  disCe();
  return value;
}

void now() {
  rtc[0] = bcd2dec( get(REG_YEAR) );
  rtc[1] = bcd2dec( get(REG_MONTH) );
  rtc[2] = bcd2dec( get(REG_DAY) );
  rtc[3] = bcd2dec( get(REG_WEEKDAY) );
  rtc[4] = bcd2dec( get(REG_HOUR) );
  rtc[5] = bcd2dec( get(REG_MINUTE) );
  rtc[6] = bcd2dec( get(REG_SECOND) );
}

void adjust(uint8_t day, uint8_t month, uint16_t year,
            uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
  // convert
  year -= 2000;
  year &= 0xff;
  year = dec2bcd((uint8_t)year);
  month = dec2bcd(month);
  day = dec2bcd(day);
  dow = dec2bcd(dow);
  minute = dec2bcd(minute);
  hour = hour & 0x1F;
  hour = dec2bcd(hour);
  second = dec2bcd(second);
  // adjust
  set(REG_YEAR, year);
  set(REG_MONTH, month);
  set(REG_DAY, day);
  set(REG_WEEKDAY, dow);
  set(REG_HOUR, hour);
  set(REG_MINUTE, minute);
  set(REG_SECOND, second);
}

void show() {
  Serial.print( rtc[3] );
  Serial.print(" ");
  Serial.print( rtc[0]+2000 );
  Serial.print("-");
  Serial.print( rtc[1] );
  Serial.print("-");
  Serial.print( rtc[2] );
  Serial.print(" ");
  Serial.print( rtc[4] );
  Serial.print(":");
  Serial.print( rtc[5] );
  Serial.print(":");
  Serial.print( rtc[6] );
  Serial.println("");
}

void setup(void)
{
  Serial.begin(9600);

  pinMode( PIN_IO, OUTPUT );
  pinMode( PIN_SCLK, OUTPUT );
  pinMode( PIN_CE, OUTPUT );
  disCe();
  digitalWrite( PIN_SCLK, LOW );

  adjust( 8, 7, 2021, 4, 13, 53, 0);
}

void loop()
{
  now();
  show();
  delay(1000);
}

The setting of Arduino IDE is as shown in the figure 5.

(Figure. 5 Arduino IDE board setup to use with esp8266.)

Example code for Arduino Mega

When trying to change the pin values for SCLK, IO and CE to D2, D3 and D4 of Arduino Mega as shown in figure 6 and configure as shown in figure 7, the program code is as follows.

// ds1302/Arduino Mega
// (C) 2021, by JarutEx (https://ww.jarutex.com)

#define PIN_CE 4
#define PIN_SCLK 2
#define PIN_IO 3

#define REG_SECOND  0x80
#define REG_MINUTE  0x82
#define REG_HOUR    0x84
#define REG_DAY     0x86
#define REG_MONTH   0x88
#define REG_WEEKDAY 0x8A
#define REG_YEAR    0x8C
#define REG_WP      0x8E
#define REG_CTRL    0x90
#define REG_RAM     0xC0
uint8_t rtc[] = {0, 0, 0, 0, 0, 0, 0}; // y/m/d/dw/h/mi/s

inline void disCe() {
  digitalWrite( PIN_CE, LOW );
}

inline void enaCe() {
  digitalWrite( PIN_CE, HIGH );
}

inline void pulse() {
  digitalWrite( PIN_SCLK, HIGH );
  digitalWrite( PIN_SCLK, LOW );
}

uint8_t dec2bcd(uint8_t n) {
  return ((int)(n / 10) * 16 + (n % 10));
}

uint8_t bcd2dec( uint8_t n ) {
  return ((int)(n / 16 * 10) + (n % 16));
}

void write( uint8_t data ) {
  uint8_t dataBit;
  pinMode( PIN_IO, OUTPUT );
  for (int i = 0; i < 8; i++) {
    dataBit = (data & 0x01);
    data >>= 1;
    digitalWrite( PIN_IO, dataBit );
    pulse();
  }
}

uint8_t read() {
  uint8_t byteData = 0x00;
  uint8_t bitData;
  pinMode( PIN_IO, INPUT );
  for (int i = 0; i < 8; i++) {
    bitData = digitalRead( PIN_IO ) & 0x01;
    bitData <<= i;
    byteData |= bitData;
    pulse();
  }
  return byteData;
}

void set(uint8_t reg, uint8_t value) {
  enaCe();
  write(reg);
  write(value);
  disCe();
}

uint8_t get(uint8_t reg) {
  uint8_t value = 0;
  enaCe();
  write(reg + 1);
  value = read();
  disCe();
  return value;
}

void now() {
  rtc[0] = bcd2dec( get(REG_YEAR) );
  rtc[1] = bcd2dec( get(REG_MONTH) );
  rtc[2] = bcd2dec( get(REG_DAY) );
  rtc[3] = bcd2dec( get(REG_WEEKDAY) );
  rtc[4] = bcd2dec( get(REG_HOUR) );
  rtc[5] = bcd2dec( get(REG_MINUTE) );
  rtc[6] = bcd2dec( get(REG_SECOND) );
}

void adjust(uint8_t day, uint8_t month, uint16_t year,
            uint8_t dow, uint8_t hour, uint8_t minute, uint8_t second) {
  // convert
  year -= 2000;
  year &= 0xff;
  year = dec2bcd((uint8_t)year);
  month = dec2bcd(month);
  day = dec2bcd(day);
  dow = dec2bcd(dow);
  minute = dec2bcd(minute);
  hour = hour & 0x1F;
  hour = dec2bcd(hour);
  second = dec2bcd(second);
  // adjust
  set(REG_YEAR, year);
  set(REG_MONTH, month);
  set(REG_DAY, day);
  set(REG_WEEKDAY, dow);
  set(REG_HOUR, hour);
  set(REG_MINUTE, minute);
  set(REG_SECOND, second);
}

void show() {
  Serial.print( rtc[3] );
  Serial.print(" ");
  Serial.print( rtc[0]+2000 );
  Serial.print("-");
  Serial.print( rtc[1] );
  Serial.print("-");
  Serial.print( rtc[2] );
  Serial.print(" ");
  Serial.print( rtc[4] );
  Serial.print(":");
  Serial.print( rtc[5] );
  Serial.print(":");
  Serial.print( rtc[6] );
  Serial.println("");
}

void setup(void)
{
  Serial.begin(9600);

  pinMode( PIN_IO, OUTPUT );
  pinMode( PIN_SCLK, OUTPUT );
  pinMode( PIN_CE, OUTPUT );
  disCe();
  digitalWrite( PIN_SCLK, LOW );

  adjust( 8, 7, 2021, 4, 13, 53, 0);
}

void loop()
{
  now();
  show();
  delay(1000);
}
(Figure. 6 Using Module DS1302 with Arduino Mega.)

(Figure. 7 Setting up the board for the Arduino Mega.)

Conclusion

From this article, you will find that when you understand the principles and can write in any language, transcoding a program across languages ​​is not that difficult and it’s a good coding practice. In addition, you will found that migrating code for use with different microcontrollers using the Arduino framework requires careful attention to the architecture and PINs before programming. Finally, we hope that the RTC module implementation example of IC DS1302 would be more or less useful. And have fun with programming.

If you want to talk with us, feel free to leave comments below!!

(C) 2020-2021, By Jarut Busarathid and Danai Jedsadathitikul
Updated 2021-10-20