Зависание 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
.
Есть какие-нибудь идеи относительно того, что может быть причиной зависания того, каким «должен быть» простой и понятный проект? Спасибо.
@The Duke Of Marshall שלום, 👍1
Обсуждение2 ответа
Поскольку ваша программа использует различные объекты String
разных размеров, существует большая вероятность, что память кучи (в ОЗУ) фрагментируется до такой степени, что начинается выделение String
. потерпеть неудачу или начать выделять поверх переменных стека. (Обычно куча и стек работают навстречу друг другу, с противоположных концов памяти, которая освобождается после выделения статических переменных.)
Например, код for(int y=1; y<=x; y++){ тире += "-";
с x=6
создает полдюжины объектов String
разной длины.
Чтобы избежать этой проблемы, вы можете осторожно освободить каждый объект, выделенный в куче, по завершении работы с ним или, что более эффективно, избежать использования объектов String
, которые на самом деле не нужны в этой программе.
Например, вместо display.println(String(previousMillis/1000));
скажите display.println(previousMillis/1000);
и вместо создания дефис
по одному символу перед его использованием, просто скажите "------"
вместо дефис
.
У меня была точно такая же проблема, и ответ Джеймса помог мне понять, что проблема связана с кучей памяти.
В дополнение к тому, что он уже рекомендовал, я нашел здесь, что вам также следует обернуть все ваши константные строки в функции F().
Например вместо
display.println(" Madgayrah");
Вы пишете
display.println(F(" Madgayrah"));
При этом строка будет сохранена во флэш-памяти, а не в SRAM.
Кроме того, если вы используете OLED-дисплей только для печати текста, я настоятельно рекомендую более легкую SSD1306Ascii библиотеку
Он выводит текст на OLED-дисплей без буферизации, что вызывает небольшое мерцание, но значительно уменьшает объем памяти, необходимой для управления OLED.
Еще один полезный совет — используйте сторожевой таймер Arduino. По сути, после того, как вы включили эту функцию, вам нужно постоянно вызывать функцию wdt_reset();
, и если вам не удалось вызвать ее в течение определенного количества секунд, Arduino автоматически перезагрузится.
- Что выбрать между датчиками температуры и влажности: AM230x или DHT22?
- Путаница между SPI и I2C для SSD1306 OLED
- Считывание 10-контактного 7-сегментного (2 цифры) сингла Arduino 1
- Объединение кода для нескольких датчиков в одной программе
- Nextion Display не получает обновленных данных
- Моя программа использует слишком много памяти
- SH1106 - Передача длинного буфера через SPI
- Частое включение и выключение в SSR
Какой ток потребляет OLED? Возможно, это будет слишком сложно, чтобы протянуть через Arduino. Возможно, ему потребуется собственная сила., @Delta_G
возникла проблема: даже со сторожевым таймером устройство не восстанавливается, пока я не отключу ЖК-дисплей, @Ayson Baxter