Hi I am trying to make a project that uses DHT22 (Temperature & Humidity Sensor) and SSD1306 (OLED Display) with the ATMega328p. I want the OLED Display to be normally off and should turn on for 5 seconds when a tactile push button is pressed. I also want the DHT22 to only record data every 30 seconds. I want to minimize the power consumption.
Below is my code:
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define DHTPIN 2 // pin connected to DHT22 sensor
#define DHTTYPE DHT22
#define SCREEN_BTN_INPUT 3 // pin connected to push button to turn screen on on click
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // create SSD1306 display object connected to I2C
DHT dht(DHTPIN, DHTTYPE);
String tempString;
String humString;
unsigned long prevTimeDisplay = 0;
int displayOn = 0;
void initialize_display()
{
// initialize OLED display with address 0x3C for 128x64
if (!oled.begin(SSD1306_SWITCHCAPVCC, 0x3C))
{
Serial.println(F("SSD1306 allocation failed"));
while (true)
;
}
oled.clearDisplay(); // clear display
oled.setTextSize(2); // text size
oled.setTextColor(WHITE); // text color
oled.setCursor(0, 10); // position to display
}
void oledDisplayCenter(String temp, String hum)
{
int16_t x1;
int16_t y1;
uint16_t width;
uint16_t height;
oled.getTextBounds(temp, 0, 0, &x1, &y1, &width, &height);
// display on horizontal and vertical center
oled.clearDisplay(); // clear display
oled.setCursor((SCREEN_WIDTH - width) / 2, SCREEN_HEIGHT / 2 - height - 2);
oled.println(temp); // text to display
oled.setCursor((SCREEN_WIDTH - width) / 2, SCREEN_HEIGHT / 2 + 2);
oled.println(hum); // text to display
oled.display();
}
void setup()
{
pinMode(DHTPIN, INPUT); // input of DHT22 sensor data
pinMode(SCREEN_BTN_INPUT, INPUT_PULLUP); // input when button pressed
Serial.begin(9600);
dht.begin(); // initialize DHT22 the temperature and humidity sensor
tempString.reserve(10); // to avoid fragmenting memory when using String
humString.reserve(10); // to avoid fragmenting memory when using String
initialize_display();
oled.ssd1306_command(0xAE);
}
void loop()
{
if (displayOn == 0 && digitalRead(SCREEN_BTN_INPUT) == LOW)
{
displayOn = 1;
prevTimeDisplay = millis();
oled.ssd1306_command(0xAF);
}
if (displayOn == 1 && digitalRead(SCREEN_BTN_INPUT) == HIGH)
{
if (millis() > prevTimeDisplay + 5000)
{
displayOn = 0;
oled.ssd1306_command(0xAE);
}
}
float hum = dht.readHumidity(); // read humidity
float temp = dht.readTemperature(); // read temperature
// check if any reads failed
if (isnan(temp))
{
tempString = "Error";
}
else
{
tempString = "T: " + String(temp, 1) + " C";
}
if (isnan(hum))
{
humString = "Error";
}
else
{
humString = "H: " + String(hum, 1) + " %";
}
Serial.println(tempString + " , " + humString);
oledDisplayCenter(tempString, humString); // display temperature and humidity on OLED
// delay(30000);
}
As you can see currently I have commented out the delay of 30 seconds and the code is working. But if I remove the code of delay, it does not function properly, because it is not able to turn the display on as the code is predominantly in the delay phase.
I have also tried to use interrupts for this, but the OLED display does not sleep in the interrupt code
oled.ssd1306_command(0xAE); //this does not work in interrupt subroutine
How can I achieve this, can someone guide me?