RTC skips up to 4 seconds when LED connected

Hi,

The goal is to have a weather station that has an audible alarm when temp is to hot.

When coded without the buzzer and leds, it works fine, as soon as I include the leds and buzzer the RTC refreshes at the same rate as the led delay. Could it be code or gnd related?

Code below

//Wiring:
//DHT11 to R3 - VCC to 5V; Data to DP2; GND to GND
//DS3231 (I2C) RTC to R3 - GND to GND; VCC to 5V; SDA to DP6; SCL to DP7
//LCD (I2C) 20x4 to R3 - GND to GND; VCC to 5V; SDA to SDA; SCL to SCL
//https://www.elithecomputerguy.com/2020/05/arduino-projects-lcd-temperature-humidity-alert-with-timestamp-dht11-ds3231-i2c-20x4-lcd/

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DS3231.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

int speakerPin = 9;
int length = 1;

#define LED_TOO_COLD A0
#define LED_PERFECT A1
#define LED_TOO_HOT A2

//Below insert for one word blink
#define Blink_interval 500            
unsigned long previousMillis = 0;
bool BlankOnOff = false;
int i = 0;

//Configure DHT11 Sensor
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

//Configure I2C 20x4 LCD Display
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7);

//Configure DS321 Real Time Clock
DS3231  rtc(6, 7);

//Temp Variables
float maxTemp = 26;
int alert = 0;
float alertTemp;
String alertTime;

void setup()
{
  //Start LCD Screen
  lcd.begin(20, 4);
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);

Serial.begin(9600);
  Serial.println("DHT11 test!");

  dht.begin();

  //Start Temperature Sensor
  dht.begin();

  //Start Clock
  rtc.begin();

  //The following lines can be uncommented to set the date and time
  //rtc.setDOW(THURSDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(16, 44, 00);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(18, 11, 2021);   // Set the date to January 1st, 2014

}
//Below insert for one word blink
void BlinkText(char *msgtxt, int col, int row) {
  unsigned long currentMillis = millis();
  lcd.setCursor(col, row);
  if(currentMillis - previousMillis > Blink_interval)   {
    previousMillis = currentMillis;
    if(BlankOnOff){
      for(i = 1; i < strlen(msgtxt); i++) {
        lcd.print(" ");
      } //End For
    } // End If
    else {
      lcd.print(msgtxt);
    } //End Else
    BlankOnOff = !BlankOnOff;
  } //End If
} // End BlinkText


void loop()
{
  //2 Second Delay to Allow DHT11 to Calibrate
  delay(1000);

  //Is Temp above maxTemp?  If So Set alertTemp to Highest Temp Value reached with Timestamp
  if (dht.readTemperature(false) > maxTemp) {
    alert = 1;
    if (dht.readTemperature(false) > alertTemp) {
      alertTemp = dht.readTemperature(false);
      alertTime = rtc.getTimeStr();
     
    }
  }

  //Standard LCD Print Out
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(rtc.getDOWStr());
  lcd.setCursor(10,0);
  lcd.print(rtc.getDateStr());
  lcd.setCursor(6, 1);
  lcd.print(rtc.getTimeStr());
  lcd.setCursor(0, 2);
  lcd.print("Temp ");
  lcd.setCursor(5, 2);
  lcd.print(dht.readTemperature(false));
  lcd.setCursor(11, 2);
  lcd.print("Hum ");
  lcd.setCursor(15, 2);
  lcd.print(dht.readHumidity());

  //LCD Print Out Alert if maxTemp is Passed
  if (alert == 1) {
     
    
    lcd.setCursor(0, 3);
    BlinkText("ALARM!", 0, 3); //Insert for one word blink - replaced orinial lcd.print(ALERT);
    lcd.setCursor(6, 3);
    lcd.print(alertTemp);
    lcd.setCursor(12, 3);
    lcd.print(alertTime);
    
 pinMode(speakerPin, OUTPUT);
  pinMode (A0 , OUTPUT);
  pinMode (A1 , OUTPUT);
  pinMode (A2 , OUTPUT);
  delay(2000);

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


  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(" *C ");
  if (t <= 20) {
    Serial.println("Too cold!");
    digitalWrite(A0, HIGH);
    digitalWrite(speakerPin, HIGH);
    delay (1000);
    digitalWrite(speakerPin, LOW);
    digitalWrite(A0, LOW);
  }
  if (20 < t < 27) {
    Serial.println("Perfect temperature!");
    digitalWrite(A1, HIGH);
    delay (2000);
    digitalWrite(A1, LOW);
  }
  if (t >= 26) {
    Serial.println("Too hot!");
    digitalWrite(A2, HIGH);
    digitalWrite(speakerPin, HIGH);
    delay (1000);
    digitalWrite(speakerPin, LOW);
    digitalWrite(A2, LOW);
  }

}

}

What happens if you just leave in the code for buzzer and leds and disconnect the uC pins?

Generally, if a "real" buzzer with a coil, it should be buffered by a transistor to manage the current and then also have a diode to deal with reverse voltage.

If a piezo buzzer, no issues as these are high-impedance and therefore low current.

LEDS should have a resistor to limit current, rule-of-thumb at 5V is 470 Ohm and 330 Ohm at 3.3V (limit to 10mA ... always check the uC specifications on a per-pin and a per-port basis.)

Try eliminating those long delay() calls and switch to millis()-based events.

Thanks for the response, all noted. I did find a 1k resistor instead of the 220, however I found that my DS3231 gains at least 1 second per every 10. That is without any other added code, just with code below, so I think I need to sort the rtc out first, or at least get it to be more accurate.

//Wiring:
//DHT11 to R3 - VCC to 5V; Data to DP2; GND to GND
//DS3231 (I2C) RTC to R3 - GND to GND; VCC to 5V; SDA to DP6; SCL to DP7
//LCD (I2C) 20x4 to R3 - GND to GND; VCC to 5V; SDA to SDA; SCL to SCL
//https://www.elithecomputerguy.com/2020/05/arduino-projects-lcd-temperature-humidity-alert-with-timestamp-dht11-ds3231-i2c-20x4-lcd/

#include <DHT.h>
#include <DS3231.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

//Below insert for one word blink
#define Blink_interval 1000            
unsigned long previousMillis = 0;
bool BlankOnOff = false;
int i = 0;

//Configure DHT11 Sensor
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

//Configure I2C 20x4 LCD Display
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7);

//Configure DS321 Real Time Clock
DS3231  rtc(6, 7);

//Temp Variables
float maxTemp = 26;
int alert = 0;
float alertTemp;
String alertTime;

void setup()
{
  //Start LCD Screen
  lcd.begin(20, 4);
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);

  //Start Temperature Sensor
  dht.begin();

  //Start Clock
  rtc.begin();

  //The following lines can be uncommented to set the date and time
  //rtc.setDOW(THURSDAY);     // Set Day-of-Week to SUNDAY
  //rtc.setTime(16, 44, 00);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(18, 11, 2021);   // Set the date to January 1st, 2014

}
//Below insert for one word blink
void BlinkText(char *msgtxt, int col, int row) {
  unsigned long currentMillis = millis();
  lcd.setCursor(col, row);
  if(currentMillis - previousMillis > Blink_interval)   {
    previousMillis = currentMillis;
    if(BlankOnOff){
      for(i = 1; i < strlen(msgtxt); i++) {
        lcd.print(" ");
      } //End For
    } // End If
    else {
      lcd.print(msgtxt);
    } //End Else
    BlankOnOff = !BlankOnOff;
  } //End If
} // End BlinkText
void loop()
{
  //2 Second Delay to Allow DHT11 to Calibrate
  delay(1000);

  //Is Temp above maxTemp?  If So Set alertTemp to Highest Temp Value reached with Timestamp
  if (dht.readTemperature(false) > maxTemp) {
    alert = 1;
    if (dht.readTemperature(false) > alertTemp) {
      alertTemp = dht.readTemperature(false);
      alertTime = rtc.getTimeStr();
     
    }
  }

  //Standard LCD Print Out
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(rtc.getDOWStr());
  lcd.setCursor(10,0);
  lcd.print(rtc.getDateStr());
  lcd.setCursor(6, 1);
  lcd.print(rtc.getTimeStr());
  lcd.setCursor(0, 2);
  lcd.print("Temp ");
  lcd.setCursor(5, 2);
  lcd.print(dht.readTemperature(false));
  lcd.setCursor(11, 2);
  lcd.print("Hum ");
  lcd.setCursor(15, 2);
  lcd.print(dht.readHumidity());

  //LCD Print Out Alert if maxTemp is Passed
  if (alert == 1) {
     
    
    lcd.setCursor(0, 3);
    BlinkText("ALARM!", 0, 3); //Insert for one word blink - replaced orinial lcd.print(ALERT);
    lcd.setCursor(6, 3);
    lcd.print(alertTemp);
    lcd.setCursor(12, 3);
    lcd.print(alertTime);
       
     }
}

Hi thanks for the response, my rtc gains second every 10. :worried:

BTW

if (20 < t < 27) {

Syntax

interesting, what is it suppose to be?

From you post #1

if (t > 20 && t < 27) {

How do you know that the RTC gains a second for each 10 seconds? Could it not be other things that looses 1 second instead?

Thank you for your response. I have made the changes :ok_hand:

I can see it on my lcd display, the only other sensor connected at this stage is the dht11

The RTC time updates every second, and usually this is very accurate. The timer of the MCU / Arduino may not be as accurate and if the 1 second delay in the loop is off by a little, it may seem as if the RTC is missing or gaining time even though it is not. Try to remove everything else but the RTC and set the loop delay to 100 and see what happens.

If you want the display to update every second according to the RTC, you should do something like this:

uint8_t last_sec = 0;

void loop()
{
  if (rtc.getSecond() != last_sec)
  {
    last_sec = rtc.getSecond();
    update_display();
  }
}

This will not be accurate if you use delay for timing elsewhere in the code.

Hi, understood thanks.

Yeah I would really have enjoyed this project if it could do what I wanted it to do, but there will have to be delays elsewhere, so this combo might not work. I will keep on trying. Thank you

It is always possible to avoid the usage of delay, it is just a question of how.. There are numerous examples in how to use millis() for timing.

EDIT: You should try the code I posted to verify that the RTC works as it is supposed to. Use a phone or whatever to time it over a minute or so.

With a well rested fresh pair of eyes I am not just reading, but also taking in what I read. I think this is the answer yes, I will certainly try this thanks.

Hi,

Thank you yes I will try this, very good starting point re the rtc. Thank you

Changed the delay to millis() however the only effect it has by watching the lcd is that the seconds are correct now and not skipping any, but the last line is faded and flashing, assuming due to my code not actually initiating the "delay"

Any assistance would be great. Even if I can just get the below code "Delay" changed to millis(), I am sure I will be able to complete the rest.

#include <DHT.h>
#include <DS3231.h>
#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

//Millis()
#define EXE_INTERVAL_1 2000
unsigned long lastExecutedMillis_1 = 0; // vairable to save the last executed time for code block 1

//Configure DHT11 Sensor
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

//Configure I2C 20x4 LCD Display
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7);

//Configure DS321 Real Time Clock
DS3231  rtc(6, 7);

//Temp Variables
float maxTemp = 26;
int alert = 0;
float alertTemp;
String alertTime;

void setup()
{
  //Start LCD Screen
  lcd.begin(20, 4);
  lcd.setBacklightPin(3, POSITIVE);
  lcd.setBacklight(HIGH);

  //Start Temperature Sensor
  dht.begin();

  //Start Clock
  rtc.begin();

  //The following lines can be uncommented to set the date and time
  //rtc.setDOW(MONDAY);     // Set Day-of-Week to SUNDAY
 // rtc.setTime(10, 34, 0);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(23, 11, 2021);   // Set the date to January 1st, 2014

}

void loop()
{
  //2 Second Delay to Allow DHT11 to Calibrate
  //delay(1000);

unsigned long currentMillis = millis();

  if (currentMillis - lastExecutedMillis_1 >= EXE_INTERVAL_1) {
    lastExecutedMillis_1 = currentMillis; // save the last executed time
  }


  //Is Temp above maxTemp?  If So Set alertTemp to Highest Temp Value reached with Timestamp
  if (dht.readTemperature(false) > maxTemp) {
    alert = 1;
    if (dht.readTemperature(false) > alertTemp) {
      alertTemp = dht.readTemperature(false);
      alertTime = rtc.getTimeStr();
    }
  }

  //Standard LCD Print Out
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(rtc.getDOWStr());
  lcd.setCursor(10,0);
  lcd.print(rtc.getDateStr());
  lcd.setCursor(6, 1);
  lcd.print(rtc.getTimeStr());
  lcd.setCursor(0, 2);
  lcd.print("Temp ");
  lcd.setCursor(5, 2);
  lcd.print(dht.readTemperature(false));
  lcd.setCursor(11, 2);
  lcd.print("Hum ");
  lcd.setCursor(15, 2);
  lcd.print(dht.readHumidity());

  //LCD Print Out Alert if maxTemp is Passed
  if (alert == 1) {
    lcd.setCursor(0, 3);
    lcd.print("ALERT");
    lcd.setCursor(6, 3);
    lcd.print(alertTemp);
    lcd.setCursor(12, 3);
    lcd.print(alertTime);
  }
}

Your implementation of millis() does absolutely nothing, the LCD is updated several times per seconds and this causes flicker. Look at this:

uint32_t last_dht_update = 0;
uint8_t last_rtc_update = 0;

void loop()
{
  uint32_t ms = millis();

  if (ms - last_dht_update >= UPDATE_DHT_INTERVAL)
  {
    display_update_dht();
    last_dht_update = ms;
  }

  if (rtc.getSecond() != last_rtc_update)
  {
    display_update_rtc();
    last_update_rtc = rtc.getSecond();
  }

}


Hi, thanks for the response.

Can you please put it in the correct order within my code above, just can not grasp it at this stage.

No, I would not take away from you the joy of succeeding in doing (and understanding) the final assembly.

1 Like