尝试在 ESP32 板上使用 DHT11 和 PxMatrix 显示器

Trying to use DHT11 with a PxMatrix display on ESP32 board

我正在尝试将 DHT11 的读数显示到 LED 矩阵上。我可以让基本显示正常工作,问题是我还把时间显示在显示器上。我当时以 Morphing Clock 作为基础,然后使用 Adafruit 传感器代码读取 DHT11。问题似乎出在

timerAlarmWrite(timer, 2000, true);

设置调用:

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);
}

如果我减慢计时器速度,我可以从 DHT11 获得读数,但变形时间显示更新不够流畅,看起来不流畅。我是这些设备的新手,所以我不确定我应该在哪里寻找将这些东西移开的地方。这是完整的应用程序,如果计时器设置为高于 25000 的值,大部分时间你会得到临时结果,但越少越暗,冒号闪烁(它们不应该)。

#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;
  }

}

您可以尝试将任务明确分配给核心。
开始玩ESP32多核代码执行时注意以下问题:

  • 设置和主循环函数都以优先级 1 执行。
  • 核心 1 上的 Arduino 主循环 运行s。
  • 执行是固定的,所以预计内核不会在程序执行过程中发生变化
  • 在 FreeRTOS(底层 OS)上,任务具有分配的优先级,调度程序使用该优先级来决定哪个任务将 运行。
  • 准备好运行的高优先级任务将优先于低优先级任务,这意味着只要高优先级任务可以运行,低优先级任务就不会CPU.
  • 注意 Serial 等共享资源可能是潜在问题。由于两个核心任务不协调访问同一个硬件可能会导致死锁和崩溃

出于实施目的,您需要考虑到 FreeRTOS 优先级从 0 到 N 分配,其中较低的数字对应较低的优先级。因此,最低优先级为 0。
首先,声明一个全局变量,该变量将包含要启动的 FreeRTOS 任务将被固定的核心编号

static int taskCore = 0; // The core the task should run on

现在在 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 */

这是您在 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); 
    }
}

希望这能让您了解如何解决您的问题,阅读更多内容here RTOS and here ESP32-IDF