Positional Control in MD_Parola ?

I am loving the MD_Parola library it is so easy to use but for my project it lacks a little bit of positional control as I would like to describe my need. Getting straight to the topic :- I am creating a clock which will contain the digits of the clock getting individual entry and exit animations. But as far as I have gone to achieve this has been in vain. This is the code which animates the whole of the timestring, but the thing is if I break the timestring in different parts I do not get how you would display them individually when the library only provides three positions for data to be displayed (right, center and left). How to achieve this any idea guys?

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Wire.h>
#include <RTClib.h>

#define MAX_DEVICES 8    // Set the number of devices in your matrix display
#define CLK_PIN   13     // Pin connected to the CLK pin of the display
#define DATA_PIN  11     // Pin connected to the DATA pin of the display
#define CS_PIN    10     // Pin connected to the CS pin of the display

MD_Parola matrix = MD_Parola(MD_MAX72XX::FC16_HW, CS_PIN, MAX_DEVICES);
RTC_DS1307 rtc;

void setup() {
  matrix.begin();
  rtc.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  if(matrix.displayAnimate())
  {
    matrix.displayText("Starting up", PA_CENTER, 20, 6000, PA_WIPE, PA_WIPE);
  }
}

void loop() {
  DateTime now = rtc.now();
  char timeString[9];
  sprintf(timeString, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
  if(matrix.displayAnimate())
  {
    matrix.displayText(timeString, PA_CENTER, 50, 1000, PA_SCROLL_DOWN, PA_SCROLL_UP);
  }
}

Is this the sort of thing that you are looking for Parola A to Z – Multi Zone Displays – Arduino++

1 Like

I am so surprised to have not seen that article before. I always thought that zones are for managing displays in physical quantity, I didn't knew that they can be used to make virtual displays. This is exactly what I need. I can't thank you enough. Have a good day to you sir :slight_smile:

I don't think zones will help, unless you want each character of the time string to use one 8x8 display ?

1 Like

What I planned was to use multiple sprintf to store hour, minutes and seconds in multiple buffers and then display them individually using the new knowledge of zones that I have acquired. I am guess with that I will be able to animate the digits accordingly. And now according to you yeah you are correct it may display only one digit per 8x8 matrix but I have 8 of them in series so 6 will be enough ...I am trying to create the code right now . Will text here after I have made it to work.

After using up almost 5 hours thinking that it would be easy to do it myself, I am stuck unfortunately. I am able to use only the first (0) zone , which is working as intended, the others are not working at all. If I set the currentZone variable in the following code to 1 or 2 for the zones that I have set, the zone doesn't lights up. I am guessing that I am missing something.

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CLK_PIN   13
#define DATA_PIN  11
#define CS_PIN    10

MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
int currentZone = 1;

void setup() {
  matrix.begin();
  matrix.setZone(0, 0, 2);
  matrix.setZone(1, 3, 5);
  matrix.setZone(2, 6, 8);
}

void loop() {
  if (matrix.displayAnimate()) {
    if (matrix.getZoneStatus(currentZone)) 
    {
      matrix.displayZoneText(currentZone, "29 ", PA_CENTER, 50, 2000, PA_SCROLL_DOWN, PA_SCROLL_UP);
    }
  }
}

The author of the library, @marco_c, is a member here but has not been seen for a while but has been very helpful in the past

Have you tried waiting until all zones have been updated as illustrated in the page that I linked to ?

Sad to hear that. But its fine , after 6 or so hours I found out from my friends(library examples) that when you are creating zones in the matrix display you need to specify them in the begin() function. For example as I need three zones I have to use matrix.begin(3) to activate zones and the next thing required is displayReset() function which is required after you call getZoneStatus(). I managed to add these two missing functions and Voila my zoned display worked. Not gonna lie but the article you ( UKHeliBob) have provided gave me a much needed hint on where I should rub my brain cells :slight_smile: Thanks.

Was on holidays :slight_smile:

Glad that it works as you need, however for completness:

  1. You don't need to wait for all zones to finish before updatsing. Each zone is independent and can be updated as soon as it has finished.
  2. There is an example in the MD_Parola library that displayed the time / date / day of week / temperature / humidity that can be used a starting point for this type of project. (Parola_Zone_TimeMsg)
  3. Zones should be initiaised in setup() before they are used. They can be changed later if required (see Parola_Zone_Dynamic example).
1 Like

Thanks @marco_c

1 Like

Thanks good sir. Yes you are correct there is an example like that , I missed that one as I usually start with the most basic ones, but I will study it now. Also thanks a lot for your hard work. I am really enjoying your library. :slight_smile:
Also thanks to you UKHeliBob for contacting him :slight_smile:

So now I know what to do and how to do and I require to display time using individual animations for each of the time components ( hours, minutes and seconds) and to do that I have done something like this? Please tell me if this is optimal, because what I am getting is that the digits refresh themselves only after the exit effect is over. How to fix this?


#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <Wire.h>
#include <RTClib.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 8

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

// Hardware SPI connection
MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
RTC_DS1307 rtc;


// Global variables
uint8_t currentString = 0;
uint8_t State = 0;
char string1[4];
char string2[4];
char string3[4];

unsigned int display_flag = 0;
unsigned long previousmillis = 0;
unsigned long interval = 1000;

void setup(void)
{

  matrix.begin(3);
  rtc.begin();

  // Set zone boundaries
  matrix.setZone(0, 0, 2);
  matrix.setZone(1, 3, 5);
  matrix.setZone(2, 6, 7);

  matrix.displayZoneText(0, string1, PA_LEFT, 5, 1000, PA_SCROLL_DOWN, PA_SCROLL_UP);
  matrix.displayZoneText(1, string2, PA_CENTER, 5, 1000, PA_SCROLL_DOWN, PA_SCROLL_UP);
  matrix.displayZoneText(2, string3, PA_RIGHT, 5, 1000, PA_SCROLL_DOWN, PA_SCROLL_UP);
}

void loop(void)
{
  DateTime now = rtc.now();
  sprintf(string1, "%02d", now.second());
  sprintf(string2, "%02d:", now.minute());
  sprintf(string3, "%02d:", now.hour());
  if (matrix.displayAnimate())
  {
    for (uint8_t i=0; i<3; i++)
    {
      if (matrix.getZoneStatus(i))
      {
        matrix.displayReset(i);
      }
    }
  }
}

Let's start from first principles - What do you want to see?

1 Like

Thanks for replying. I wanted to make a clock which will have scrolling up animation for the digits of the time. Let me explain, for example , the time is 10:30:57 , the matrix display will show the time and then when the seconds change from 57 to 58 it will scroll up the digit in one's place i.e. 7 scrolled up and 8 will take its place, and so on for the entire time screen, then I wanted to change the replace the entire time screen(probably after 3 seconds) and then display calender.
And yes I wanted to use the MD_Parola because its fantastic and so easy to use. So far I have tried various things :-

  1. Firstly I used a string to display time but it scrolled up entirely obviously . LOL. I meant like this :-
String timeString = formatTime(now.hour(), now.minute(), now.second());
matrix.displayText(timeString.c_str(), PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);

This was my first attempt at doing this and obviously at this point I didn't knew much about zones.

  1. Then I used sprintf to break the timestring and then display the components(hour, minute and seconds) individually but they also resulted in more or less the same output as the first code, here take a look :-
void displayDigit(char digit, int position) {
  char digitString[2] = {digit, '\0'};
  matrix.displayText(digitString, position, 50, 0, PA_PRINT, PA_PRINT);
}

void loop() {
  DateTime now = rtc.now();
  char timeString[9];
  sprintf(timeString, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());

  for (int i = 0; i < 8; i++) {
    matrix.displayClear();  // Clear the display

    for (int j = 0; j < 8; j++) {
      char digitChar = timeString[j];
      displayDigit(digitChar, j);

      matrix.displayAnimate();
      delay(100);  // Adjust the delay to control the animation speed
    }
  }
}

Here as you can see I have also tried to manually position the string components but it didn't worked as I figured out that the positional parameter can take only three values 0, 1 and 2 which corresponds to Left , Center and Right, the string stopped displaying after reaching the far right corner.
Also Please cut me some slack as this is an older code in which I tested the positional parameter but hadn't broke the timestring using sprintf. The idea I had was to display the different components of time in different places by changing the positional parameter but it failed.

  1. Next UKHeliBob gave me an article which explained what zones are actually used for I always thought that zones are for controlling groups of matrices that you get from store, I mean for example the hardware type FC16_HW has four 8x8 matrices so if you are using 2 of those modules then zones would become 2. That is what I thought but how wrong I was.LOL.
    Here is what I did with my new acquired knowledge of zones but failed here as well.

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CS_PIN 10

MD_Parola matrix = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
RTC_DS1307 rtc;

unsigned long previousmillis = 0;
unsigned long interval = 3000;
int seconds = 0, minutes = 0, hours = 0;
int prevseconds = 0, prevminutes = 0, prevhours = 0;
int display_flag = 0, introDone = 0;

char hourstring[2], minutestring[2], secondstring[2];

void setup(void) 
{
  matrix.begin(3);
  rtc.begin();
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  matrix.setZone(0, 0, 2);
  matrix.setZone(1, 3, 5);
  matrix.setZone(2, 6, 7);

  matrix.displayZoneText(0, secondstring, PA_LEFT, 50, 100, PA_NO_EFFECT, PA_NO_EFFECT);
  matrix.displayZoneText(1, minutestring, PA_CENTER, 50, 100, PA_NO_EFFECT, PA_NO_EFFECT);
  matrix.displayZoneText(2, hourstring, PA_RIGHT, 50, 100, PA_NO_EFFECT, PA_NO_EFFECT);
}

void loop(void) 
{
  clock();
  reset_zones();
  
}


void clock(void)
{
  DateTime now = rtc.now();
  hours = now.hour();
  minutes = now.minute();
  seconds = now.second();
  sprintf(hourstring, "%d%d", (now.hour()/10), (now.hour()%10));
  sprintf(minutestring, "%d%d", (now.minute()/10), (now.minute()%10));
  sprintf(secondstring, "%d%d", (now.second()/10), (now.second()%10));
}

void reset_zones(void)
{
  matrix.displayAnimate();
  if(matrix.getZoneStatus(0))
  {
    if((display_flag == 0) && (seconds != prevseconds))
    {
      matrix.setTextEffect(0, PA_SCROLL_UP, PA_SCROLL_UP);
      prevseconds = seconds;
    }
    else
    {
      matrix.setTextEffect(0, PA_NO_EFFECT, PA_NO_EFFECT); 
    }
    matrix.displayReset(0);
  }

  if(matrix.getZoneStatus(1))
  {
    if((display_flag == 0) && (minutes != prevminutes))
    {
      matrix.setTextEffect(1, PA_SCROLL_UP, PA_SCROLL_UP);
      prevminutes = minutes;
    }
    else
    {
      matrix.setTextEffect(1, PA_NO_EFFECT, PA_NO_EFFECT); 
    }
    matrix.displayReset(1);
  }

  if(matrix.getZoneStatus(2))
  {
    if((display_flag == 0) && (hours != prevhours))
    {
      matrix.setTextEffect(2, PA_SCROLL_UP, PA_SCROLL_UP);
      prevhours = hours;
    }
    else
    {
      matrix.setTextEffect(2, PA_NO_EFFECT, PA_NO_EFFECT); 
    }
    matrix.displayReset(2);
  }
}

This code just displays the seconds only once(they don't refresh) and they are flickering as well, minutes and hours are absent from the display(they are not displaying the places where they should be displayed are off). Also please tell me how to use the setzone() function, if I use this configuration then there is some space left between the 0th and 1st zone but the 2nd zone loses some place where it should display data, you can say that the 1st zone is shifted a little bit to the left (away from the data lines where arduino is connected).

You don't have to give a code I want to do everything myself (as its a birthday gift for my little brother(he loves leds) ) but please guide me on what should be done to achieve this :slight_smile:
I highly appreciate you guys helping me.

OK. This is now clearer.

You will find it difficult to do the animation you want using Parola as the scrolling digits will not look right as the minimum zone is one matrix and zone boundaries are the edge of a matrix. The characters are small compared to the matrix and as you will have one digit per module and it will look too spaced out in my opinion.

However, can you look at the MD_MAX72xx example MD_MAX72xx_Pushwheel to confirm this is the type of animation you need? This should contain all the logic (which is quite complex) you need for scrolling one digit on the display. You can then adapt this to suit your needs.

1 Like

Yeah I figured that to do what I need I might need 6 zones which is kinda impossible with just eight matrices I have. Thanks for guiding me to an example let me check that, I will be back in no time.

I just tested out the example on my hardware and the logic is exactly what I need although the animations are not as neat as when using the MD_Parola's scrollup but I guess its better than nothing , imma try to create my clock using that example. I will provide what I have done after I am finished.

OK. Just remember that you can do some in MD_Parola (messages) and some in MD_MAX72xx directly (time display).

Use the getGraphicObject() method to get the underlying shared MD_MAX72xx object to take over the display (just don't call displayAnimate() when you go direct).

1 Like

You are suggesting that I can use both libraries simultaneously? Wow . That would be amazing. Imma start searching and studying the getGraphicObject() function.

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