Hello everyone,
I'm currently working on a project where an LED should blink based on data received via I2C. I’ve noticed that the delay() function works correctly in the setup() function, but not as expected in the loop() function. To achieve a 1-second delay, I need to set the delay to approximately 8000 ms instead of the usual 1000 ms.
Interestingly, the delay works as expected in setup(), but not in the blinkNumber() function, which is called in the loop() function. I have already checked the fuses, but the issue persists.
Here’s a snippet of my code:
void blinkNumber(unsigned long number) {
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(8000); // Sollte 1 Sekunde leuchten
digitalWrite(LED_PIN, LOW);
delay(8000); // Sollte 1 Sekunde ausgeschaltet bleiben
}
}
Does anyone have an idea what could be causing this? Why does delay() work correctly in setup() but not in loop()? Could it have something to do with the sleep mode or the watchdog settings?
I’m looking forward to your tips and ideas!
Thanks in advance!
Here’s the complete code:
#include <Arduino.h>
#include "TinyWire.h"
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/power.h>
#define LED_PIN 4 // Definiert den Pin für die LED
#define MOSFET_ENABLE 3 // Definiert den Pin zur Steuerung des MOSFETs
#define SHORT_ESP_POWER_BUTTON 1 // Definiert den Pin für den ESP Power-Button
volatile unsigned long receivedData = 0; // Speichert die über I2C empfangenen Daten
volatile unsigned long totalSleepTime = 0; // Gesamtschlafzeit in Sekunden
const unsigned long MAX_SLEEP_TIME = 72000; // Maximale Schlafzeit (12 Stunden in Sekunden) => auf 20h geändert
const byte MAX_ON_TIME = 90; // Maximale Zeit für Modemverbindung in Sekunden
const byte RETRY_TIME = 8; // Wartezeit vor erneutem Verbindungsversuch in Minuten
volatile byte onTimeCounter = 0; // Zähler für die Zeit, die das Modem eingeschaltet ist
volatile byte sleepPrepared = 0; // Flag, ob der Schlafmodus vorbereitet ist
volatile bool blinkDone = false; // Flag zum Überprüfen, ob das Blinken abgeschlossen ist
byte saveADCSRA; // Speichert den ADCSRA-Wert für den Schlafmodus
volatile unsigned long counterWD = 0; // Zähler für den Watchdog-Timer
void resetWatchDog() {
cli(); // Deaktiviert globale Interrupts
MCUSR = 0; // Setzt das MCU Status Register zurück
WDTCR = bit(WDCE) | bit(WDE) | bit(WDIF); // Aktiviert Watchdog-Änderungen
WDTCR = bit(WDIE) | bit(WDP3) | bit(WDP0); // Setzt Watchdog auf 8 Sekunden
sei(); // Aktiviert globale Interrupts
wdt_reset(); // Setzt den Watchdog-Timer zurück
}
void sleepNow() {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Setzt den tiefsten Schlafmodus
saveADCSRA = ADCSRA; // Speichert den aktuellen ADCSRA-Wert
ADCSRA = 0; // Deaktiviert den ADC
power_all_disable(); // Schaltet alle Peripheriegeräte aus
noInterrupts(); // Deaktiviert Interrupts
resetWatchDog(); // Setzt den Watchdog zurück
sleep_enable(); // Aktiviert den Schlafmodus
interrupts(); // Aktiviert Interrupts wieder
sleep_cpu(); // Geht in den Schlafmodus
sleep_disable(); // CPU wacht auf, deaktiviert Schlafmodus
power_all_enable(); // Schaltet alle Peripheriegeräte wieder ein
ADCSRA = saveADCSRA; // Stellt den ursprünglichen ADCSRA-Wert wieder her
}
// ######################
void blinkNumber(unsigned long number) {
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
}
}
void blinkNumber(unsigned long number) {
blinkDone = false; // Setzt das Flag vor dem Start des Blinkens
// Flackern am Anfang
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(400);
digitalWrite(LED_PIN, LOW);
delay(400);
}
// Pause nach dem Flackern
delay(2000);
// Jede Ziffer einzeln blinken
unsigned long divisor = 1;
while (number / divisor > 9) {
divisor *= 10;
digitalWrite(LED_PIN, HIGH);
delay(10000);
digitalWrite(LED_PIN, LOW);
delay(80);
}
while (divisor > 0) {
int digit = (number / divisor) % 10;
// Blinke die Ziffer
for (int i = 0; i < digit; i++) {
digitalWrite(LED_PIN, HIGH);
delay(8000);
digitalWrite(LED_PIN, LOW);
delay(8000);
}
// Pause zwischen den Ziffern
delay(30000);
divisor /= 10;
}
// Flackern am Ende
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(LED_PIN, LOW);
delay(1000);
}
// Abschließende Pause
delay(2000);
blinkDone = true; // Setzt das Flag, wenn das Blinken abgeschlossen ist
}
// ################
void receiveEvent(int num) {
byte rxbyte[3] = {0}; // Array zur Speicherung der empfangenen Bytes
int i = 0;
while (TinyWire.available() && i < 3) {
rxbyte[i++] = TinyWire.read(); // Liest bis zu 3 Bytes ein
}
// Kombiniert die 3 Bytes zu einer Zahl
receivedData = ((unsigned long)rxbyte[0] << 16) | ((unsigned long)rxbyte[1] << 8) | rxbyte[2];
if (receivedData >= 1 && receivedData <= 9999) {
totalSleepTime = receivedData * 60; // Umrechnung von Minuten in Sekunden
counterWD = 0; // Setzt den Watchdog-Zähler zurück
sleepPrepared = 0; // Setzt das Schlafvorbereitungs-Flag zurück
// Bestätigung durch LED-Blinken
// digitalWrite(LED_PIN, HIGH);
// delay(100);
// digitalWrite(LED_PIN, LOW);
// Anzeigen des empfangenen Werts durch LED-Blinken
blinkNumber(receivedData);
}
}
void requestEvent() {
// Teilt receivedData in 3 Bytes auf
byte highB = (receivedData >> 16) & 0xFF;
byte midB = (receivedData >> 8) & 0xFF;
byte lowB = receivedData & 0xFF;
// Sendet die 3 Bytes über I2C
TinyWire.send(highB);
TinyWire.send(midB);
TinyWire.send(lowB);
receivedData = 0; // Setzt receivedData zurück
}
void setup() {
// // Debug-Schleife für Zeitkalibrierung
// for (int i = 0; i < 10; i++) { // 10 Wiederholungen für eine einfache Messung
// digitalWrite(LED_PIN, HIGH);
// delay(2000); // Sollte 1 Sekunde sein
// digitalWrite(LED_PIN, LOW);
// delay(2000); // Sollte 1 Sekunde sein
// }
resetWatchDog(); // Initialisiert den Watchdog-Timer
pinMode(LED_PIN, OUTPUT);
pinMode(SHORT_ESP_POWER_BUTTON, OUTPUT);
pinMode(MOSFET_ENABLE, OUTPUT);
digitalWrite(MOSFET_ENABLE, HIGH); // Aktiviert den MOSFET
TinyWire.begin(0x08); // Initialisiert I2C mit Adresse 0x08
TinyWire.onReceive(receiveEvent);
TinyWire.onRequest(requestEvent);
// Initialisierung anzeigen durch LED-Blinken ( Flackern)
for (int i = 0; i < 5; i++) {
digitalWrite(LED_PIN, HIGH);
delay(50);
digitalWrite(LED_PIN, LOW);
delay(50);
}
// ESP starten
digitalWrite(SHORT_ESP_POWER_BUTTON, HIGH);
delay(1000);
digitalWrite(SHORT_ESP_POWER_BUTTON, LOW);
}
void loop() {
if (digitalRead(MOSFET_ENABLE) == HIGH) {
onTimeCounter++;
if (onTimeCounter >= MAX_ON_TIME) {
digitalWrite(MOSFET_ENABLE, LOW); // Schaltet MOSFET aus
totalSleepTime = (unsigned long)RETRY_TIME * 60; // Setzt Schlafzeit auf RETRY_TIME
onTimeCounter = 0;
sleepPrepared = 0;
counterWD = 0;
}
} else {
onTimeCounter = 0;
}
if (totalSleepTime > 0 && blinkDone) { // Überprüft, ob das Blinken abgeschlossen ist
if (!sleepPrepared) {
digitalWrite(MOSFET_ENABLE, LOW); // Schaltet MOSFET aus
sleepPrepared = 1;
}
if (counterWD >= totalSleepTime || counterWD >= MAX_SLEEP_TIME) {
// Aufwachen
digitalWrite(LED_PIN, HIGH);
delay(10);
digitalWrite(LED_PIN, LOW);
counterWD = 0;
digitalWrite(MOSFET_ENABLE, HIGH); // Schaltet MOSFET ein
totalSleepTime = 0;
sleepPrepared = 0;
// ESP neu starten => Hack um TTGO zu staren ist ein zus Knopfdruck notwendig
digitalWrite(SHORT_ESP_POWER_BUTTON, HIGH);
delay(500);
digitalWrite(SHORT_ESP_POWER_BUTTON, LOW);
} else {
sleepNow(); // Geht in den Schlafmodus
}
}
delay(1000); // Kurze Pause, um Energie zu sparen
}
ISR(WDT_vect) {
wdt_disable(); // Deaktiviert den Watchdog
counterWD += 8; // Erhöht den Zähler um 8 Sekunden
}
Fuse EInstellungen:
Low-Fuse: 0xE2
High-Fuse: 0xDF
Extended-Fuse: 0xFF