Code suddenly stopped working, hardware related?

Hello,

one of the awesome guys here programmed some code for me. And it is working perfect.
I had it on a breadboard, but the wires were kind of messy.

So, I wanted to re-wire and than put it on a real PCB.
But for some strange reason the display doesn't show the correct time anymore
The RTC (ds3231) remembers the time when I remove the power.
When I upload the code, the display starts with the previous time, and doesn't update from the computer.

Does anyone know what is going on?

/*
  Forum: https://forum.arduino.cc/t/problems-with-this-code/1220732
  Wokwi: https://wokwi.com/projects/389909319974077441

  PIR Sketch IV

  2024/02/16
  ec2021
*/

#define WOKWI


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <RTClib.h>


#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SSD1306_I2C_ADDRESS 0x3C

#define PIR_PIN 5
#define LED_PIN 3

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);
#ifdef WOKWI
RTC_DS1307 rtc;
#else
RTC_DS3231 rtc;
#endif

unsigned long previousMillisTime = 0;
unsigned long ledStartTime = 0;
bool ledOn = false;
const long intervalTime = 1000;
long ledDuration = 10 * 1000; // 10 seconds in milliseconds

struct timeType {
  private:
    int hour;
    int minute;
    unsigned long totalSeconds;
  public:
    void set(int Hour, int Minute) {
      hour = Hour;
      minute = Minute;
      totalSeconds = (hour * 60 + minute) * 60;
    }
    unsigned long inSeconds() {
      return totalSeconds;
    };
};

timeType pirActive;
timeType pirDeactive;

const int LED_BRIGHTNESS = 64; // LED brightness (0-255)

unsigned long currentMillis;
DateTime now;
boolean pirIsActive = false;

void setup() {
  Serial.begin(115200);
  pirActive.set(16, 30);
  pirDeactive.set( 8, 30);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);

  if (!rtc.begin()) {
    Serial.println("Unable to find RTC");
    while (1);
  }

#ifndef WOKWI
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, setting the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
#endif
  display.begin(SSD1306_I2C_ADDRESS, SSD1306_I2C_ADDRESS);
  display.display();
  display.clearDisplay();
}

void loop() {
  now = rtc.now();
  handleTime(); // Display time every second
  handleLEDOnTime();
  checkPIR(); // Check PIR sensor and activate LED if conditions are met
}

void handleTime() {
  if (millis() - previousMillisTime >= intervalTime) {
    checkPirTime();
    previousMillisTime = millis();
    display.clearDisplay();
    display.setTextSize(2, 5);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(10, 20);
    printWithLeadingZero(now.hour(), true);
    printWithLeadingZero(now.minute(), true);
    printWithLeadingZero(now.second(), false);
    display.display();
  }
}

void handleLEDOnTime() {
  byte mode = 0;
  if (now.hour() >= 20 && now.minute() >= 30) {
    mode = 1;
  }
  if (now.hour() >= 21) {
    mode = 1;
  }
  if (now.hour() >= 23 || now.hour() < 9)     {
    mode = 2;
  }
  switch (mode) {
    case 0:
    case 1: ledDuration = 10 * 1000L;
      break;
    case 2: ledDuration = 25 * 1000L;
      break;
  }
}

void printWithLeadingZero(int number, boolean displayColon) {
  if (number < 10) {
    display.print("0");
  }
  display.print(number, DEC);
  if (displayColon) {
    display.print(":");
  }
}

void checkPirTime() {
  unsigned long timeInSeconds = (now.hour() * 60 + now.minute()) * 60;
  byte mode;
  if (pirDeactive.inSeconds() < pirActive.inSeconds()) {
    mode = 0;  // Deactivation is earlier than activation
  } else {
    mode = 1;  // Deactivation is later than activation
  }
  if (pirDeactive.inSeconds() == pirActive.inSeconds()) {
    mode = 2; // Deactivation is at the same time as activation
  }
  switch (mode) {
    case 0:  // Deactivation earlier
      pirIsActive = !(timeInSeconds >= pirDeactive.inSeconds() &&
                      timeInSeconds < pirActive.inSeconds());
      break;
    case 1:  // Deactivation later
      pirIsActive =  (timeInSeconds >= pirActive.inSeconds() &&
                      timeInSeconds <  pirDeactive.inSeconds());
      break;
    case 2:  // At the same time ... ?!! Set PIR always active
      pirIsActive = true;
      break;
  }
  if (!pirIsActive && ledOn) {
    digitalWrite(LED_PIN, LOW);
    ledOn = false;
  }
}


void checkPIR() {
  static unsigned long reTriggerDelay = 0;
  if (pirIsActive && digitalRead(PIR_PIN) == HIGH && !ledOn) {
    if (millis() - ledStartTime > reTriggerDelay) {
      digitalWrite(LED_PIN, HIGH);
      ledStartTime = millis();
      ledOn = true;
      Serial.println("LED turned on");
      reTriggerDelay = 7100 + ledDuration;
    }
  }
  if (ledOn && millis() - ledStartTime >= ledDuration) {
    digitalWrite(LED_PIN, LOW);
    ledOn = false;
    Serial.println("LED turned off");
  }
}

Comment out the following line:

#define WOKWI

Hi David,

yes! That works. But why? I have tested with this code for several times.
And it always worked. So I don't underderstand why it has to be removed.

I am happy, but why?

Regards, Peter

That is adapting the code to run as a wokwi simulation, and bypasses setting the RTC data/time in setup if the RTC was not running.

Do you have a battery on the RTC?

Your inSeconds will misbehave when (hour * 60 + minute) * 60 exceeds 32767 (the maximum for an int). Try changing it to:
totalSeconds = (hour * 60L + minute) * 60L;

Thanks for the explantion.

Yes there is a CR20232 on the board. Should I replace it with a LIR2032 (rechargable)?

Thanks!
I have changed the code now. And it works.
But there is no way to test this?

No, the CR2032 should work fine, but some of these clock boards do have a charge circuit for the battery that should be disabled for a non-rechargeable battery.

The code that you have in setup() will set the RTC to the time you compiled the sketch, but only if the RTC has lost power.

What time is it now in your time zone?
How many is totalSeconds ?
Why not just write code to display the number given by the inSeconds() function ?

OK. So for example remove the 200 ohm resistor?

I am in the Netherlands, it's now 20.35 hrs.

Should I use:

  int seconds = inSeconds(); // Get the number of seconds
    Serial.print(" Number of seconds since power on: ");
    Serial.print(seconds); // Display the number of seconds

Or do you mean someting else?

I have looked at your code again, and I am trying to make sense of it.

I don't understand what it is supposed to do. Did you copy and paste this sketch from somewhere else?

I can tell you that this line has a bug:

void checkPirTime() {
  unsigned long timeInSeconds = (now.hour() * 60 + now.minute()) * 60;

or at least, it seems to have a bug, because an int times an int will gave an int, and an int can only go up to 32767, but there are 86400 seconds in a day.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.