Code werkt niet volledig zoals gewild

Hallo
Ik ben Noé.
Ik ben nu al een tijdje beig met een project zodat de kippen automatish eten krijgen.
Ik heb heel wat geprogrameerd en dingen gebouwd en opzoekwerk gedaan.
Ik heb een probleem met mijn code maar ik weet niet hoe dat het komt.
Alles is verbonden zoals in de code.
Het probleem is dat het werkt 2-3 keer.
Maar dan blijft de tijd steken voor ewig tot dat ik het weer reset.
Zouden jullie weten hoe en waarom dat dit komt?

Dit is de code:

#include <ThreeWire.h>
#include <RtcDS1302.h>

// Pinnen voor buzzer en relais
const int buzzPin = 13;  // Pin buzzer
const int relPin = 9;    // Pin relais

// Pinnen voor RTC (DS1302)
const int clk = 11;  // Klok
const int dat = 12;  // Data
const int rst = 10;  // Reset

// Initialiseer ThreeWire interface voor RTC
ThreeWire myWire(dat, clk, rst);
RtcDS1302<ThreeWire> Rtc(myWire);

// Instellen van alarmtijden (3 verschillende tijden)
// Pas deze tijden aan naar wens
int Hour[]   = {14, 14, 14};   // Uren
int Minute[] = {25, 27, 3};    // Minuten
int Second[] = {30, 10, 0};    // Seconden

// Instellingen voor alarm
const int Count = 15;           // Tijd dat relais actief blijft (in seconden)
const int toneDuration = 1000;  // Duur van elke toon in milliseconden
const int totalTones = 6;       // Aantal tonen dat buzzer afspeelt

// Statusvariabelen voor alarm
bool alarmActive = false;  // Geeft aan of het alarm aan staat
bool buzzerDone = false;   // Geeft aan of buzzer klaar is met afspelen

// Tijdregistratie voor het afspelen van tonen en relais activeren
unsigned long toneStart = 0;   // Starttijd voor tonen
int toneStep = 0;              // Huidige toonstap
unsigned long relayStart = 0;  // Starttijd voor relais

void setup() {
  Serial.begin(115200);           // Start seriële communicatie (baudrate 115200)
  pinMode(buzzPin, OUTPUT);       // Zet buzzerpin als uitgang
  pinMode(relPin, OUTPUT);        // Zet relaispin als uitgang
  digitalWrite(relPin, LOW);      // Zet relais initieel uit

  // Initialiseer RTC
  Rtc.Begin();
  Rtc.SetIsWriteProtected(false);
  Rtc.SetIsRunning(true);

  // Controleer of RTC tijd geldig is
  if (!Rtc.IsDateTimeValid()) {
    Serial.println("⚠️ RTC tijd ongeldig. Stel in op compileertijd...");
    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
    Rtc.SetDateTime(compiled);  // Stel RTC tijd in op moment van compileren
  }
}

void loop() {
  // Variabelen die persistent blijven tussen loop-calls
  static unsigned long lastUpdate = 0;  // Tijdstip van laatste tijdupdate
  static RtcDateTime now;                // Huidige RTC tijd

  // Vernieuw RTC tijd maximaal 1x per seconde
  if (millis() - lastUpdate >= 1000) {
    lastUpdate = millis();          // Update tijd van laatste check
    now = Rtc.GetDateTime();        // Lees huidige tijd van RTC

    // Debug: controleer of RTC tijd "vastzit" (bevroren seconden)
    static uint8_t lastSecond = 255;  // Vorige seconde, initieel onwaarschijnlijk getal
    static int freezeCounter = 0;     // Tel hoe vaak dezelfde seconde wordt gezien

    if (now.Second() == lastSecond) {
      freezeCounter++;  // Seconde is gelijk aan vorige, verhoog teller
      if (freezeCounter > 3) {
        Serial.println("⛔ RTC tijd lijkt vast te zitten!");  // Waarschuwing
      }
    } else {
      freezeCounter = 0;        // Seconde is veranderd, reset teller
      lastSecond = now.Second();  // Sla nieuwe seconde op
    }

    // Print de huidige tijd op seriële monitor
    char buffer[16];
    sprintf(buffer, "%02u:%02u:%02u", now.Hour(), now.Minute(), now.Second());
    Serial.println(buffer);
  }

  // Alarm check: start alarm als huidige tijd overeenkomt met een ingestelde alarmtijd
  if (!alarmActive) {
    for (int i = 0; i < 3; i++) {
      // Controleer uur, minuut en seconde (binnen 1 seconde marge)
      if (now.Hour() == Hour[i] && now.Minute() == Minute[i] &&
          abs(now.Second() - Second[i]) <= 1) {
        Serial.println("🔔 Buzzer gestart");
        alarmActive = true;   // Zet alarm actief
        buzzerDone = false;   // Buzzer is nog niet klaar
        toneStart = millis(); // Starttijd tonen instellen
        toneStep = 0;         // Begin bij eerste toon
        break;                // Stop met zoeken, alarm gestart
      }
    }
  }

  // Fase 1: Buzzer afspelen
  if (alarmActive && !buzzerDone) {
    // Als er nog tonen over zijn en de tijd voor de volgende toon is bereikt
    if (toneStep < totalTones && millis() - toneStart >= toneStep * toneDuration) {
      // Speel afwisselend twee tonen (523 Hz en 587 Hz)
      tone(buzzPin, (toneStep % 2 == 0) ? 523 : 587);
      toneStep++;  // Volgende toon
    } 
    // Als alle tonen zijn gespeeld
    else if (toneStep >= totalTones) {
      noTone(buzzPin);         // Stop buzzer
      buzzerDone = true;       // Buzzer klaar
      relayStart = millis();   // Start tijd voor relais aan
      digitalWrite(relPin, HIGH);  // Zet relais aan
      Serial.println("➡️ Relay gestart");
    }
  }

  // Fase 2: Relay aanhouden en daarna uitschakelen
  if (buzzerDone && millis() - relayStart >= Count * 1000UL) {
    digitalWrite(relPin, LOW);  // Zet relais uit
    alarmActive = false;        // Zet alarm uit
    buzzerDone = false;         // Reset buzzer status
    Serial.println("🛑 Alarm volledig beëindigd");
  }

  delay(50);  // Kleine pauze om CPU te ontlasten
}

// Comments en debug systeem gemaakt door ChatGPT

De comments en het debug systeem zijn gemaakt door chatGPT.

Alvast bedankt voor jullie hulp
Noé

PS: Ik zal er de volgende twee weken niet zijn dus ik zal niet kunnen antwoorden sorry.

Deze code kan problemen geven.

De RTC-tijd wordt maar één keer per seconde bijgewerkt. Als die verversing net gebeurt vlak vóór het alarmmoment, wordt de voorwaarde gecontroleerd met de oude waarde en faalt. De volgende update komt te laat, één seconde na het alarm, waardoor de controle niet meer klopt. Gevolg: het alarm wordt gemist en pas de volgende minuut opnieuw geprobeerd.

Bedankt voor je antwoord
Maar dat is niet het probleem het probleem is dat het volledig werkt maar dat het soms (dus niet altijd) na dat het alarm is afgegaan de tijd ineens blijft steken voor ewig. Hoe zou ik dit kunnen oplossen?

alvast bedankt
Noé

Wat betekent dat precies? Wat zijn de symptomen?

Je hebt een RTC, dus het is nutteloos om de tijd slechts één keer per seconde uit te lezen. Laat de loop() de tijd voortdurend lezen en reageer op basis van het verloop van de tijd zonder kunstmatige frequentiebeperking

Wat voor relay heb je en hoe is het aangesloten?

Waar precies ? wat is de laatste 'debug message' die wordt geprint ?

Ik blijf het lastig lezen vinden als de '&&' voorwaarden niet door haakjes gescheiden zijn, maar in principe test je hier voor een exacte overeenkomst, terwijl je moet testen of de tijd verstreken is.

Als je een externe tijd gebruikt om de tijd binnen je programma op te meten, kan het zijn dat door een tijd update de tijd verspringt. Je moet voor alle tussenliggende tijdsmomenten ook alle condities testen. Als de RTC voor ligt op de CPU tijd, dan moet je ook het verspringende deel uitvoeren voor de te testen condities.

Hmm ik zie dat je helemaal geen CPU tijd mee laat lopen. De klok van de CPU zal over de periode vna een dag hoogstens enkele (tientallen) seconden afwijken van de werkelijke tijd, dus of je kan gebruik maken van de interne klok en deze slechts heel weinig vergelijken met de RTC (zoals je dat met een NTP tijd zou doen) of je kan de RTC continue lezen zonder het 1 seconde interval.

Dat is wel een relevante vraag ! Ook omdat het schakelen van het relais het moment lijkt te zijn dat er iets fout gaat.

Ik heb deze relay: relay.

Sorry maar ik snap niet helemaal wat je bedoelt kun je het een beetje maklkelijker uitleggen?

Noé

Je moet kijken of de tijd verstreken is, maar je kijkt nu of het precies op tijd is.
Daardoor is de kans dat niet aan die voorwaarde wordt voldaan, ontelbaar groter dan dat er wel aan wordt voldaan.
Zo loopt je sketch dus wel vast.

Denk dat er bedoeld wordt dat == in de vergelijking vervangen zou kunnen worden door >= Verspringt de tijd exact voor het moment van vergelijken, dan is altijd nog aan de voorwaarde voldaan......

Dat is dus een volledig 'kaal' relais op een PCB met wat pinnen om 'm aan te sluiten. Je kan zo'n relais niet rechtstreeks van een arduino pin aansturen. Je moet een transistor gebruiken en er hoort een fly-back diode op, en een externe 5v voeding is waarschijnlijk ook geen overbodige luxe (hoewel je van de USB poort nog wel voldoende 5v kan krijgen, maar bv niet voldoende als je de Arduino met 12v voedt en dan het relais op de 5v pin aansluit.

Dus nogmaals, hoe heb je het aangesloten ?

Er lijken wel wat extra componenten op te zitten; iets gemarkeerd met Q1, iets gemarkeerd met D1, een LED en waarschijnlijk een weerstand.

Oh ja aan de zijkant daar, was niet zichtbaar op de foto die ik bekeek, Q1 is aan transistor en D1 een diode, waarschijnlijk een fly-back, gelukkig maar, toch is hoe het wordt aangesloten wel degelijk van belang.

Hallo sorry
Ik had dit deeltje niet gezien.

De aansluitingen zijn als volgt:

Arduino usb voeding --> 12V stekker
arduino pin 13 --> buzzer positief
arduino GND pin --> buzzer negatief
arduino pin 9 --> relais Signal pin
arduino GND pin --> relais negatief pin
arduino 5V pin --> relais positief pin
arduino pin 11 --> RTC clk pin
arduino pin 12 --> RTC dat pin
arduino pin 10 --> RTC rst pin
arduino 5V pin --> RTC positief
arduino GND pin --> RTC negatief

Er is maar 1 arduino 5V pin en het verloopt als volgt:

5V ---| Drie touwtjes aan elkaar gesoldeerd

Eentje in de arduino 5V pin, eentje in de relais positief pin en eentje in de RTC positief pin.

Dit is nog is mijn code:

#include <ThreeWire.h>
#include <RtcDS1302.h>

// Pinnen voor buzzer en relais
const int buzzPin = 13;  // Pin buzzer
const int relPin = 9;    // Pin relais

// Pinnen voor RTC (DS1302)
const int clk = 11;  // Klok
const int dat = 12;  // Data
const int rst = 10;  // Reset

// Initialiseer ThreeWire interface voor RTC
ThreeWire myWire(dat, clk, rst);
RtcDS1302<ThreeWire> Rtc(myWire);

// Instellen van alarmtijden (3 verschillende tijden)
// Pas deze tijden aan naar wens
int Hour[]   = {14, 14, 14};   // Uren
int Minute[] = {25, 27, 3};    // Minuten
int Second[] = {30, 10, 0};    // Seconden

// Instellingen voor alarm
const int Count = 15;           // Tijd dat relais actief blijft (in seconden)
const int toneDuration = 1000;  // Duur van elke toon in milliseconden
const int totalTones = 6;       // Aantal tonen dat buzzer afspeelt

// Statusvariabelen voor alarm
bool alarmActive = false;  // Geeft aan of het alarm aan staat
bool buzzerDone = false;   // Geeft aan of buzzer klaar is met afspelen

// Tijdregistratie voor het afspelen van tonen en relais activeren
unsigned long toneStart = 0;   // Starttijd voor tonen
int toneStep = 0;              // Huidige toonstap
unsigned long relayStart = 0;  // Starttijd voor relais

void setup() {
  Serial.begin(115200);           // Start seriële communicatie (baudrate 115200)
  pinMode(buzzPin, OUTPUT);       // Zet buzzerpin als uitgang
  pinMode(relPin, OUTPUT);        // Zet relaispin als uitgang
  digitalWrite(relPin, LOW);      // Zet relais initieel uit

  // Initialiseer RTC
  Rtc.Begin();
  Rtc.SetIsWriteProtected(false);
  Rtc.SetIsRunning(true);

  // Controleer of RTC tijd geldig is
  if (!Rtc.IsDateTimeValid()) {
    Serial.println("⚠️ RTC tijd ongeldig. Stel in op compileertijd...");
    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
    Rtc.SetDateTime(compiled);  // Stel RTC tijd in op moment van compileren
  }
}

void loop() {
  // Variabelen die persistent blijven tussen loop-calls
  static unsigned long lastUpdate = 0;  // Tijdstip van laatste tijdupdate
  static RtcDateTime now;                // Huidige RTC tijd

  // Vernieuw RTC tijd maximaal 1x per seconde
  if (millis() - lastUpdate >= 1000) {
    lastUpdate = millis();          // Update tijd van laatste check
    now = Rtc.GetDateTime();        // Lees huidige tijd van RTC

    // Debug: controleer of RTC tijd "vastzit" (bevroren seconden)
    static uint8_t lastSecond = 255;  // Vorige seconde, initieel onwaarschijnlijk getal
    static int freezeCounter = 0;     // Tel hoe vaak dezelfde seconde wordt gezien

    if (now.Second() == lastSecond) {
      freezeCounter++;  // Seconde is gelijk aan vorige, verhoog teller
      if (freezeCounter > 3) {
        Serial.println("⛔ RTC tijd lijkt vast te zitten!");  // Waarschuwing
      }
    } else {
      freezeCounter = 0;        // Seconde is veranderd, reset teller
      lastSecond = now.Second();  // Sla nieuwe seconde op
    }

    // Print de huidige tijd op seriële monitor
    char buffer[16];
    sprintf(buffer, "%02u:%02u:%02u", now.Hour(), now.Minute(), now.Second());
    Serial.println(buffer);
  }

  // Alarm check: start alarm als huidige tijd overeenkomt met een ingestelde alarmtijd
  if (!alarmActive) {
    for (int i = 0; i < 3; i++) {
      // Controleer uur, minuut en seconde (binnen 1 seconde marge)
      if (now.Hour() == Hour[i] && now.Minute() == Minute[i] &&
          abs(now.Second() - Second[i]) <= 1) {
        Serial.println("🔔 Buzzer gestart");
        alarmActive = true;   // Zet alarm actief
        buzzerDone = false;   // Buzzer is nog niet klaar
        toneStart = millis(); // Starttijd tonen instellen
        toneStep = 0;         // Begin bij eerste toon
        break;                // Stop met zoeken, alarm gestart
      }
    }
  }

  // Fase 1: Buzzer afspelen
  if (alarmActive && !buzzerDone) {
    // Als er nog tonen over zijn en de tijd voor de volgende toon is bereikt
    if (toneStep < totalTones && millis() - toneStart >= toneStep * toneDuration) {
      // Speel afwisselend twee tonen (523 Hz en 587 Hz)
      tone(buzzPin, (toneStep % 2 == 0) ? 523 : 587);
      toneStep++;  // Volgende toon
    } 
    // Als alle tonen zijn gespeeld
    else if (toneStep >= totalTones) {
      noTone(buzzPin);         // Stop buzzer
      buzzerDone = true;       // Buzzer klaar
      relayStart = millis();   // Start tijd voor relais aan
      digitalWrite(relPin, HIGH);  // Zet relais aan
      Serial.println("➡️ Relay gestart");
    }
  }

  // Fase 2: Relay aanhouden en daarna uitschakelen
  if (buzzerDone && millis() - relayStart >= Count * 1000UL) {
    digitalWrite(relPin, LOW);  // Zet relais uit
    alarmActive = false;        // Zet alarm uit
    buzzerDone = false;         // Reset buzzer status
    Serial.println("🛑 Alarm volledig beëindigd");
  }

  delay(50);  // Kleine pauze om CPU te ontlasten
}

// Comments en debug systeem gemaakt door ChatGPT

Alvast bedankt

Noé

Leg dat a.u.b even uit.

PS
Een tekening zegt vaak meer dan 1000 woorden.

Ik heb deze kabel besteld voor de arduino: amazon (voeding)

Alvast bedankt
Noé

Ik vind geen goede tool om zo een schema te maken.

Noé

Ben je van plan 12V op de USB te zetten? Dat is een gegarandeerde dood voor je Arduino.

Ik heb me vergist van link.
Ik heb deze kabel besteld: https://www.amazon.de/-/nl/dp/B00VL1KQ3I?ref=fed_asin_title&tag=wkss20-20

Potlood en papier tekening. Foto daarvan maken en hier neer zetten.