Combine hours, minutes and seconds to output

Using MD MAX and Parola libraries. I'm trying to make a clock using max7219 and 8x8 leds.
I start with minimal print example and ad RTC. I can display hours, minutes and seconds as their own, but trying to make hh:mm:ss display they just group and stack to the left corner. :smiley:

Any ideas how to display them in row instead on top of each other?

Code:

// Program to demonstrate the MD_Parola library
//
// Simplest program that does something useful - Hello!
// Uses the Arduino Print Class extension
//
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
//

#include <MD_Parola.h>
#include <MD_DS3231.h>

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup(void)
{
  P.begin();
}

void loop(void)
{
  RTC.readTime();
 P.print(RTC.h);
 P.print(RTC.m);
 P.print(RTC.s);
delay(1000);
}

sounds like you need to advance the caret (ie, the place at which the next print will start) after each print?

You can try this:

// Program to demonstrate the MD_Parola library
//
// Simplest program that does something useful - Hello!
// Uses the Arduino Print Class extension
//
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
//

#include <MD_Parola.h>
#include <MD_DS3231.h>

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary output pins
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

void setup(void)
{
   P.begin();
}

char buf[20];

void loop(void)
{
 RTC.readTime();
 sprintf(buf,"%02d%02d%02d",RTC.h, RTC.m,RTC.s);
 P.print(buf);
 delay(1000);
}

On Wokwi it looks like this:

Be aware that the sketch on Wokwi is different to your version due to the available simulation components ...!!!

Good luck!

Thank You :slight_smile:

Welcome!

To learn about sprintf() you may have a look here

std::printf, std::fprintf, std::sprintf, std::snprintf - cppreference.com

Be aware that unfortunately the formatting of float variables is switched off in the compiler directives as uses by Arduino IDE. There are work arounds for that:

http://yaab-arduino.blogspot.com/2015/12/how-to-sprintf-float-with-arduino.html

And finally: If you had more than 4 MAX devices you could add ":" between hours, minutes and seconds ( h:m:s ):

See here

Thank you, already playing with it and got "seconds" running. :smiley:
Currently i have 1X4 grid, but I'm drawing a custom PCB with easyeda.

Youtube how that clock turned out:

What caused the colon to stop blinking momentarily 5 seconds into the video? Was that intentional?

here is a demo-code that uses a different library

// Use the MD_MAX72XX library to Print some text on the display
//
// Demonstrates the use of the library to print text.
//
// User can enter text on the serial monitor and this will display as a
// message on the display.

#include <MD_MAX72xx.h>
#include <SPI.h>
#include <MD_DS3231.h>
#include "SafeString.h"

cSF(myMessage_SS,8);

#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 4

#define CLK_PIN   13  // or SCK
#define DATA_PIN  11  // or MOSI
#define CS_PIN    10  // or SS

// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Text parameters
#define CHAR_SPACING  1 // pixels between characters

// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE  75
char message[BUF_SIZE] = "Hello!";
bool newMessageAvailable = true;


void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
// Print the text string to the LED matrix modules specified.
// Message area is padded with blank columns after printing.
{
  uint8_t   state = 0;
  uint8_t   curLen;
  uint16_t  showLen;
  uint8_t   cBuf[8];
  int16_t   col = ((modEnd + 1) * COL_SIZE) - 1;

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);

  do     // finite state machine to print the characters in the space available
  {
    switch(state)
    {
      case 0: // Load the next character from the font table
        // if we reached end of message, reset the message pointer
        if (*pMsg == '\0')
        {
          showLen = col - (modEnd * COL_SIZE);  // padding characters
          state = 2;
          break;
        }

        // retrieve the next character form the font file
        showLen = mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
        curLen = 0;
        state++;
        // !! deliberately fall through to next state to start displaying

      case 1: // display the next part of the character
        mx.setColumn(col--, cBuf[curLen++]);

        // done with font character, now display the space between chars
        if (curLen == showLen)
        {
          showLen = CHAR_SPACING;
          state = 2;
        }
        break;

      case 2: // initialize state for displaying empty columns
        curLen = 0;
        state++;
        // fall through

      case 3:	// display inter-character spacing or end of message padding (blank columns)
        mx.setColumn(col--, 0);
        curLen++;
        if (curLen == showLen)
          state = 0;
        break;

      default:
        col = -1;   // this definitely ends the do loop
    }
  } while (col >= (modStart * COL_SIZE));

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

void setup() {
  mx.begin();

  Serial.begin(115200);
  Serial.print("\n[MD_MAX72XX Message Display]\nType a message for the display\nEnd message line with a newline");
}

void loop() {
    myMessage_SS = "Hello";
    //PRINT(myMessage_SS,"1");
    printText(0, MAX_DEVICES-1, myMessage_SS.c_str());
    delay(1000);

    //PRINT(myMessage_SS,"2");
    myMessage_SS = "World";
    printText(0, MAX_DEVICES-1, myMessage_SS.c_str());
    delay(1000);

    RTC.readTime();
    myMessage_SS  = RTC.h;
    myMessage_SS += ":";
    myMessage_SS += RTC.m;
    printText(0, MAX_DEVICES-1, myMessage_SS.c_str());
    delay(1000);    
}

best regards Stefan

bad power connection. I made a custom UNO board and at the moment of filming it was powered through ICSP header with loose jumper wires from programmer. It has "raspberry pi" DS3231 RTC Either on pins or soldered directly, and CR2032 holder soldered on PCB to keep clock running.
Also has RX/TX pins and other pins available, but mostly why i made this was that i needed a board that can be screwed behind these 1X4 matrices.

Changed it to USB-C power and now running just fine. (C used only for power)

First prototype..

Might need to reduce brightness for convenience, but MD libraries has that built in.

And here is the non-blocking state-machine variant

// Use the MD_MAX72XX library to Print some text on the display
//
// Demonstrates the use of the library to print text.
//
// User can enter text on the serial monitor and this will display as a
// message on the display.

#include <MD_MAX72xx.h>
#include <SPI.h>
#include <MD_DS3231.h>
#include "SafeString.h"

const byte ShowHello = 0;
const byte wait1     = 1;
const byte ShowWorld = 2;
const byte wait2     = 3;
const byte ShowTime  = 4;
const byte wait3     = 5;

const char myStateNames[][16] = {
  "ShowHello",
  "wait1",
  "ShowWorld",
  "wait2",
  "ShowTime",
  "wait3"
};

     
byte myStateVar = ShowHello;
unsigned long myWaitTimer;

cSF(myMessage_SS,8);

#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::PAROLA_HW
#define MAX_DEVICES 4

#define CLK_PIN   13  // or SCK
#define DATA_PIN  11  // or MOSI
#define CS_PIN    10  // or SS

// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// Arbitrary pins
//MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);

// Text parameters
#define CHAR_SPACING  1 // pixels between characters

// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE  75
char message[BUF_SIZE] = "Hello!";
bool newMessageAvailable = true;


void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
// Print the text string to the LED matrix modules specified.
// Message area is padded with blank columns after printing.
{
  uint8_t   state = 0;
  uint8_t   curLen;
  uint16_t  showLen;
  uint8_t   cBuf[8];
  int16_t   col = ((modEnd + 1) * COL_SIZE) - 1;

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);

  do     // finite state machine to print the characters in the space available
  {
    switch(state)
    {
      case 0: // Load the next character from the font table
        // if we reached end of message, reset the message pointer
        if (*pMsg == '\0')
        {
          showLen = col - (modEnd * COL_SIZE);  // padding characters
          state = 2;
          break;
        }

        // retrieve the next character form the font file
        showLen = mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
        curLen = 0;
        state++;
        // !! deliberately fall through to next state to start displaying

      case 1: // display the next part of the character
        mx.setColumn(col--, cBuf[curLen++]);

        // done with font character, now display the space between chars
        if (curLen == showLen)
        {
          showLen = CHAR_SPACING;
          state = 2;
        }
        break;

      case 2: // initialize state for displaying empty columns
        curLen = 0;
        state++;
        // fall through

      case 3:	// display inter-character spacing or end of message padding (blank columns)
        mx.setColumn(col--, 0);
        curLen++;
        if (curLen == showLen)
          state = 0;
        break;

      default:
        col = -1;   // this definitely ends the do loop
    }
  } while (col >= (modStart * COL_SIZE));

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

void setup() {
  mx.begin();
  Serial.begin(115200);
}

void loop() {
  myStateMachine();
}


void myStateMachine() {

  printStateOnChange(myStateVar);
  
  switch (myStateVar) {
    case ShowHello:
      myMessage_SS = "Hello";
      printText(0, MAX_DEVICES-1, myMessage_SS.c_str() );
      myStateVar = wait1;
      break;

    case wait1:
      if (TimePeriodIsOver(myWaitTimer,1000) ) {
        myStateVar = ShowWorld;
      }
      break;

    case ShowWorld:
      myMessage_SS = "World";
      printText(0, MAX_DEVICES-1, myMessage_SS.c_str() );
      myStateVar = wait2;
      break;

    case wait2:
      if (TimePeriodIsOver(myWaitTimer,1000) ) {
        myStateVar = ShowTime;
      }
      break;

    case ShowTime:
      RTC.readTime();
      myMessage_SS  = RTC.h;
      myMessage_SS += ":";
      myMessage_SS += RTC.m;
      printText(0, MAX_DEVICES-1, myMessage_SS.c_str() );
      myStateVar = wait3;
      break;

    case wait3:
      if (TimePeriodIsOver(myWaitTimer,1000)) {
        myStateVar = ShowHello;
      }
      break;
  }

}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void printStateOnChange(byte p_actualState) {

  static byte lastState;
  
  if (lastState != p_actualState) {
    Serial.print("state changed from ");
    Serial.print(myStateNames[lastState]);
    Serial.print(" to ");
    Serial.print(myStateNames[p_actualState]);
    Serial.println();
    lastState = p_actualState;
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.