Go Down

Topic: Scrolling LED matrix display - Parola for Arduino (Read 430278 times) previous topic - next topic

marco_c

1. Make sure you are running the latest version of the libraries.
2. Make sure your power supply is adequate. You cannot run this many modules from the USB power supply.
3. With a separate power supply, make sure the ground for all the power supplies and the Arduino board are connected together.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

marco_c

#1306
Jun 09, 2018, 11:18 pm Last Edit: Jun 11, 2018, 12:47 am by marco_c
NEW VERSION ANNOUNCEMENT

There is a major new version of MD_Parola and MD_MAX72XX released. Both are now version 3.0.0.

The changes to MD_Parola are because of the changes to MD_MAX72XX, so both need to be upgraded in this cycle.

There are a number of changes to MD_MAX72XX:

  • Setting module hardware type is now done at run time. There is no longer the need to edit the header files, but all applications using the library must add in the hardware type to the object constructor. THIS WILL BREAK ALL EXISTING CODE until the small change is made to the object initialization. All the examples for MD_MAX72XX and MD_Parola have been updated to use the new format.
  • Graphics routines in MD_MAX72XX have been moved to a new library called MD_MAXPanel. MD_MAXPanel supports an x*y array of MAX72xx LED modules and manages it like a pixel addressable display. Any code that used the line() and rectangle() methods in MD_MAX72XX will now need to use MD_MAXPanel instead. This new library will provide scope for additional future functionality without bloating the size MD_MAX72XX. MD_MAXPanel requires MD_MAX72XX version 3.0.0 or greater.
  • A new font file format has been implemented. Existing font files will work as-is but the new format has additional information as part of the font definition that helps in managing the fonts. The change is described in the library documentation.

As usual, please report any issues so they can be fixed.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

  • Setting module hardware type is now done at run time. There is no longer the need to edit the header files any more but all applications using the library must add in the hardware type to the object constructor. THIS WILL BREAK ALL EXISTING CODE until the small change is made to the object initialization. All the examples in MD_MAX72XX and MD_Parola have been updated to use the new format.

:) thank you!
--
You never learn anything by doing it right.

CTB

#1308
Jun 19, 2018, 11:33 am Last Edit: Jun 19, 2018, 11:38 am by CTB
First off, thank you Marco for the amazing library you created. For many of us newbies your code is extremely helpful as I am sure it is for more experienced users.

What I am trying to do is create a simple NTP clock that will display the weekday, date and time on a 64x8 MAX7219 screen (2 joined 32x8 screens) by using a Wemos D1 Mini v3.

I found a sketch online that does exactly that, but it uses a scroll effect to update the screen, which I want to change to a different effect. Then I found your MD Parola library which has an effect that I want to use (PA_OPENING_CURSOR). As a side note, I am using the latest MD_Parola and MD_MAX72xx libraries.

The result I want to get is:
- display the weekday
- switch (with the PA_OPENING_CURSOR effect) to the date
- switch (with the PA_OPENING_CURSOR effect again) to the time
- repeat

By making use of the initial sketch and merging it with the Parola library examples, I've managed to reach to the sketch below (altered from the originals and heavily commented so that I can better understand the code and every step taken - newbie alert) but I've reached to a standstill as I don't know how to pass the required variables to the code that creates the swithcing effect. As you can see, the sketch currently displays the weekday/date/time (Monday/17 Jan 2345/21:59) but their values are only hard-coded (static), so they are not pulled up from the NTP server. The serial monitor shows me that the time/date are pulled from the NTP server correctly.

Could you please guide me on how to achieve this?

(The code is in the post right below as I reached the limit of 9000 characters so I had to split in two posts)

CTB

Here's the code I have so far:

Code: [Select]


// Program to demonstrate the MD_Parola library
//
// For every string defined by pc[] iterate through all combinations
// of entry and exit effects.
//
// Animation speed can be controlled using a pot on pin SPEED_IN
//
// MD_MAX72XX library can be found at https://github.com/MajicDesigns/MD_MAX72XX
//


/*
NTP CLOCK and DATE Scroller
*/


//___________________________________________________________LIBRARIES USED
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>
#include <TimeLib.h>

//___________________________________________________________PINS DEFINITIONS
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CLK_PIN   D5 // or SCK
#define DATA_PIN  D7 // or MOSI
#define CS_PIN    D4 // or SS

//___________________________________________________________ARBITRARY PINS DEFINITIONS
MD_Parola p = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);


//___________________________________________________________USER CONTROL (POTENTIOMETER)
#define USE_UI_CONTROL 0 // set to 1 if we are implementing the user interface pot

#if USE_UI_CONTROL
#define SPEED_IN  A0
uint8_t frameDelay = 25;  // default frame delay value
#endif

//___________________________________________________________SPEED DEFINITION
#define SPEED_TIME  25  // Lower number means faster speed
#define PAUSE_TIME  2000

//___________________________________________________________DEBUGGING
#define  DEBUG  1 // Change to 1/0 to turn on/off debug statements to the serial output

#if  DEBUG
#define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
#define PRINTS(x) Serial.print(F(x))
#define PRINTX(x) Serial.println(x, HEX)
#else
#define PRINT(s, x)
#define PRINTS(x)
#define PRINTX(x)
#endif

//___________________________________________________________WEB SERVER SETUP
ESP8266WebServer server(80);
const char ssid[] = "My_SSID_here";  //  your network SSID (name)
const char pass[] = "My_Password_here";       // your network password

//___________________________________________________________NTP SERVER and TIMEZONE
static const char ntpServerName[] = "3.uk.pool.ntp.org";
const float timeZone = 1.0;     // UK Standard Time

WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets
time_t getNtpTime();
void sendNTPpacket(IPAddress &address);
static boolean isLongFormat = false;

String myTime;
String myDate;

//___________________________________________________________TIME AND DATE FUNCTION
void timeDisplay() {
  // Populate myTime String
  myTime = hour();

  if (hour() < 10) {
    myTime = "0" + myTime;
  }

  if (minute() < 10) {
    myTime = myTime + " : 0" + minute();
  }
  else {
    myTime = myTime + " : " + minute();
  }

  myTime = (" " + myTime + " ");
  PRINT("\nMyTime: ", myTime);

  int myTime_len = myTime.length() + 1;
  char myTime_charArray[myTime_len];
  myTime.toCharArray(myTime_charArray, myTime_len);

  PRINT("\nMyTime_charArray: ", myTime_charArray );

}

void dateDisplay() {
  // Populate myDate String
  myDate = myDate + "  " + day() + " " + monthShortStr(month()) + " " + year() ;
  myDate = (" " + myDate + " ");
  PRINT("\nMyDate: " , myDate);


  // covert from string/float to char array
  int myDate_len = myDate.length() + 1;
  char myDate_charArray[myDate_len];
  myDate.toCharArray(myDate_charArray, myDate_len);

  PRINT("\nMyDate_charArray: ", myDate_charArray);

}

//___________________________________________________________DEFINE THE TEXT TO DISPLAY
// Global variables
uint8_t  curText;
char  *pc[] =
{
  "Monday",
  "17 Jan 2345",
  "21 : 59",
  
};

//___________________________________________________________DEFINE THE TEXT EFFECT
uint8_t  inFX, outFX;
textEffect_t  effect[] =
{
  PA_OPENING_CURSOR,
};

//___________________________________________________________USER CONTROL ACTIONS (IF USED)
#if USE_UI_CONTROL
void doUI(void)
{
  // set the speed if it has changed
  {
    int16_t speed = map(analogRead(SPEED_IN), 0, 1023, 0, 250);

    if (speed != (int16_t)p.getSpeed())
    {
      p.setSpeed(speed);
      p.setPause(speed);
      frameDelay = speed;
      PRINT("\nChanged speed to ", p.getSpeed());
    }
  }
}
#endif // USE_UI_CONTROL

//___________________________________________________________void setup
void setup()
{
  p.begin();

#if  DEBUG
  Serial.begin(115200);
  delay(1000);
#endif

  Serial.begin(115200);
  PRINTS("\nLet's see if this thing will EVER work...");
  PRINTS("\n ");
  delay(1000);

  PRINT("\nConnecting to the WiFi Network named > ", ssid);

  WiFi.begin(ssid, pass);
  delay(1000);

  PRINTS("\n ");
  PRINTS("\nConnection established successfully");
  PRINTS("\n ");
  PRINT("\nThe IP address assigned to your device by your WiFi router is ", WiFi.localIP());
  PRINTS("\n ");
  PRINTS("\nStarting UDP...");
  PRINTS("\n ");
  Udp.begin(localPort);
  PRINT("\nLocal port: ", Udp.localPort());
  PRINTS("\n ");
  PRINTS("\nWaiting for synchronisation...");
  PRINTS("\n ");
  PRINTS("\n ");
  setSyncProvider(getNtpTime);
  setSyncInterval(120);  // NTP re-sync interval in seconds

#if USE_UI_CONTROL
  pinMode(SPEED_IN, INPUT);
  doUI();
#endif // USE_UI_CONTROL

  p.begin();
  p.setInvert(false);
  p.displayText(pc[curText], PA_CENTER, SPEED_TIME, PAUSE_TIME, effect[inFX], effect[outFX]);

}

//___________________________________________________________NTP CODE
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  IPAddress ntpServerIP; // NTP server's ip address

  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Serial.println("Transmited request to the NTP server:");
  WiFi.hostByName(ntpServerName, ntpServerIP);
  Serial.print(" "); Serial.print(ntpServerName);
  Serial.print(": ");
  Serial.println(ntpServerIP);
  sendNTPpacket(ntpServerIP);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Serial.println(" ");
      Serial.println("The NTP server responded successfully");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 30;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}


//___________________________________________________________void loop
void loop()
{

#if  DEBUG
#define PRINT(s, x) { Serial.print(F(s)); Serial.print(x); }
#define PRINTS(x) Serial.print(F(x))
#define PRINTD(x) Serial.println(x, DEC)

#else
#define PRINT(s, x)
#define PRINTS(x)
#define PRINTD(x)

#endif


#if USE_UI_CONTROL
  doUI();
#endif // USE_UI_CONTROL

  if (p.displayAnimate()) // animates and returns true when an animation is completed
  {
    // Set the display for the next string.
    curText = (++curText) % ARRAY_SIZE(pc);
    p.setTextBuffer(pc[curText]);

    // When we have gone back to the first string, set a new exit effect
    // and when we have done all those set a new entry effect.
    if (curText == 0)
    {
      outFX = (++outFX) % ARRAY_SIZE(effect);
      if (outFX == 0)
        p.setTextEffect(effect[inFX], effect[outFX]);
    }

    // Tell Parola we have a new animation
    p.displayReset();
  }
}

marco_c

You can attach large sketches as an attachment to the post.

I am guessing that if you look up the sprintf() function you will find what you need to format a new message.
Don't use the array of messages but just one string buffer where you change the message every iteration.
I would also ditch Strings in favor of char arrays to avoid potential memory leakage problems.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

CTB

Thank you Marco.

I hope it isn't too much to ask, but could you please show an example of how you would use a string buffer?
I am very new to this and don't quite understand how to do it.

marco_c

Plenty of stuff out there on standard C strings that will explain better than I can. Google C strings.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Very very very basic usage, might be enough for you, I didn't check your code

Code: [Select]

char buffer[32];
int a=10;
int b=20;

sprintf(buffer, "a is %d and b is %d", a, b);

/this loads into char array buffer the string "a is 10 and b is 20"


Note that the size you assign to the buffer is important, if your sprintf generates more that 31 (yes 31, sprintf adds a NULL ascii (zero) to the end of the string) chars your code or variables can become corrupt.
Note that the arduino *printf functions don't handle floats, you'll need to use ftoa(), look it up with google.
--
You never learn anything by doing it right.

CTB

That's great, thank you ocsav and Marco for your time and help

PriSim

Hello marco_c,


I hope you doing fine.
First of all hats off and Thanks for your work regarding MAX7219 and Dotmatrix.

Recently i was working with Parola v2.0, I convert my old code to new with some function name changes etc, it worked.

One year ago , when i left working with parola library was lag in seconds display on dotmtrix, Problem is same for today. I simulate the code , and checked it with hardware too. It always give some seconds lag while displaying.

Removed and rearranged whole code only to show the time , but problem is still there.
Please have a look into code and guide me whats wrong.
Here is the code, need simulation file please let me know i will upload it.

Code: [Select]


#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <MD_DS1307.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::ICSTATION_HW
#define  MAX_DEVICES 5
#define CLK_PIN   11
#define DATA_PIN  12
#define CS_PIN    10



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

#define BUF_SIZE  100
char curMessage[BUF_SIZE];
char  szTime[9];
char  szwelcome[9];


void getwelcome(char *psz, bool f = true)
{
 sprintf(psz, "%c%c%c%c%c%c%c", 'W','e','l','c','o','m','e');
}

void getTime(char *psz, bool f = true)
// Code for reading clock time
{
RTC.readTime();
  P.setTextAlignment(PA_LEFT);
  sprintf(psz, "%c%01d%c%c%02d%c%c%02d",' ', (RTC.h%12),':',':', RTC.m,':',':',RTC.s);
 
}

void setup(void)
{
  P.begin();
  P.setInvert(false);
RTC.readTime();
   P.displayText(szwelcome, PA_CENTER, 50, 1500, PA_PRINT, PA_NO_EFFECT);
   RTC.control(DS1307_CLOCK_HALT, DS1307_OFF);
   RTC.control(DS1307_12H, DS1307_OFF);

getwelcome(szwelcome);
 
}

void loop(void)
{
RTC.readTime();

  if (P.displayAnimate()){
  P.setIntensity(8);
  getTime(szTime);
 
    P.setTextEffect(PA_PRINT, PA_NO_EFFECT);
 
    P.setTextBuffer(szTime);
   P.displayReset();
 
}
 
  }


marco_c

To be clear did you actually run this on hardware or was it just simulation?
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

marco_c

#1317
Jun 28, 2018, 08:46 am Last Edit: Jun 28, 2018, 08:47 am by marco_c
This
Code: [Select]
char  szTime[9];
is incompatible with this
Code: [Select]
sprintf(psz, "%c%01d%c%c%02d%c%c%02d",' ', (RTC.h%12),':',':', RTC.m,':',':',RTC.s);
The string you get out (" 9::99::99") has 10 characters and your buffer is 9 long. This is likely to cause problems as you overrun the buffer with 11 characters (10+nul). In any case h%12 will be 2 digit for 10 and 11 o'clock.

Also, your constructs are a bit strange. I would write the code like this (untested):
Code: [Select]

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <MD_DS1307.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::ICSTATION_HW
#define  MAX_DEVICES 5
#define CLK_PIN   11
#define DATA_PIN  12
#define CS_PIN    10

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

#define BUF_SIZE  100
char curMessage[BUF_SIZE] = "Welcome";

void getTime(char *psz)
// Code for reading clock time
{
  RTC.readTime();
  sprintf(psz, " %02d::%02d::%02d", (RTC.h%12), RTC.m, RTC.s);
}

void setup(void)
{
  P.begin();
  P.setIntensity(8);
  P.displayText(szBuf, PA_CENTER, 50, 1500, PA_PRINT, PA_NO_EFFECT);
  RTC.control(DS1307_CLOCK_HALT, DS1307_OFF);
  RTC.control(DS1307_12H, DS1307_OFF);
  RTC.readTime();
}

void loop(void)
{
  if (P.displayAnimate())
  {
    getTime(szBuf);
    P.displayReset();
  }
}
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

PriSim

To be clear did you actually run this on hardware or was it just simulation?
Yes i tested it on proper hardware ! will uploaded a video if you say so.


Code: [Select]

#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <MD_DS1307.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::ICSTATION_HW
#define  MAX_DEVICES 5
#define CLK_PIN   11
#define DATA_PIN  12
#define CS_PIN    10

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

#define BUF_SIZE  100
char curMessage[BUF_SIZE] = "Welcome";
char  szBuf[9];

void getTime(char *psz)
// Code for reading clock time
{
  RTC.readTime();
  sprintf(psz, " %01d::%02d::%02d", (RTC.h%12), RTC.m, RTC.s);
}

void setup(void)
{
  P.begin();
  P.setIntensity(8);
  P.displayText(szBuf, PA_CENTER, 50, 1500, PA_PRINT, PA_NO_EFFECT);
  RTC.control(DS1307_CLOCK_HALT, DS1307_OFF);
  RTC.control(DS1307_12H, DS1307_OFF);
  RTC.readTime();
}

void loop(void)
{
  if (P.displayAnimate())
  {
    getTime(szBuf);
    P.displayReset();
  }
}


Tested this code as per your recommendation, Same results. Also tried to increase Buffer size in my code,Same issue.

marco_c

Do you understand that the second number parameter here (1500)
Code: [Select]
P.displayText(szBuf, PA_CENTER, 50, 1500, PA_PRINT, PA_NO_EFFECT);
is the delay between the end of PA_PRINT and PA_NO_EFFECT?
If you are trying to update a clock every second then having a 1.5 second delay before the animation is finished does not seem like a good idea.
You should probably just use the .print() method for Parola and then update it again after you have detected that 1000ms have passed (like in blink without delay).
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Go Up