Go Down

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

Nope! 'char' is not to be used at all, the correct form is

sprintf(message, "TEMP: %s%cF  RH: %s%%", 247, f_temp, h_temp);

(CHAR)247 or (char)247 is WRONG, printf with the %c is expecting a numeric value

probably you'd want to add a

#define DG 247

and than do

sprintf(message, "TEMP: %s%cF  RH: %s%%", DG, f_temp, h_temp);
--
You never learn anything by doing it right.

ScottJ2505

Hi Marco_c,
I was finally able to find my post and your reply. 
I will look into what you have suggested.
Thank you!
Scott

ScottJ2505

Hi Marco_C,
The code works great!  Thank you for the assistance.
Scott

Nealix

Ah, thank you.
So if I understand you correctly;

The library font table shows; 
5, 0x06, 0x0f, 0x09, 0x0f, 0x06,  // 247 - 'Degree'
for the degree symbol.  So is that CHAR 247 for degree symbol?

So would I change my existng line;

       sprintf(message, "TEMP: %s F  RH: %s%%", f_temp, h_temp);

into this new line;

       sprintf(message, "TEMP: %s%cF  RH: %s%%", (char)247, f_temp, h_temp);
     
Am I on the right track?

Cheers

@Marco:   If I use;

                sprintf(message, "TEMP: %s%cF  RH: %s%%", (char)247, f_temp, h_temp);

the program does not crash, but instead of temperature degrees F, it prints;

"TEMP: !=F"  where the "=" is actually three horizontal bars.   Not sure I understand
what to do next?


@Ocsav:   If I use your suggestion;

              sprintf(message, "TEMP: %s%cF  RH: %s%%", 247, f_temp, h_temp);

the program prints a corrupted string that looks like a wild pointer to some other buffer,
crashes, and resets the Arduino.  Do we perhaps need a null terminator after the 247?

I read about the %c, but I am puzzled as to what I may be doing wrong?
Any ideas on how to proceed?   Eager to learn.
Is 247 perhaps the wrong value for the degree symbol?
I may be misunderstanding the standard font table in the cpp source file?

Neal

Nealix

I think I found the solution, but I don't understand why?
As in my previous post, the two proposed solutions using %c and a value
like (char)247, or just 247, do not work.

But simply using the \xF7 hexadecimal format as part of the text string,
without a variable or value after, DOES work.   This format works;

        sprintf(message, "TEMP: %s\xF7 F  RH: %s%%", f_temp, h_temp);

And it prints out like;    TEMP: 71° F   RH: 52%
on the matrix display.  I found this in the following post, reply #14;

      https://forum.arduino.cc/index.php?topic=389248.msg2685482#msg2685482

Apparently, the space is needed between the hex code \xF7 for the degree symbol,
and the "F" for Fahrenheit, but the post does not explain why?
Is there a way around having that space after degree and before "F" ?

It sure is hard to find any tutorial or usage lookup info on Arduino sprintf,
especially with regard to %c escapes.  I don't know why that is, since
Arduino is aimed at beginners like me :-)

Cheers,

Neal
       

marco_c

Quote
Apparently, the space is needed between the hex code \xF7 for the degree symbol,
and the "F" for Fahrenheit, but the post does not explain why?
Because the number \xF7F is a valid hexadecimal number. The escape sequence stops when the character is not a valid hex character. You could try the format string "\xf7%c" and then put the 'F' in the parameters to be printed. This may work as the the % is not a hex digit, part of the escape sequence.

Quote
It sure is hard to find any tutorial or usage lookup info on Arduino sprintf,
especially with regard to %c escapes.
Because it is not specific to Arduino and is part of the C/C++ specification.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

@Ocsav:   If I use your suggestion;

              sprintf(message, "TEMP: %s%cF  RH: %s%%", 247, f_temp, h_temp);

the program prints a corrupted string that looks like a wild pointer to some other buffer,
crashes, and resets the Arduino.  Do we perhaps need a null terminator after the 247?

I read about the %c, but I am puzzled as to what I may be doing wrong?
Any ideas on how to proceed?   Eager to learn.
Is 247 perhaps the wrong value for the degree symbol?
I may be misunderstanding the standard font table in the cpp source file?

Neal
The problem with the printf family is that the number and type of tokens (the %s or %c or %d) inside the string *MUST* match the number of parameters after the string, what you paste above is wrong because
Code: [Select]
             sprintf(message, "TEMP: %s%cF  RH: %s%%", 247, f_temp, h_temp);

You have the tokens string, char, string, but you have the parameters char, string, string, you must have


Code: [Select]
             sprintf(message, "TEMP: %s%cF  RH: %s%%", f_temp, 247, h_temp);

In a way it's easier to learn C on an operating system like linux where this kind of mistake almost always produce a memory error, in the Arduino you can do a lot of useful programming without really understanding what you're doing.


--
You never learn anything by doing it right.

Jmeredith

@marco_c or anyone,  I am still trying to get my weather display LED matrix to scroll... If I just run the basic code it scrolls, however when I try to use it with the weather.gov json parser that I made. I get the data retuned but cant get it to scroll.  any ideas?

here is the code:

Code: [Select]
/**
NOAA forcast for San Antonio using JSON data from https://api.weather.gov
to parse datasets use http://json.parser.online.fr/
*/
#include <ArduinoJson.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 12
#define DATA_PIN  D7
#define CS_PIN    D8
#define CLK_PIN   D5


// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

const uint8_t SPEED_DEADBAND = 5;
uint8_t scrollSpeed = 25;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 2000; // in milliseconds

// Global message buffers shared by Serial and Scrolling functions
#define  BUF_SIZE  200
char curMessage[BUF_SIZE] = { "" };
char newMessage[BUF_SIZE] = { "Test" };
bool newMessageAvailable = true;

// Current fingerprint for https://api.weather.gov
const uint8_t fingerprint[20] = {0x1C, 0xE6, 0x10, 0xE0, 0x6D, 0x39, 0x26, 0x74, 0xEE, 0x44, 0x3A, 0x46, 0x9B, 0x44, 0x99, 0x77, 0xAC, 0xA3, 0xD4, 0x72};

ESP8266WiFiMulti WiFiMulti;

void setup() {

  Serial.begin(115200);
  //Turn LED Matrix On
  P.begin();
  P.print("Turn LED Matrix: ON");
  Serial.println();
  Serial.println();
  Serial.println();

  for (uint8_t t = 4; t > 0; t--) {
    Serial.printf("[SETUP] WAIT %d...\n", t);
    Serial.flush();
    delay(1000);
  }
  Serial.println("[WiFi] Set Mode -> Station");
  WiFi.mode(WIFI_STA);
  Serial.println("[WiFi] Mode = Station");
  WiFiMulti.addAP("----SSID----", "----KEY----");
  Serial.println("[WiFi] Send authentication data...");
}
void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {
    Serial.println("[WiFi] connected!");
    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
    client->setFingerprint(fingerprint);
    HTTPClient https;
    Serial.print("[HTTPS] begin...\n");
    if (https.begin(*client, "https://forecast.weather.gov/MapClick.php?lat=29.584&lon=-98.553&FcstType=json")) {
      Serial.print("[HTTPS] GET...\n");
      int httpCode = https.GET();
      if (httpCode > 0) {
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
      //pass GET results to doc
      //Serial.println(https.getString());
      String payload = https.getString();
      //print payload
      //Serial.print("Print payload: ");
      //Serial.println(payload);
      // assign memory pool expression based on https://arduinojson.org/v6/assistant/
      const size_t capacity = 2*JSON_ARRAY_SIZE(0) + 8*JSON_ARRAY_SIZE(13) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(11) + JSON_OBJECT_SIZE(12) + JSON_OBJECT_SIZE(20);
      //print the capacity
      //Serial.printf("[JSON] capacity: %d\n" , capacity);
      // set the capacity of 'doc'
      DynamicJsonDocument doc(capacity+4000); //add in extra bytes for string duplication
      //Deserialize the payload
      //deserializeJson(doc, payload);
      DeserializationError error = deserializeJson(doc, payload);
      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      } 
      Serial.println();
      //Serial.print("Weather for ");
      //Serial.print(doc["periods"][0].as<char*>());
      //Serial.print(": "); 
      Serial.println();
      //Current period and forcast
      Serial.print(doc["time"]["startPeriodName"][0].as<char*>());
      Serial.print(", ");
      Serial.print(doc["data"]["text"][0].as<char*>());
      //Next period and forcast
      Serial.print(doc["time"]["startPeriodName"][1].as<char*>());
      Serial.print(", ");
      Serial.print(doc["data"]["text"][1].as<char*>());
      Serial.print(" As of: ");
      Serial.print(doc["creationDateLocal"].as<char*>());
     
      // Try to make sprintf work with JSON data...
      Serial.println("\n\n Result of buffer print");
      //char CurrentPeriodBuffer[800];  //used in ealier test
      strcpy(newMessage, doc["time"]["startPeriodName"][0].as<char*>());
      strcat(newMessage, ", ");
      strcpy(newMessage + strlen(newMessage), doc["data"]["text"][0].as<char*>());
      Serial.println(newMessage);
      //P.print(newMessage);
      if (P.displayAnimate())
        {
          if (newMessageAvailable)
          {
          strcpy(curMessage, newMessage);
          newMessageAvailable = false;
          }
       P.displayReset();
        }
         
       }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }
 
      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }
  Serial.println("\n\n Wait 1hour before next round...");
  delay(3600000);
}

marco_c

I may be missing it in your code, but nowhere do you set up the animation parameters. Without the setup on the buffer to show, speed, animation type, etc, the P.animate() won't know what to do and P.displayReset() resets to unknown. Look at the example code. the animation is usually set up in the setup() function.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Jmeredith

Isnt that here:

Code: [Select]
const uint8_t SPEED_DEADBAND = 5;
uint8_t scrollSpeed = 25;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 2000; // in milliseconds

marco_c

No, you need to pass these into the library using a method call, not just define them in your code.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Jmeredith

you mean this part:

Code: [Select]
P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);

marco_c

Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Jmeredith

yeah I have that up in the setup...  still no joy

Code: [Select]
/**
NOAA forcast for San Antonio using JSON data from https://api.weather.gov
to see parsed datasets you can use http://json.parser.online.fr/
and paste the JSON data from the weather.gov API
*/
#include <ArduinoJson.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClientSecureBearSSL.h>
#include <MD_Parola.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 12
#define DATA_PIN  D7
#define CS_PIN    D8
#define CLK_PIN   D5

// Hardware SPI connection
MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

uint8_t scrollSpeed = 25;    // default frame delay value
textEffect_t scrollEffect = PA_SCROLL_LEFT;
textPosition_t scrollAlign = PA_LEFT;
uint16_t scrollPause = 0; // in milliseconds

// Global message buffers shared by Serial and Scrolling functions
#define  BUF_SIZE  250
char curMessage[BUF_SIZE] = { "Getting WX Data . . ." };
char newMessage[BUF_SIZE] = { "This should be the lastest weather forecast" };
bool newMessageAvailable = false;

// Current fingerprint for https://api.weather.gov
const uint8_t fingerprint[20] = {0x1C, 0xE6, 0x10, 0xE0, 0x6D, 0x39, 0x26, 0x74, 0xEE, 0x44, 0x3A, 0x46, 0x9B, 0x44, 0x99, 0x77, 0xAC, 0xA3, 0xD4, 0x72};

ESP8266WiFiMulti WiFiMulti;

void setup() {

  Serial.begin(115200);
  //Turn LED Matrix On
  P.begin();
  //make LED Matrix say Getting WX Data... (curMessage)
  P.displayText(curMessage, scrollAlign, scrollSpeed, scrollPause, scrollEffect, scrollEffect);
  Serial.println();
  Serial.println();
  Serial.println();

  for (uint8_t t = 4; t > 0; t--) {
    Serial.printf("[SETUP] WAIT %d...\n", t);
    Serial.flush();
    delay(1000);
  }
  Serial.println("[WiFi] Set Mode -> Station");
  WiFi.mode(WIFI_STA);
  Serial.println("[WiFi] Mode = Station");
  WiFiMulti.addAP("----SSID----", "----KEY----");
  Serial.println("[WiFi] Send authentication data...");
}
void loop() {
  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {
    Serial.println("[WiFi] connected!");
    std::unique_ptr<BearSSL::WiFiClientSecure>client(new BearSSL::WiFiClientSecure);
    client->setFingerprint(fingerprint);
    HTTPClient https;
    Serial.print("[HTTPS] begin...\n");
    if (https.begin(*client, "https://forecast.weather.gov/MapClick.php?lat=29.584&lon=-98.553&FcstType=json")) {
      Serial.print("[HTTPS] GET...\n");
      int httpCode = https.GET();
      if (httpCode > 0) {
        Serial.printf("[HTTPS] GET... code: %d\n", httpCode);
    if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
      //pass GET results to doc
      //Serial.println(https.getString());
      String payload = https.getString();
      //newMessageAvailable = true;
      //print payloa
      //Serial.print("Print payload: ");
      //Serial.println(payload);
      // assign memory pool expression based on https://arduinojson.org/v6/assistant/
      const size_t capacity = 2*JSON_ARRAY_SIZE(0) + 8*JSON_ARRAY_SIZE(13) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(7) + JSON_OBJECT_SIZE(11) + JSON_OBJECT_SIZE(12) + JSON_OBJECT_SIZE(20);
      //print the capacity
      //Serial.printf("[JSON] capacity: %d\n" , capacity);
      // set the capacity of 'doc'
      DynamicJsonDocument doc(capacity+4000); //add in extra bytes for string duplication
      //Deserialize the payload
      //deserializeJson(doc, payload);
      DeserializationError error = deserializeJson(doc, payload);
      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
        return;
      } 
      Serial.println();
      //Serial.print("Weather for ");
      //Serial.print(doc["periods"][0].as<char*>());
      //Serial.print(": "); 
      Serial.println();
      //Current period and forcast
      Serial.print(doc["time"]["startPeriodName"][0].as<char*>());
      Serial.print(", ");
      Serial.print(doc["data"]["text"][0].as<char*>());
      //Next period and forcast
      Serial.print(doc["time"]["startPeriodName"][1].as<char*>());
      Serial.print(", ");
      Serial.print(doc["data"]["text"][1].as<char*>());
      Serial.print(" As of: ");
      Serial.print(doc["creationDateLocal"].as<char*>());
     
      // Try to make sprintf work with JSON data...
      Serial.println("\n\nResult of buffer print");
      //char CurrentPeriodBuffer[800];  //used in ealier test
      strcpy(newMessage, doc["time"]["startPeriodName"][0].as<char*>());
      strcat(newMessage, ", ");
      strcpy(newMessage + strlen(newMessage), doc["data"]["text"][0].as<char*>());
      strcat(newMessage, " ");
      strcpy(newMessage + strlen(newMessage), doc["time"]["startPeriodName"][1].as<char*>());
      strcat(newMessage, ", ");
      strcpy(newMessage + strlen(newMessage), doc["data"]["text"][1].as<char*>());
      strcat(newMessage, "As of: ");
      strcpy(newMessage + strlen(newMessage), doc["creationDateLocal"].as<char*>());
      Serial.println(newMessage);
      //P.print(newMessage);
      if (P.displayAnimate())
        {
          if (newMessageAvailable)
          {
          strcpy(curMessage, newMessage);
          newMessageAvailable = false;
          }
       P.displayReset();
        }
         
       }
      } else {
        Serial.printf("[HTTPS] GET... failed, error: %s\n", https.errorToString(httpCode).c_str());
      }
 
      https.end();
    } else {
      Serial.printf("[HTTPS] Unable to connect\n");
    }
  }
  Serial.println("\n\n Wait 1hour before next round...");
  delay(3600000);
}

marco_c

(1) you animate only when the link is connected (it is within the if statement). It should run every time loop() runs - pull it out and put it either at the start or end of loop().

(2)
Code: [Select]
  Serial.println("\n\n Wait 1hour before next round...");
  delay(3600000);

also means that the next step in the animation will take place in an hour. Is this what you want?

You cannot block the execution of loop() as nothing will run while the processor twiddles its thumbs in a busy loop. You should understand how BlinkWithoutDelay() works and restructure your code accordingly. delay() is generally a bad idea and should be avoided if you want responsive code.

Your next problem, btw, will be that your new message is not updated when you have one.
Arduino Libraries https://github.com/MajicDesigns?tab=Repositories
Parola for Arduino https://github.com/MajicDesigns/Parola
Arduino++ blog https://arduinoplusplus.wordpress.com

Go Up