Go Down

Topic: LED matrix display - MD_Parola, MD_MAX72xx and MD_MAXPanel (Read 651439 times) previous topic - next topic

kwolf1909

Hello Marco,

I have an application which requires switching between using one and two zones dynamically. It seems that this works, but I found that the behaviour of the displayAnimate() function seems to be unspecific when switching back to one zone, due to the fact that the result of this function always refers to both zones.
Actually I solved this by defining a "hidden" module (one module more than physically available) which is just used to hide the unused zone when the whole display uses just one zone.
Question: Is this the right way handling this szenario? And does the library support switching between different number of zones dynamically?
Also it would be a great improvement if the boundaries between zones must not match physical modules rather than more flexible pixel positions over the whole display width.

Many regards Klaus

marco_c

The library supports dynamic zones - one of the example is for this.

However, if you declare that you need 2 zones when you begin Parola then you will always operate as 2 zones, even if one of them is not used. The use case of not having modules for a zone is not one I considered - if your approach works then that is fine by me. Just be aware that the library will be trying to send data to his phantom module so it is slightly affecting performance, but it should be unnoticeable.

As for the zone/module boundaries there are many things that can't be arbitrary (module intensity, module shutdown, etc) because they depend on the hardware, so for consistency throughout the library everything sits on module boundaries.

kwolf1909

#1697
Dec 31, 2020, 11:42 am Last Edit: Dec 31, 2020, 11:59 am by kwolf1909
Using a dummy module to hide an unused zone works fine for me. I didn't try to specify a zone with identical start- and end-module-number (i.e. no modules), maybe this works too. But then, I assume the result of displayAnimate() will be unspecific.
Another question: Using the function displayZoneText() with effect-parameters PA_PRINT, PA_NO_EFFECT requires at least one call to displayAnimate(), is that true? Because there ist no "animation" at all.
Sometimes it would be useful to call displayAnimate() with a zone-identifier to have more control which zone is animated.

marco_c

Quote
Using the function displayZoneText() with effect-parameters PA_PRINT, PA_NO_EFFECT requires at least one call to displayAnimate(), is that true? Because there ist no "animation" at all.
There is animation. The call to displayZoneText() only sets up the parameters for the zone display. The animation is ALWAYS done by animate(), even if for print this is a single cycle (it has to 'appear'). The print() method has the animate() call built in but is limited to a single zone display as it is included to support the standard Arduino output stream and there is no way to specify a zone from in that stream.


Quote
Sometimes it would be useful to call displayAnimate() with a zone-identifier to have more control which zone is animated.
If that is what you need then you should be able to make the zone animation method public so you can call it directly. In thousands of downloads of the library this is the first time this has been seen as a need, but feel free to change your copy of the library to suit.

ton4eff

Hello, I'm trying to use DHT22 sensor with Parola, added 3 sec delay to read from the sensor (according to the DHT22 pdf the minimum is 2 sec). I want to show the temperature and humidity sensor readings consequently on the LED matrix, but it shows only the humidity and I don't know why… :smiley-confuse:


Code: [Select]
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#include "DHT.h"
#define DHTPIN 2

#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

// 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
#define MAX_MESG  20
// HARDWARE SPI
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
// SOFTWARE SPI
//MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
uint8_t scrollSpeed = 15;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_CENTER;
uint16_t scrollPause = 3000; // in milliseconds
char szMesg[MAX_MESG + 1] = "";

uint8_t degC[] = { 6, 3, 3, 56, 68, 68, 68 }; // Deg C


unsigned long previousMillis = 0;   // will store last time DHT was updated
const long interval = 3000;         // Updates DHT readings every 3 seconds

float t = 0.0;
float h = 0.0;   // current temperature & humidity, updated in loop()

void setup()
{
  dht.begin();
  Serial.begin(115200);
  P.begin();
  P.displayText(szMesg, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);

  P.addChar('$', degC);
}

void loop() {

  static uint8_t  display = 0;  // current display mode
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    // Read temperature as Celsius (the default)
    float newT = dht.readTemperature();
    if (isnan(newT)) {
      Serial.println("Failed to read from DHT sensor!");
    }
    else {
      t = newT;
      Serial.print(t, 1);
      Serial.print("°C  ");
    }
    // Read Humidity
    float newH = dht.readHumidity();
    // if humidity read failed, don't change h value
    if (isnan(newH)) {
      Serial.println("Failed to read from DHT sensor!");
    }
    else {
      h = newH;
      Serial.print(h, 1);
      Serial.println("%");
    }
  }

  switch (display)
  {
    case 0: // Temperature deg C
      dtostrf(h, 3, 0, szMesg);
      strcat(szMesg, " %");
      break;

    case 1: // Relative Humidity %
      dtostrf(t, 3, 1, szMesg);
      strcat(szMesg, " $");
      break;
  }


  if (P.displayAnimate())
  {
    P.displayReset();
  }

}






marco_c

There is no way that it will switch between the temperature and humidity as the display variable never changes value. According to this code, it will always just show temperature. When you do a displayReset() is a good time to change the message
Code: [Select]

  if (P.displayAnimate())
  {
    display = (display + 1) % 2;
    switch (display)
    {
      case 0: // Temperature deg C
        dtostrf(h, 3, 0, szMesg);
        strcat(szMesg, " %");
        break;

      case 1: // Relative Humidity %
        dtostrf(t, 3, 1, szMesg);
        strcat(szMesg, " $");
        break;
    }

    P.displayReset();
  }

ton4eff

Thank you Marco! It works fine now:

Code: [Select]
static uint8_t  display = 0;  // current display mode
  if (P.displayAnimate()) {

    switch (display)
    {
      case 0:
        //P.setTextEffect(0, PA_SCROLL_DOWN, PA_SCROLL_DOWN);
        display++;
        dtostrf(h, 3, 0, szMesg);
        strcat(szMesg, " %");
        break;

      case 1:
        //P.setTextEffect(0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
        display = 0;
        dtostrf(t, 3, 1, szMesg);
        strcat(szMesg, " $");
        break;

    }
    P.displayReset();
  }

dj_janker_

Hi, I'm using this code for monitoring Bitcoin price, but the scrolling effect is too slow. Could you help me to get more speed, please?

Code: [Select]
//PARTE BITCOIN TICKER
#include <Arduino.h>

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>

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

const uint16_t WAIT_TIME = 1000;

// 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   D5
#define DATA_PIN  D7
#define CS_PIN    D2
#define MAX_MESG  20
// 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);
const char* ssid = "xx";
const char* password = "xx";
const char* host = "api.coindesk.com";

float previousValue = 0.00;
float threshold = 0.05;
// SOFTWARE SPI
//MD_Parola P = MD_Parola(HARDWARE_TYPE, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);




uint8_t scrollSpeed = 10;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 1000; // in milliseconds
char szMesg[MAX_MESG + 1] = "";




void setup()
{
  pinMode(D3, OUTPUT); //Price down
  pinMode(D4, OUTPUT); //Price up
 
 
  Serial.begin(115200);               
  delay(10);

  WiFi.begin(ssid, password);

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  P.begin();
  P.displayText(szMesg, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);

//  P.addChar('$', degC);
}

void loop() {

  // Connect to API
  Serial.print("connecting to ");
  Serial.println(host);
 
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }
 
  // We now create a URI for the request
  String url = "/v1/bpi/currentprice.json";
 
  Serial.print("Requesting URL: ");
  Serial.println(url);
 
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Connection: close\r\n\r\n");
  delay(500); //geändert von 100
 
  // Read all the lines of the reply from server and print them to Serial
  String answer;
  while(client.available()){
    String line = client.readStringUntil('\r');
    answer += line;
  }

  client.stop();
  Serial.println();
  Serial.println("closing connection");

  // Process answer
  Serial.println();
  Serial.println("Answer: ");
  Serial.println(answer);

  // Convert to JSON
  String jsonAnswer;
  int jsonIndex;

  for (int i = 0; i < answer.length(); i++) {
    if (answer[i] == '{') {
      jsonIndex = i;
      break;
    }
  }

  // Get JSON data
  jsonAnswer = answer.substring(jsonIndex);
  Serial.println();
  Serial.println("JSON answer: ");
  Serial.println(jsonAnswer);
  jsonAnswer.trim();

  // Get rate as float
  int rateIndex = jsonAnswer.indexOf("rate_float");
  String priceString = jsonAnswer.substring(rateIndex + 12, rateIndex + 18);
  priceString.trim();
  float price = priceString.toFloat();

  // Print price
  Serial.println();
  Serial.println("Bitcoin price: ");
  Serial.println(price);
   

   
      dtostrf(price, 3, 0, szMesg);
      strcat(szMesg, " $");
 



  if (P.displayAnimate())
  {
    P.displayReset();
  }

}


marco_c

You cannot have delay() in your loop() or any code that is called from your loop() because it blocks everything else from running.

You need to call the displayAnimate() function many times (really, every time through loop()) while you want the animation to happen as it checks the timer to see if it needs to move anything. This is covered in this blog article https://arduinoplusplus.wordpress.com/2020/08/29/parola-a-to-z-frequently-asked-issues/.

To code your application, you will need to change your application coding style to be more aligned to Finite State Machine principles (see this other blog for an explanation https://arduinoplusplus.wordpress.com/2019/07/06/finite-state-machine-programming-basics-part-1/ or many other sources online).

Go Up