I'm trying to display the readings from a DHT11 onto an LED Matrix. I can get the basic display to work, the issue is when I also put the time on the display. I started with the Morphing Clock as a base for the time then used the Adafruit Sensor code to read the DHT11. The issue seems to be with"
timerAlarmWrite(timer, 2000, true);
Which is setup to call:
void IRAM_ATTR display_updater(){
// Increment the counter and set the time of ISR
portENTER_CRITICAL_ISR(&timerMux);
display.display(10);
portEXIT_CRITICAL_ISR(&timerMux);
}
If I slow the timer down I can get readings from the DHT11 but the morphing time display doesn't update enough to look fluid. I'm new to coding for these devices so I'm not sure where I should be looking to move these things out of each others way. Here is the full app if the timer is set to something above 25000 you will get temp results most of the time, but the less are dimmer and the colons flash (they shouldn't).
#define double_buffer
#include <PxMatrix.h>
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "Digit.h"
#include <Adafruit_Sensor.h>
#include <DHT.h>
const char* ssid = "Gallifrey";
const char* password = "ThisIsAGoodPlaceToPutAPassword!";
// ESP32 Pins for LED MATRIX
#define P_LAT 22
#define P_A 19
#define P_B 23
#define P_C 18
#define P_D 5
#define P_E 15 // NOT USED for 1/16 scan
#define P_OE 2
hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
PxMATRIX display(64,32,P_LAT, P_OE,P_A,P_B,P_C,P_D,P_E);
void IRAM_ATTR display_updater(){
// Increment the counter and set the time of ISR
portENTER_CRITICAL_ISR(&timerMux);
display.display(10);
portEXIT_CRITICAL_ISR(&timerMux);
}
// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);
// Variables to save date and time
String formattedDate;
String dayStamp;
String timeStamp;
unsigned long prevEpoch;
byte prevhh;
byte prevmm;
byte prevss;
//====== Digits =======
Digit digit0(&display, 0, 63 - 1 - 9*1, 17, display.color565(0, 250, 0));
Digit digit1(&display, 0, 63 - 1 - 9*2, 17, display.color565(0, 250, 0));
Digit digit2(&display, 0, 63 - 4 - 9*3, 17, display.color565(0, 250, 0));
Digit digit3(&display, 0, 63 - 4 - 9*4, 17, display.color565(0, 250, 0));
Digit digit4(&display, 0, 63 - 7 - 9*5, 17, display.color565(0, 250, 0));
Digit digit5(&display, 0, 63 - 7 - 9*6, 17, display.color565(0, 250, 0));
#define DHTPIN 27
#define DHTTYPE DHT11
//DHT_Unified dht(DHTPIN, DHTTYPE);
DHT dht(DHTPIN, DHTTYPE);
//DHT dht;
const uint32_t delayMS = 6000;
uint32_t lastRead;
void setup() {
display.begin(16); // 1/16 scan
display.setFastUpdate(true);
// Initialize Serial Monitor
Serial.begin(115200);
pinMode(DHTPIN, INPUT_PULLUP);
dht.begin();
// // Set delay between sensor readings based on sensor details.
lastRead = 0;
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
timer = timerBegin(0, 80, true);
timerAttachInterrupt(timer, &display_updater, true);
timerAlarmWrite(timer, 1500, true); /// The Problem is Here!!!???!!!!?
timerAlarmEnable(timer);
display.fillScreen(display.color565(0, 0, 0));
digit1.DrawColon(display.color565(100, 175, 0));
digit3.DrawColon(display.color565(100, 175, 0));
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Initialize a NTPClient to get time
timeClient.begin();
timeClient.setTimeOffset(-28800);
}
void loop() {
while(!timeClient.update()) {
timeClient.forceUpdate();
}
formattedDate = timeClient.getFormattedDate();
// Extract date
int splitT = formattedDate.indexOf("T");
dayStamp = formattedDate.substring(0, splitT);
// Extract time
timeStamp = formattedDate.substring(splitT+1, formattedDate.length()-1);
displayLocalTemp();
updateTimeDisplay();
}
String readDHTTemperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// Read temperature as Celsius (the default)
float t = dht.readTemperature(true);
// Read temperature as Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(t);
return String(t);
}
}
String readDHTHumidity() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(h);
return String(h);
}
}
void displayLocalTemp() {
uint32_t currentTime = millis();
uint32_t waited = currentTime - lastRead;
static String lastTemp;
static String lastHumid;
if (waited > delayMS) {
lastRead = currentTime;
String temp = readDHTTemperature();
String humidity = readDHTHumidity();
String preTemp = "T:";
String preHumidity = "H:";
String tempDisplay = preTemp + temp;
String humidDisplay = preHumidity + humidity;
Serial.print("temp: ");
Serial.print(temp);
Serial.print(" -- humidity: ");
Serial.println(humidity);
display.setTextColor(display.color565(0,0,0));
display.setCursor(20,16);
display.print(lastTemp);
display.setCursor(20,25);
display.print(lastHumid);
display.setTextColor(display.color565(0,255,0));
display.setCursor(20,16);
display.print(tempDisplay);
display.setCursor(20,25);
display.print(humidDisplay);
lastTemp = tempDisplay;
lastHumid = humidDisplay;
}
}
void updateTimeDisplay() {
unsigned long epoch = timeClient.getEpochTime();
if (epoch != prevEpoch) {
int hh = timeClient.getHours();
int mm = timeClient.getMinutes();
int ss = timeClient.getSeconds();
if (hh > 12) hh = hh % 12;
if (prevEpoch == 0) { // If we didn't have a previous time. Just draw it without morphing.
digit0.Draw(ss % 10);
digit1.Draw(ss / 10);
digit2.Draw(mm % 10);
digit3.Draw(mm / 10);
digit4.Draw(hh % 10);
digit5.Draw(hh / 10);
}
else
{
// epoch changes every miliseconds, we only want to draw when digits actually change.
if (ss!=prevss) {
int s0 = ss % 10;
int s1 = ss / 10;
if (s0!=digit0.Value()) digit0.Morph(s0);
if (s1!=digit1.Value()) digit1.Morph(s1);
//ntpClient.PrintTime();
prevss = ss;
}
if (mm!=prevmm) {
int m0 = mm % 10;
int m1 = mm / 10;
if (m0!=digit2.Value()) digit2.Morph(m0);
if (m1!=digit3.Value()) digit3.Morph(m1);
prevmm = mm;
}
if (hh!=prevhh) {
int h0 = hh % 10;
int h1 = hh / 10;
if (h0!=digit4.Value()) digit4.Morph(h0);
if (h1!=digit5.Value()) digit5.Morph(h1);
prevhh = hh;
}
}
prevEpoch = epoch;
}
}
You could try to assign tasks explicitly to a core.
When you start playing with ESP32 multi core code execution be aware of the following issues:
For implementation purposes, you need to take in consideration that FreeRTOS priorities are assigned from 0 to N, where lower numbers correspond to lower priorities. So, the lowest priority is 0.
First of all, declare a global variable that will contain the number of the core where the FreeRTOS task to launch will be pinned
static int taskCore = 0; // The core the task should run on
now create the assignment of a task to the core in Setup()
xTaskCreatePinnedToCore(
myCoreTask, /* Function to implement the task */
"myCoreTask", /* Name of the task */
10000, /* Stack size in words */
NULL, /* Task input parameter */
0, /* Priority of the task */
NULL, /* Task handle. */
taskCore); /* Core where the task should run */
Here is a test function which you call in loop()
void myCoreTask( void * pvParameters ){
while(true){
Serial.println("Task running on core ");
Serial.print(xPortGetCoreID());
// This is here to show that other tasks run
// NEVER use in production
delay(1000);
}
}
Hope this gives you an idea how to tackle your problem, read more here RTOS and here ESP32-IDF