Help on 4 zone Parola LED matrix display

I am trying to build a 24 display with 4 zones as below

[Clock - 4 units] [Temperature / Humid - 4 units - Alternate]
[Date / Day - 8 units - Alternate]
[ Scroll Message - 8 units]

Can anyone help me correct the code for the multi zone display. I need the logic for the four zone update with out interrupting each other.
Any suggestions are welcome.

void setup(void)
{
  
  Serial.begin(115200);
  Serial3.begin(115200); // Bluetooth communication
  pinMode(BUZZER_PIN, OUTPUT);
 
  pinMode(LDRPin, INPUT); // For LDR
   P.begin(MAX_ZONES);
   P.setIntensity(0); //Set the display intensity
  P.setZone(0, 0, MAX_DEVICES - 17);
  P.setZone(1, MAX_DEVICES - 16, MAX_DEVICES - 9);
  P.setZone(2, MAX_DEVICES - 8, MAX_DEVICES - 5);
  P.setZone(3, MAX_DEVICES - 4, MAX_DEVICES - 1);
  P.setFont(3, numeric7Seg);
  P.setFont(2, numeric7Seg);
  rotaryswitch.begin();

  //***** Interrupt Service Routine for Rotary encoder inputs.
  PCICR |= (1 << PCIE0);
  PCMSK0 |= (1 << PCINT4) | (1 << PCINT5);
  sei();

  //Display routine

  //P.displayZoneText(1, szTime, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_PRINT, PA_NO_EFFECT);

  //P.displayZoneText(1, szTime, PA_CENTER, SPEED_TIME, PAUSE_TIME, PA_FADE);
  //P.displayZoneText(0, szMesg, PA_CENTER, SPEED_TIME, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
  P.displayZoneText(0, szMesg, PA_CENTER, frameDelay, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
  P.displayZoneText(1, szDate, PA_CENTER, 0, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
  P.displayZoneText(2, szTemp, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);
  P.displayZoneText(3, szTime, PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);


#if USE_12H
  RTC.control(DS3231_CLOCK_HALT, DS3231_OFF);
  RTC.control(DS3231_12H, DS3231_ON); // DS3231_ON is for 12H
#endif

#if !USE_12H
  RTC.control(DS3231_CLOCK_HALT, DS3231_OFF);
  RTC.control(DS3231_12H, DS3231_OFF); // DS3231_ON is for 12H
#endif

  //pinMode(ROTARY_BUTTON, INPUT_PULLUP); // KY-040 rotary does not have internal pullup resistor hence use Arduino pullup resistor.

  getTime(szTime);

  beep(1, SysFreq); // Buzzer to indicate the system is started
  //digitalWrite(ENABLE_DISPLAY, HIGH);
  //Serial.println ("Setup ends");
}
//Setup ends

//Loop
void loop(void)
{
  static uint32_t lastTime = 0;   // millis() memory
  static uint8_t  display = 0;    // current display mode
  //static uint8_t  Temp.display = 0;
  static bool flasher = false;  // seconds passing flasher

  doUI();

  P.displayAnimate();

  P.getZoneStatus(2);
 
   // P.setTextEffect(2, PA_NO_EFFECT, PA_DISSOLVE);
    if (DHT11.read(DHT11_PIN) == 0)
    {
      dtostrf(DHT11.temperature, 3, 0, szTemp);
      //strcat(szTemp, "°");
      strcat(szTemp, "°");
      
      Serial.println("szTemp1");
    }
  P.displayReset(2);
 
  
  //strcpy(szTemp, "");
  P.displayAnimate();
  
  P.getZoneStatus(2);
  {
  //P.setTextEffect(2, PA_DISSOLVE, PA_NO_EFFECT);
    
        if (DHT11.read(DHT11_PIN) == 0)
        {
          dtostrf(DHT11.humidity, 3, 0, szTemp);
          strcat(szMesg, "%");
          
          Serial.println("szTemp2");
        }
    P.displayReset(2);    
  }
  
   //strcpy(szTemp, "");
  
   P.displayAnimate();
  P.getZoneStatus(1);
  {
    //P.setTextEffect(1, PA_OPENING, PA_NO_EFFECT);
    dow2str(RTC.dow, szDate, 18);
    
    Serial.println("szDate1");
    P.displayReset(1);
  }

 //strcpy(szDate, "");
 P.displayAnimate();
  P.getZoneStatus(1);
  {
    //P.setTextEffect(1, PA_OPENING, PA_NO_EFFECT);
    getDate(szDate);
    
    Serial.println("szDate2");
 P.displayReset(1);
  }
 
//strcpy(szDate, "");
P.displayAnimate();
  P.getZoneStatus(0);
  {
    //P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
    if (FIRSTRUN && count <= 9)
    {
      //P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
      //display = 0;
      strcpy(szMesg, curMessage);
      strcpy_P(curMessage, (char*)pgm_read_word(&(string_table[count]))); // Necessary casts and dereferencing, just copy.
      //Serial.println(curMessage);
      //Serial.println (count);
      //Serial.println(FIRSTRUN);
      count++;
      strcpy(szMesg, "");
      Serial.println("szMesg");
    }
    //strcpy(szMesg, "");
    else
    {
      count = 0;
      strcpy(szMesg, "");
    }
    //strcpy(szMesg, "");

    if (!FIRSTRUN)

    //P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
    //display = 0;
    strcpy(szMesg, curMessage);
    P.displayReset(0);

  }

  P.displayReset();


  // Read and process serial input received data if available.
  while (Serial3.available())

  {
    serialMessage[putIndex] = (char)Serial3.read();
    if ((serialMessage[putIndex] == '\n') || (putIndex >= MAX_MESG - 2)) // end of message character or full buffer
    {
      // put in a message separator and end the string
      serialMessage[putIndex] = '\0';
      // restart the index for next filling spree and flag we have a message waiting
      putIndex = 0;
      strcpy (curMessage, serialMessage);
      FIRSTRUN = false;

    }
    else
    {
      // Just save the next char in next location
      serialMessage[putIndex++];
    }
    //FIRSTRUN = false;
  }

  // Finally, adjust the time string if we have to

  if (millis() - lastTime >= 1000)
  {
    lastTime = millis();
    getTime(szTime, flasher);
    flasher = !flasher;
    P.displayReset(3);
  }

Is this all the code? Have you tried to compile this? There are several definitions (ex MAX_DEVICES) missing and some global variables as well.

I would also suggest that you may be better off starting from a working example program and move gradually to your setup. There is a similar clock/temp/RH display in the Parola examples folder.

Additional resources for information:

  • There is extensive documentation for the Parola library. I would encourage you to read that.
  • There is a series of blog articles at my blog site (link below). All the relevant articles start with "Parola A to Z"
  • As mentioned, there are a lot of examples to look at. Key is to understand what each one does and why. The documentation and blog will help here.
    There is a lot to learn but adopting gradual changes from a working base will allow you to ensure that the last change made is what broke the software. This is far easier to deal with that a big bang approach.

Always ready to help you if you need it, just come back to this thread.

Thanks a lot for your reply Marco. Your seamless support is appreciated.

As per your guidance, i have reworked the code for Zone1, 2 and 3. and it is working perfect. (Zone 0 is yet to be coded). Have used most of the codes from the Parola_Zone_TimeMsg example.

Interesting things..

1, Temperature reading used to start at 25-26 degree C and gradually increased to 30 degree while the actual temperature is 25-26 degree. Found the root cause at the DHT11 module with the power LED which was near the DHT11 sensor ( as LED light up and in a few seconds the heat dissipation making the DHT11 reading increase as well). I am yet to code for the alternate display of Temperature / Humidity in Zone2

2, A cold start shows scrambled characters and the Arduino not start (can make out with the beep in the setup function as it never reaches). System starts and display works with the reset button pressed once, though the intensity of the LED are more ( not as per setup function - 0) - a second reset of the board clears this. I am using an adequate 3Amp power supply.

My future plans are...

1, Incorporate an LDR to auto adjust the brightness of display.
2, Incorporate a IR to control the device.
3, Incorporate a motion sensor to control the display ( no motion for 30 minutes switch off the display)
4, A Bluetooth that can take serial data and scroll in the Zone0 ( Zone0 normally scrolls the default text in sequence till a text entry from the serial port - Bluetooth.
5, A rotary encoder to adjust the scroll speed of Zone0. The same Rotary can be used for settings menu ( Adjust Time, date etc. Set and save user input display brightness and scroll speed to EEPROM. - This is already there in the code.

Earlier posted code was not complete as it was giving 9000 character limit error, hence i have attached the complete code

Font_Data.h (5.1 KB)

Parola_Binny_MegaV1.0.ino (7.02 KB)

Yup, that looks a whole lot better than the first lot of code.

I have got a Bluetooth example (recently completed) that you can look at for that part of the project if you are interested.

Good luck and fun with the rest of the project.

Thank you so much for the support. Since my plan is to read data from the Bluetooth through the serial port, I have used code from one of your project to do that (while serial available.....). Its working fantastic. of course, your sample sketches has a lot of codes that can be reused.

I would request if you can help me with code for rotary encoder (though i already have one in the sketch) to control the scroll speed (my encoder is 20 steps) and a menu using rotary encoder to change the settings like brightness, Speed, Set clock & Date etc.

Not sure what you mean by 20 steps for the rotary encoder. The digital encoders usually just provide you with clicks that you count. See this blog article on making it more responsive Adaptive User Input with a Rotary Encoder – Arduino++

You need to decide how you will display the menu. Are you going to use the LED Matrix? In that case you will need to start thinking about how you will manage going from 'normal' display to menu system and vice versa (ie, change mode) and how the menu will work with the user.

By 20 steps, i mean 20 clicks (Detents) sorry for the confusion :slight_smile:
Thanks for the reference link. Is it possible to use that code in my situation ( controlling speed and menu's)?

You read my mind.. I plan to use the Zone0 of LED display for the Menu.

Menu is like...

Settings - Adjust time (Hour, Minutes, Seconds) Date
Adjust date (Year, month date. DoW)

Set Alarms -
Which Alarm (Alarm1 or Alarm 2?)
Adjust Hour, Minutes,
Type ( Off, Daily, Weekday, Weekend, Once)

Display brightness - 0 to 15.

Scroll Speed - 0 - 100

Save - Save the settings to EEPROM.

The push button on the Rotary encoder (KY-040) will be used to save/accept the changes while turn left/right used as the menu selection.

Is it possible to use that code in my situation ( controlling speed and menu's)?

Maybe. You will find that when you need to scroll though a large number (eg 0 to 1000) incrementing by 1 will be very tedious, so using some sort of accelerator makes sense. If you were changing scrolling Speed and Pause values (in milliseconds), they include a large number range. 'List' type menu options are usually just selected on the direction of the scroll (up/down or left/right).

The top level of your menu is probably a list selection and then I would probably create a one-way menu (press selects the value and move to the next option). Keeps it simple and you can easily keep track of what you are doing with a 'state' variable (ie, 0 is no menu, 1 is the speed, 2 is the next thing, 3 etc). Then select based on that what message you print and what value is updated internally.

In any event you should probably look up Finite State Machines if you have not already done so. This will help to plan structure the code.

I have done some update to your MD_REncoder with ISR which i intent to use in the project.
Thank you for providing the link and hint.

I need help with the menu code or a link to it which helps me build the rest of it.

MD_REncoder_Interrupt_MEGA.ino (1022 Bytes)

Menu only needs a simple display, so I would write small function that just prints a string (similar to the print() method). Use sprintf() to create the string to print. This keeps it straightforward.

Menu code will end up looking something like this:

switch (menustate)
{
case 0: 
  if Rotaryencoder press then menustate = whatever the next menu state is
  if Rotaryencoder clicks then 
  {
    change the value being set up
    print() the prompt and the current value as one string
  }
case 1:
  // same stuff for another value
case 2:
  // same stuff again
etc.
}

Another option is just to find a menu library that you like and use that. There are lots around as it seems something that gets reinvented many times.

Marco, I have completed the Zone0 as well. Few problems i face and look forward for help...

1, Time (Zone3) flasher is dependent on the Zone0 scroll speed ie, if the scroll speed is slow, the flasher is also slow. When increase scroll speed, flasher works fine.

2, When adjusting the scroll speed (zone0) effect is not immediate it takes the next scroll to speed up.

Code is attached, can you please help out..

Font_Data.h (5.1 KB)

Parola_Binny_MegaV1.0.ino (7.46 KB)

1, Time (Zone3) flasher is dependent on the Zone0 scroll speed ie, if the scroll speed is slow, the flasher is also slow. When increase scroll speed, flasher works fine.

    P.setSpeed(speed);
    P.setPause(speed); // Need to check this line

You are setting the speed for the whole display. You need to set it for the zone only. Also, don't change pause unless you really mean to. The pause is the time the message is displayed between the in and out phase of the animation. It is usually not directly related to speed.

2, When adjusting the scroll speed (zone0) effect is not immediate it takes the next scroll to speed up.

That's how you have coded it. doUI() is only called when all the animations are complete. If you want immediate effect, move the function call outside the "if displayAnimate()" statement and inside loop(). Normally it is the first or last thing called in loop().

I had to restructure the code to work with the zones. Thank you so much for the pointers, Marco. That helped a lot understanding the program structure and the Parola library. I , now have working display with all the zone animation as needed.

The project continues to the next level - the settings menu's and DS3231 set time etc. Will be needing your suggestions for the same.

Hello Marco, quite a time i couldn't continue the project due to some personal incidents of losing couple of souls.
I am slowly recovering and starting back this project. I am very success in implementing a four zone display as per the initial plan but unable to get to the code for setting the clock using the <MD_DS3231.h> library.

Could you please help me with a code for this. Sorry for the bother.

Example code in the library uses DS1307. That will work with DS3231.

Could you please help with a code that test all the LED (like spiral example in the MD_MAX72xx_Test.ino)

void spiral()
// setPoint() used to draw a spiral across the whole display
{
PRINTS("\nSpiral in");
int rmin = 0, rmax = ROW_SIZE-1;
int cmin = 0, cmax = (COL_SIZE*MAX_DEVICES)-1;

mx.clear();
while ((rmax > rmin) && (cmax > cmin))
{
// do row
for (int i=cmin; i<=cmax; i++)
{
mx.setPoint(rmin, i, true);
delay(DELAYTIME/MAX_DEVICES);
}
rmin++;

// do column
for (uint8_t i=rmin; i<=rmax; i++)
{
mx.setPoint(i, cmax, true);
delay(DELAYTIME/MAX_DEVICES);
}
cmax--;

// do row
for (int i=cmax; i>=cmin; i--)
{
mx.setPoint(rmax, i, true);
delay(DELAYTIME/MAX_DEVICES);
}
rmax--;

// do column
for (uint8_t i=rmax; i>=rmin; i--)
{
mx.setPoint(i, cmin, true);
delay(DELAYTIME/MAX_DEVICES);
}
cmin++;
}
}

The display is 64Width*32Height and would like to use Parola library (Not MD_MAX72xx)

Parola does not do graphics as part of the library. If you are confident to modify the library you can do it yourself. See the main Parola forum thread around post #1157.

I am NOT confident modifying the library! I would rather use MD_MAX72xx_ library :wink:

Could you suggest the code modification for the Spiral function for 64Width*32Height display.

  int  rmin = 0, rmax = ROW_SIZE-1;
  int  cmin = 0, cmax = (COL_SIZE*MAX_DEVICES)-1;

These set the boundary limits of the animation.

If you are going across more than one row of LED matrices you will need to make your own adjustments.

You may also want to consider a different library that allows you to use the LED matrices as a panel. I have seen one but cannot remember what it is called.

While i enjoy this library and the recent update, i have a question again - is it possible to run this library in PCDUINO and/or Arduino Yun?