ich würde gerne meinen Arduino Nano 1x in der Stunde für 10 Minuten betreiben und den Rest der Stunde, also 50 Minuten, in den Schlafmodus versetzen. Der Arduino soll nach dem Schlafen durch den Watchdogtimer geweckt werden, also müsste man den Watchdogtimer iwie in eine Schleife einbauen. Leider komme ich gerade auf keine Lösung und hoffe mir kann jemand von euch helfen?
Ein Beispielcode wäre super
Ich habe hier ein Muster für einen Attiny vorgestellt. Das gleiche Prinzip kann auch für einen Nano verwendet werden. Nur die Register für die Einstellung des Watchdogs muss man an den Atmega328 anpassen.
Ja, die Anfänger ... scheuen das lesen . Ein Microcontroller arbeitet mit Registern um bestimmte Funktionen einstellbar zu machen. Die Arduino Umgebung verbirgt das gut. Aber manchmal muss man sich halt doch damit befassen. Im vorliegenden Beispiel wird der Watchdog direkt über Register konfiguriert.
Hier ein Beispiel für den Nano, in meinem verlinkten Beispiel ist mir noch ein Fehler aufgefallen. Der Fehler ist hier korrigiert und ein Register wurde auf den Atmega328 angepasst:
#include <Arduino.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <util/atomic.h>
// How many watchdog wake-ups should be performed.
constexpr uint8_t WATCHDOG_WAKEUPS_TARGET {7}; // 8 * 7 = 56 seconds sleep duration
// watchdog ISR
ISR(WDT_vect) {
// nothing to do here, just wake up
}
void enableWatchdog() {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
MCUSR &= ~_BV(WDRF); // clear the reset flag
WDTCSR |= _BV(WDCE) | _BV(WDE); // set WDCE to be able to change/set WDE
// WDTCR = _BV(WDP1) | _BV(WDP2); // Set timer to 1 sec
// WDTCR = _BV(WDP0) | _BV(WDP1) | _BV(WDP2); // Set timer to 2 sec
// WDTCR = _BV(WDP3); // Set timer to 4 sec
WDTCSR = _BV(WDP0) | _BV(WDP3); // Set timer to 8sec (max).
WDTCSR |= (1 << WDIE); // enable the WD interrupt to get an interrupt instead of a reset
}
}
// function to go to sleep
void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode(); // Now enter sleep mode.
// The program will continue from here after the WDT timeout
sleep_disable(); // First thing to do is disable sleep.
}
void setup() {
Serial.begin(115200);
enableWatchdog();
}
void loop() {
// some code
Serial.println("Goto Sleep");
// sleep
for (size_t i = 0; i < WATCHDOG_WAKEUPS_TARGET; i++) { enterSleep(); }
Serial.println("Waked up");
}
In der For-Schleife am Ende der loop() Funktion wird die "Schlafdauer", bzw. die Anzahl der 8 Sekunden Schlafzyklen festgelegt. Für 50 Minuten Schlafen muss der Zähler (WATCHDOG_WAKEUPS_TARGET) halt entsprechend hoch sein. Er ist im vorliegenden Beispiel mit dem Datentyp byte festgelegt. Das wird nicht reichen. Mach ein "unsigned int" draus.
Der NANO ist nicht die glücklichste Wahl zum Stromsparen mittels Sleep. Auf dem NANO sind außer dem Controller noch andere Stromverbraucher.
Ein MINI / PRO MINI hat nur den Controller ohne weitere Hardware. Darum spart man da wirklich viel, wenn er in sleep geschickt ist.
Das wurde in einem anderen Thread schon mehrmals erwähnt. Ist der TO aber nicht so besonders drauf eingegangen. Aber er kann ja wenigstens die PowerLED auslöten. Macht dann wieder ca. 5mA weniger.
Ich habe noch eine Frage zu diesem Code:
Den verwende ich jetz für den Betrieb des Hydroponic Towers. Gestartet habe ich heute um 7:30 Uhr und er soll für 13 Zyklen immer erst 10 Minuten bewässern und dann 50 Minuten schlafen. Nach den 13 Zyklen soll der Controller wieder bis um 7:30 Uhr am nächsten Tag schlafen.
#include <avr/wdt.h>
#include <avr/sleep.h>
// time until the watchdog wakes the mc in seconds
constexpr uint8_t WATCHDOG_TIME {4}; // 1, 2, 4 or 8
// after how many watchdog wakeups we should collect and send the data
#define Pin_Pumpe 2
#define SLEEP_ZEIT 3000 // Sleep-Zeit in Sekunden (50 Minuten * 60)
#define MAX_DURCHLAUFE 13 // Maximale Anzahl von Durchläufen pro Tag
#define EIN_TAG 86400 // Ein Tag in Sekunden (24 Stunden * 60 Minuten * 60 Sekunden)
#define RESTZEIT 39600 //11 Stunden in Sekunden (11 Stunden * 60 Minuten * 60 Sekunden)
#define PUMPENLAUFZEIT 600000 //Laufzeit der Pumpe in Millisekunden
unsigned int durchlaufe=0;
// watchdog ISR
ISR(WDT_vect) {
// nothing to do here, just wake up
}
void enableWatchdog() {
cli();
wdt_reset();
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = (1<<WDIE) | (0<<WDE) | (1<<WDP3); // 4s / interrupt, no system reset
sei();
}
// function to go to sleep
void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // EDIT: could also use SLEEP_MODE_PWR_DOWN for lowest power consumption.
sleep_enable();
sleep_mode(); // Now enter sleep mode.
// The program will continue from here after the WDT timeout
sleep_disable(); // First thing to do is disable sleep.
}
void setup()
{
enableWatchdog();
pinMode(Pin_Pumpe, OUTPUT);
}
void loop() {
if (durchlaufe < MAX_DURCHLAUFE)
{
// Pumpe ansteuern für 10 Minuten
digitalWrite(Pin_Pumpe, HIGH);
delay(PUMPENLAUFZEIT);
digitalWrite(Pin_Pumpe, LOW);
delay(50);
// 50 Minuten in den Schlafmodus wechseln
for (size_t i = 0; i < (SLEEP_ZEIT/WATCHDOG_TIME) ; i++)
{
enterSleep();
}
//Zähler für Durchläufe erhöhen
durchlaufe++;
}
else
{
for (size_t j = 0; j < (RESTZEIT/WATCHDOG_TIME) ; j++)
{
enterSleep();
}
//Zähler zurücksetzen
durchlaufe=0;
}
}
Bin gerade nach Hause gekommen und habe gesehen, dass er schon um 16 Uhr gegossen hat, aber nach dem Code sollte erst 16:30 Uhr der Fall sein. Findet jemand den Fehler im Code ?
Mal abgesehen davon, ob da noch ein Fehler im Programm ist oder nicht, würde ich diese unschönen #defines nicht verwenden.
constexpr byte Pin_Pumpe {2};
constexpr uint8_t WATCHDOG_TIME {4}; // time until the watchdog wakes the mc in seconds
constexpr byte MAX_DURCHLAUFE {13}; // Maximale Anzahl von Durchläufen pro Tag
constexpr unsigned int SLEEP_ZEIT {50 * 60}; // Schlafzeit bis zum nächsten Pumpvorgang
constexpr unsigned int RESTZEIT {(24 - MAX_DURCHLAUFE) * 60 * 60UL}; // Schlafzeit inaktiv
constexpr unsigned long PUMPENLAUFZEIT_MS {10 * 60 * 1000UL}; // Laufzeit der Pumpe in Millisekunden
constexpr unsigned int SLEEP_AKTIV {SLEEP_ZEIT / WATCHDOG_TIME}; // Aktiv Intervalle
constexpr unsigned int SLEEP_INAKTIV {RESTZEIT / WATCHDOG_TIME}; // Inaktiv Intervall ohne Bewässerung
So errechnet sich alles von selber. Und wenn MAX_DURCHLAUFE oder die WATCHDOG_TIME geändert wird, passt sich der Rest automatisch an. Das funktioniert mit #defines nicht.
Wobei die SLEEP_AKTIV und SLEEP_INAKTIV nicht unbedingt notwendig ist. Aber die Benennung ist vielleicht etwas "sprechender" als RESTZEIT / WATCHDOG_TIME.
Davon abgesehen, ist so ein Nano(clone) kein Chronometer. Die zumindest bei den Clones (beim originalen weiß ich das nicht) eingesetzten Keramik-Resonatoren sind nicht besonders genau.
Allerdings dürfte die Ungenauigkeit keine halbe Stunde auf 8,5 Stunden ausmachen.
Was würdest du anstatt von #define benutzen ?
Ja iwo hat sich da eine halbe Stunde Verzögerung eingeschlichen
Aber mir reicht es vollkommen wenn es auf 5-10 Minuten stimmt
Für deinen konkreten Anwendungsfall nicht. Aber google hilft dir da weiter. Im www findest massig Beispiele zum Thema rtc und Arduino.
Aber bevor es ans code schreiben geht brauchst auch erstmal eine rtc.
Wenn das erledigt ist, ist das programmieren doch recht einfach.
Du prüfst nach jedem Aufwachen erstmal deine Uhrzeit und tust anhand dieser dann deine Aktionen ausführen (oder eben auch nicht).