Зависание Arduino с OLED-дисплеем

У меня есть OLED дисплей с диагональю 0,96 дюйма, подключенный к моему Arduino Mega через SPI. Я установил Библиотека Adafruit и библиотека GFX. Я могу легко запустить небольшую графическую демонстрацию из Adafruit, а также без проблем отобразить статический текст.

Однако я пытаюсь реализовать проект, который, по моему мнению, будет простым и понятным. Я пытаюсь использовать DHT22 для сбора данных о температуре и влажности, а затем отображать их на OLED. Проблема, с которой я столкнулся, заключается в том, что Arduino зависает через неопределенное время. Максимальное время, которое ему удалось проработать, — около 6 минут.

Вот код, который я использую:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>

#define DHTPIN 7
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// При использовании программного SPI (случай по умолчанию):
#define OLED_MOSI   8
#define OLED_CLK   9
#define OLED_DC    10
#define OLED_CS    11
#define OLED_RESET 12
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16

#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

long previousMillis = 0;
long interval = 5000;

    String temperature;
    String humidity;

void setup(){    
  dht.begin();

  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);

  // по умолчанию мы будем генерировать высокое напряжение из линии 3,3 В внутри себя! (аккуратный!)
  display.begin(SSD1306_SWITCHCAPVCC);

  display.clearDisplay();

  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(0,0);

  display.println(" Madgayrah");
  display.display();
  while(millis()<2000);
}


void loop() {

  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;

    float h = dht.readHumidity();
    float f = dht.readTemperature(true);

    if(isnan(h) || isnan(f)){
      int x = 6;
      String dashes = "";
      for(int y=1; y<=x; y++){
        dashes += "-";
      }
      temperature = humidity = dashes;
    }else{
      temperature = String(f)+(char)248;
      humidity = String(h)+"%";
    }

    display.clearDisplay();
    display.setTextColor(WHITE);
    display.setCursor(0,0);

    display.setTextSize(1);
    display.println(String(previousMillis/1000));
    display.println("");

    display.println("Temperature:");
    display.setTextSize(2);
    display.println(temperature);

    display.setTextSize(1);
    display.println("Humidity:");
    display.setTextSize(2);
    display.println(humidity);

    display.display();
  }
}

При попытке отладки я обнаружил, что НЕ распечатка переменных температуры и влажности позволяет программе работать бесконечно. Однако по какой-то причине включение любой из этих строк и вывод этой переменной приводит к проблеме зависания Arduino.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Я использую внешний источник питания на 12 В, подключенный к корпусу Mega. Mega подает 5 В и землю на макетную плату, которая питает/заземляет как OLED, так и DHT22.

Есть какие-нибудь идеи относительно того, что может быть причиной зависания того, каким «должен быть» простой и понятный проект? Спасибо.

, 👍1

Обсуждение

Какой ток потребляет OLED? Возможно, это будет слишком сложно, чтобы протянуть через Arduino. Возможно, ему потребуется собственная сила., @Delta_G

возникла проблема: даже со сторожевым таймером устройство не восстанавливается, пока я не отключу ЖК-дисплей, @Ayson Baxter


2 ответа


5

Поскольку ваша программа использует различные объекты String разных размеров, существует большая вероятность, что память кучи (в ОЗУ) фрагментируется до такой степени, что начинается выделение String. потерпеть неудачу или начать выделять поверх переменных стека. (Обычно куча и стек работают навстречу друг другу, с противоположных концов памяти, которая освобождается после выделения статических переменных.)

Например, код for(int y=1; y<=x; y++){ тире += "-"; с x=6 создает полдюжины объектов String разной длины.

Чтобы избежать этой проблемы, вы можете осторожно освободить каждый объект, выделенный в куче, по завершении работы с ним или, что более эффективно, избежать использования объектов String, которые на самом деле не нужны в этой программе.

Например, вместо display.println(String(previousMillis/1000)); скажите display.println(previousMillis/1000); и вместо создания дефис по одному символу перед его использованием, просто скажите "------" вместо дефис.

,

1

У меня была точно такая же проблема, и ответ Джеймса помог мне понять, что проблема связана с кучей памяти.

В дополнение к тому, что он уже рекомендовал, я нашел здесь, что вам также следует обернуть все ваши константные строки в функции F().

Например вместо

display.println(" Madgayrah");

Вы пишете

display.println(F(" Madgayrah"));

При этом строка будет сохранена во флэш-памяти, а не в SRAM.

Кроме того, если вы используете OLED-дисплей только для печати текста, я настоятельно рекомендую более легкую SSD1306Ascii библиотеку

Он выводит текст на OLED-дисплей без буферизации, что вызывает небольшое мерцание, но значительно уменьшает объем памяти, необходимой для управления OLED.

Еще один полезный совет — используйте сторожевой таймер Arduino. По сути, после того, как вы включили эту функцию, вам нужно постоянно вызывать функцию wdt_reset();, и если вам не удалось вызвать ее в течение определенного количества секунд, Arduino автоматически перезагрузится.

,