Need help with DMD display

I am doing a project where Arduino mega dos some calculation work and sends the data to UNO via serial(115200) and the UNO is inturn expected to scroll the received text on DMD display(1X4).

Here is the code part of mega which generates the message to be sent on serial to UNO

void DmD()
{
    DateTime now = rtc.now();
  int dai = now.day();
  int mon = now.month();
  int yr = now.year();
  int hr = now.hour();
  int minit = now.minute();
  
  sprintf(scrollingtext, "<%d/%d %d:%d Total Feedback:%d Air:%d Toilet:%d Service:%d Total Avg:%d Air:%d Toilet:%d Service:%d >" , dai,mon,hr,minit,TotalFB,TotalAirFB,TotalToiletFB,TotalServiceFB,total_avg,Air_avg,toilet_avg,service_avg);
 }

I am not posting the entire code since the word limit doesn't allow more charachters

The code at UNo which receives the message and expected it to scroll on DMD is

#include <SPI.h>        //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
#include <DMD.h>        
#include <TimerOne.h>   
#include "SystemFont5x7.h"
#include "Arial_black_16.h"

//Fire up the DMD library as dmd
#define DISPLAYS_ACROSS 4
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);

const byte numChars = 100;
char receivedChars[numChars];

boolean newData = false;

void ScanDMD()
{ 
  dmd.scanDisplayBySPI();
}

void setup()
{
    //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
   Timer1.initialize( 5000 );           //period in microseconds to call ScanDMD. Anything longer than 5000 (5s) and you can see flicker.
   Timer1.attachInterrupt( ScanDMD );   //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()
  
   //clear/init the DMD pixels held in RAM
   dmd.clearScreen( true );   //true is normal (all pixels off), false is negative (all pixels on)
   Serial.begin(115200);

   Serial.println("<Arduino is ready>");
}

void loop()
{
    recvWithStartEndMarkers();
    showNewData();
    DmD();
}

void recvWithStartEndMarkers()
{
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
 
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() 
{
    if (newData == true) 
    {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}


void DmD()
{
  if (newData == true)
  {
    dmd.selectFont(Arial_Black_16);
   //displays the message
   dmd.drawMarquee(receivedChars ,200,(32*DISPLAYS_ACROSS)-1 ,0);
   long start=millis();
   long timer=start;
   boolean ret=false;
   while(!ret)
   {
     if ((timer+30) < millis()) {
       ret=dmd.stepMarquee(-1,0);
       timer=millis();
     }
   }
  }
}

So here's the two problems m facing

  1. whenever the function DMD is enabled the function ShowNewData doesn't show up in the serial monitor. And if the DmD function is disabled then ShowNewData hows up in the serial monitor(Although this doesn't really matter to me, But m just wondering why this happens)

  2. The DMD dispaly only scrolls text till "Service:" parameter (rest " total avg: air, toilet and service" parameters doesn't show up on DmD)

What changes do I need to make either in the mega code or UNO code? I am really stuck on this thing from past two weeks and not able to get the reason why this is happening. Any help, suggestion would be really appreciated. Thanks in advance

A couple of things.

Inside ShowNewData() you print the new data and then set newData to false.

Inside DmD(), you check if newData is true (which it is not) and then display something.

Your whole DmD() function shouldn't step through all the marquees and then return, it should just do one step and then return so your main code has time to check for new data, etc.

You also need to make your time variables unsigned long (not long) and never compare a future time (timer+30) vs. the current time - it will eventually roll over and break your code. The only safe operation is subtracting current time from some past start time to get an elapsed time and compare that to how long you wanted to wait.

something like this...

#include <SPI.h>        //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
#include <DMD.h>
#include <TimerOne.h>
#include "SystemFont5x7.h"
#include "Arial_black_16.h"

//Fire up the DMD library as dmd
#define DISPLAYS_ACROSS 4
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);

const byte numChars = 100;
char receivedChars[numChars];

boolean newData = false;

void ScanDMD()
{
  dmd.scanDisplayBySPI();
}

void setup()
{
  //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
  Timer1.initialize( 5000 );           //period in microseconds to call ScanDMD. Anything longer than 5000 (5s) and you can see flicker.
  Timer1.attachInterrupt( ScanDMD );   //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()

  //clear/init the DMD pixels held in RAM
  dmd.clearScreen( true );   //true is normal (all pixels off), false is negative (all pixels on)
  Serial.begin(115200);
  while ( !Serial );

  Serial.println("<Arduino is ready>");
}

void loop()
{
  recvWithStartEndMarkers();
  showNewData();
  DmD();
  if ( newData ) newData = false;
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData()
{
  if (newData == true)
  {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
  }
}


void DmD()
{
  static unsigned long start = 0;
  const unsigned long duration = 30;  // ms

  if (newData == true)
  {
    dmd.selectFont(Arial_Black_16);
    //displays the message
    dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
    start = millis();
  }

  if ( start && millis() - start >= duration ) {
    start = millis();
    if ( dmd.stepMarquee(-1, 0) == true ) {
      start = 0;  // done scrolling
    }
  }
}

blh64:
A couple of things.

Inside ShowNewData() you print the new data and then set newData to false.

Inside DmD(), you check if newData is true (which it is not) and then display something.

Your whole DmD() function shouldn't step through all the marquees and then return, it should just do one step and then return so your main code has time to check for new data, etc.

You also need to make your time variables unsigned long (not long) and never compare a future time (timer+30) vs. the current time - it will eventually roll over and break your code. The only safe operation is subtracting current time from some past start time to get an elapsed time and compare that to how long you wanted to wait.

something like this...

#include <SPI.h>        //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)

#include <DMD.h>
#include <TimerOne.h>
#include "SystemFont5x7.h"
#include "Arial_black_16.h"

//Fire up the DMD library as dmd
#define DISPLAYS_ACROSS 4
#define DISPLAYS_DOWN 1
DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);

const byte numChars = 100;
char receivedChars[numChars];

boolean newData = false;

void ScanDMD()
{
  dmd.scanDisplayBySPI();
}

void setup()
{
  //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
  Timer1.initialize( 5000 );          //period in microseconds to call ScanDMD. Anything longer than 5000 (5s) and you can see flicker.
  Timer1.attachInterrupt( ScanDMD );  //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()

//clear/init the DMD pixels held in RAM
  dmd.clearScreen( true );  //true is normal (all pixels off), false is negative (all pixels on)
  Serial.begin(115200);
  while ( !Serial );

Serial.println("");
}

void loop()
{
  recvWithStartEndMarkers();
  showNewData();
  DmD();
  if ( newData ) newData = false;
}

void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData()
{
  if (newData == true)
  {
    Serial.print("This just in ... ");
    Serial.println(receivedChars);
  }
}

void DmD()
{
  static unsigned long start = 0;
  const unsigned long duration = 30;  // ms

if (newData == true)
  {
    dmd.selectFont(Arial_Black_16);
    //displays the message
    dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
    start = millis();
  }

if ( start && millis() - start >= duration ) {
    start = millis();
    if ( dmd.stepMarquee(-1, 0) == true ) {
      start = 0;  // done scrolling
    }
  }
}

blh64 so far so good thanks for taking time and replying me your help has been a life saver. There are still some problems I am facing. I tried uploading th code you suggested.

During first run everything goes well but during second time when the mega sends data something really weird scrolls on DMD like there are spelling mistakes and missing letters also even after the complete sentence has been scrolled up there comes some characters like ? ! > " & % and some numbers 2 6....followed by again the last segment of sentence like "otal Avg:3 Air:"...."3 oilet:".....so on...
Also I need to keep scrolling the previously received message till the new ones arrives. What changes do I need to make?

Whats going wrong in there can you assist me further, I would be really greatful to have your help since m stuck here from past few weeks and have tried everything i could but not able to figure it out. I am not that good wiith arduino programing tho. Please help me ahead

You code calls drawMarquee() with a char length of 200 so it is scrolling all 200 characters (even garbage beyond the end of your string).

You should chance that value to the actual length of the string. I'll leave that as an exercise for the reader :slight_smile:

blh64:
You code calls drawMarquee() with a char length of 200 so it is scrolling all 200 characters (even garbage beyond the end of your string).

You should chance that value to the actual length of the string. I'll leave that as an exercise for the reader :slight_smile:

I figured out where the problem was. First I tried to reduce the charchter size to exactly fit the incoming message and then lowered the baud rate to 9600 hich solved my problem.

Still one thing left to be sorted, I need that the received msg keeps on continously scrolling on the DMD until new one is received. How do I do that? please help me with that. I tried removing the boolean newData but then the whole code stops working. What should be the alternative method to do that?

Well, if you want it to keep scrolling, you can't stop, you have to cycle back around and call drawMarque() again.

blh64:
Well, if you want it to keep scrolling, you can't stop, you have to cycle back around and call drawMarque() again.

Should it be something like this???

  #include <SPI.h>        //SPI.h must be included as DMD is written by SPI (the IDE complains otherwise)
  #include <DMD.h>
  #include <TimerOne.h>
  #include "SystemFont5x7.h"
  #include "Arial_black_16.h"
  
  //Fire up the DMD library as dmd
  #define DISPLAYS_ACROSS 4
  #define DISPLAYS_DOWN 1
  DMD dmd(DISPLAYS_ACROSS, DISPLAYS_DOWN);
  
  const byte numChars = 200;
  char receivedChars[numChars];
  
  boolean newData = false;
  
  void ScanDMD()
  {
    dmd.scanDisplayBySPI();
  }
  
  void setup()
  {
    //initialize TimerOne's interrupt/CPU usage used to scan and refresh the display
    Timer1.initialize( 5000 );           //period in microseconds to call ScanDMD. Anything longer than 5000 (5s) and you can see flicker.
    Timer1.attachInterrupt( ScanDMD );   //attach the Timer1 interrupt to ScanDMD which goes to dmd.scanDisplayBySPI()
  
    //clear/init the DMD pixels held in RAM
    dmd.clearScreen( true );   //true is normal (all pixels off), false is negative (all pixels on)
    Serial.begin(9600);
    while ( !Serial );
  
    Serial.println("<Arduino is ready>");
  }
  
  void loop()
  {
    recvWithStartEndMarkers();
    showNewData();
    DmD();
    if ( newData ) newData = false;
      dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
      start = millis();
       if ( start && millis() - start >= duration ) {
      start = millis();
      if ( dmd.stepMarquee(-1, 0) == true ) {
        start = 0;  // done scrolling

  }
  
  void recvWithStartEndMarkers()
  {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
  
    while (Serial.available() > 0 && newData == false) {
      rc = Serial.read();
  
      if (recvInProgress == true) {
        if (rc != endMarker) {
          receivedChars[ndx] = rc;
          ndx++;
          if (ndx >= numChars) {
            ndx = numChars - 1;
          }
        }
        else {
          receivedChars[ndx] = '\0'; // terminate the string
          recvInProgress = false;
          ndx = 0;
          newData = true;
        }
      }
  
      else if (rc == startMarker) {
        recvInProgress = true;
      }
    }
  }
  
  void showNewData()
  {
    if (newData == true)
    {
      Serial.print("This just in ... ");
      Serial.println(receivedChars);
    }
  }
  
  
  void DmD()
  {
    static unsigned long start = 0;
    const unsigned long duration = 30;  // ms
  
    if (newData == true)
    {
      dmd.selectFont(Arial_Black_16);
      //displays the message
      dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
      start = millis();
    }
  
    if ( start && millis() - start >= duration ) {
      start = millis();
      if ( dmd.stepMarquee(-1, 0) == true ) {
        start = 0;  // done scrolling
      }
    }
  }

but if I do this then DMD doesn't scroll anything but just two of the LEDs in starting row are lit and nothing else happens

Dude, that code doesn't even compile. Did you try it?

You need another state variable inside your DMD() function to signal the restart.

void DmD()
{
  static unsigned long start = 0;
  const unsigned long duration = 30;  // ms
  static bool restart = false;

  if (newData == true or restart == true)
  {
    dmd.selectFont(Arial_Black_16);
    //displays the message
    dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
    start = millis();
    restart = false;
  }

  if ( start && millis() - start >= duration ) {
    start = millis();
    if ( dmd.stepMarquee(-1, 0) == true ) {
      //start = 0;  // done scrolling
      restart = true;
    }
  }
}

How did you connect the Uno to the Mega.
The Mega has three spare serial ports, but the Uno has not.
I hope you don't use pin 0,1 on the Uno (or on the Mega), because that is already used by the USB<>Serial chip.
I don't see any SoftwareSerial calls on different pins either in your code.
And if it did, that wouldn't work on 11500baud.
Leo..

Wawa:
How did you connect the Uno to the Mega.
The Mega has three spare serial ports, but the Uno has not.
I hope you don't use pin 0,1 on the Uno (or on the Mega), because that is already used by the USB<>Serial chip.
I don't see any SoftwareSerial calls on different pins either in your code.
And if it did, that wouldn't work on 11500baud.
Leo..

Yes I use 0 and 1 ports but the UNO is not connected to my computer it is powered from external supply

blh64:
Dude, that code doesn't even compile. Did you try it?

You need another state variable inside your DMD() function to signal the restart.

void DmD()

{
  static unsigned long start = 0;
  const unsigned long duration = 30;  // ms
  static bool restart = false;

if (newData == true or restart == true)
  {
    dmd.selectFont(Arial_Black_16);
    //displays the message
    dmd.drawMarquee(receivedChars , 200, (32 * DISPLAYS_ACROSS) - 1 , 0);
    start = millis();
    restart = false;
  }

if ( start && millis() - start >= duration ) {
    start = millis();
    if ( dmd.stepMarquee(-1, 0) == true ) {
      //start = 0;  // done scrolling
      restart = true;
    }
  }
}

Sorry for very very late reply.....

I was going thru some ups and downs so it took time for me to get back to this project but as soon as I tried your code!!!!!

IT WORKED LIKE WONDERS!!!! U R TRULY BEEN A LIFE SAVER FOR ME!!!!!HEARTIEST THANKS!!!!

is this code working now???