0
\$\begingroup\$

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 circuit schematic enter image description here

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?

\$\endgroup\$
6
  • 1
    \$\begingroup\$ How do you debounce the button? \$\endgroup\$
    – Lundin
    Aug 23, 2022 at 11:07
  • \$\begingroup\$ Not currently doing it \$\endgroup\$
    – dracarys
    Aug 23, 2022 at 11:27
  • \$\begingroup\$ Then how do you expect any form of deterministic behavior when you press the button? \$\endgroup\$
    – Lundin
    Aug 23, 2022 at 11:34
  • \$\begingroup\$ Yes I agree, was doing debouncing in previous iterations of code when using interrupts but first concentrating on getting the intended behavior \$\endgroup\$
    – dracarys
    Aug 23, 2022 at 11:38
  • 1
    \$\begingroup\$ If you put a delay of 30 seconds right there, nothing helps you with that. Also this is a generic programming issue, which is basically, how to keep track of time and monitor for inputs instead of blindly delaying for 30 seconds. How about just not writing to the display when it's off? \$\endgroup\$
    – Justme
    Aug 23, 2022 at 11:46

1 Answer 1

1
\$\begingroup\$

I fixed the code. Instead if using delay for the DHT22, I used millis like used with the Display to delay and only measure once every 30 seconds.

#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

#define DISPLAY_TIMEOUT 2000
#define DHT_TIMEOUT 30000

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;
unsigned long prevTimeDHT = 0;
int displayOn = 0;
int startFlag = 1;

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()
{
  int startFlag = 1;
  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);
    oledDisplayCenter(tempString, humString); // display temperature and humidity on OLED
  }
  if (displayOn == 1 && digitalRead(SCREEN_BTN_INPUT) == HIGH)
  {
    if (millis() - prevTimeDisplay > DISPLAY_TIMEOUT)
    {
      displayOn = 0;
      oled.ssd1306_command(0xAE);
    }
  }

  if (startFlag || (millis() - prevTimeDHT > DHT_TIMEOUT))
  {
    startFlag = 0;
    prevTimeDHT = millis();
    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);
  }
}

```
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Please explain what was wrong and how you fixed it. \$\endgroup\$
    – Null
    Aug 23, 2022 at 12:32
  • \$\begingroup\$ It still has the problem in schematics regarding the reset pin. Either the schematics are wrong or you are unable to upload with Arduino tools because reset is hardwired to VCC via resistor so RTS from PC can't reset it. \$\endgroup\$
    – Justme
    Aug 23, 2022 at 20:15
  • \$\begingroup\$ uploaded the new schematic, the bugs are fixed. Also added a switching voltage regulator to power the chip from a battery bank \$\endgroup\$
    – dracarys
    Aug 24, 2022 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.