Rhetorische Frage:
Welche Code-Version wird von Anfängern wohl bevorzugt?
Die Code-Version die am leichtesten verständlich ist.
Hier die Funktion Lüfter ein Zeitintervall A eingeschaltet, ein anderes Zeitintervall B ausgeschaltet
#define EIN LOW // Relais is low-aktiv umgekehrte Logik: LOW entspricht eingeschaltet
#define AUS HIGH // HIGH entspricht ausgeschaltet
const byte PIN_RELAY2_LUFT = 10;
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__) );
Serial.print( F(" compiled ") );
Serial.print( F(__DATE__) );
Serial.print( F(" ") );
Serial.println( F(__TIME__) );
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
unsigned long MyLuefterTimer = 0; // Timer-variables MUST be of type unsigned long
const byte OnBoard_LED = 2;
// für die korrekte Berechnung von Variablen vom Typ unsigned long "UL" an die Zahl anhängen
// 2 Minuten * 60 Sekunden * 1000 Millisekunden
const unsigned long LuefterLaueftIntervall = 2 * 60 * 1000UL;
const unsigned long LuefterAusIntervall = 1 * 60 * 1000UL;
unsigned long SchaltIntervall;
boolean LuefterLaueft;
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
PrintFileNameDateTime();
pinMode(PIN_RELAY2_LUFT, OUTPUT);
// Initialisierung mit Lüfter wird eingeschaltet
LuefterLaueft = true;
SchaltIntervall = LuefterLaueftIntervall;
digitalWrite(PIN_RELAY2_LUFT, EIN);
MyLuefterTimer = millis(); // In der Timer-Variable den akteuellen Zeitstempel speichern
}
void LuefterIntervallSchaltung() {
if ( TimePeriodIsOver(MyLuefterTimer, SchaltIntervall) ) {
// Luefter wird geschaltet.
// Der Zeitstempel des Schaltens wird in Variable MyLuefterTimer gespeichert
// und automatisch bei jedem "Ablauf" des Timers von der
// function TimePeriodIsOver aktualisiert = neu gespeichert
// wenn die Anzahl Millisekunden vergangen ist die in der Variable
// SchaltIntervall steht dann wird der Code in der If.Bedingung ausgeführt
if (LuefterLaueft) {
digitalWrite(PIN_RELAY2_LUFT, AUS);
LuefterLaueft = false;
SchaltIntervall = LuefterAusIntervall;
}
else {
digitalWrite(PIN_RELAY2_LUFT, EIN);
LuefterLaueft = true;
SchaltIntervall = LuefterLaueftIntervall;
}
}
}
void loop() {
BlinkHeartBeatLED(OnBoard_LED, 250);
LuefterIntervallSchaltung();
}
Und hier die Version mit zusätzlichem komfortablen debug-output
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
// usage: dbg("1:my fixed text",myVariable);
// myVariable can be any variable or expression that is defined in scope
#define dbgi(myFixedText, variableName,timeInterval) \
do { \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
} while (false);
// usage: dbgi("2:my fixed text",myVariable,1000);
// myVariable can be any variable or expression that is defined in scope
// third parameter is the time in milliseconds that must pass by until the next time a
// Serial.print is executed
// end of macros dbg and dbgi
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *
#define EIN LOW // Relais is low-aktiv umgekehrte Logik: LOW entspricht eingeschaltet
#define AUS HIGH // HIGH entspricht ausgeschaltet
const byte PIN_RELAY2_LUFT = 10;
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__) );
Serial.print( F(" compiled ") );
Serial.print( F(__DATE__) );
Serial.print( F(" ") );
Serial.println( F(__TIME__) );
}
// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
unsigned long MyLuefterTimer = 0; // Timer-variables MUST be of type unsigned long
const byte OnBoard_LED = 13;
// für die korrekte Berechnung von Variablen vom Typ unsigned long "UL" an die Zahl anhängen
// 2 Minuten * 60 Sekunden * 1000 Millisekunden
const unsigned long LuefterLaueftIntervall = 2 * 60 * 1000UL;
const unsigned long LuefterAusIntervall = 1 * 60 * 1000UL;
unsigned long SchaltIntervall;
boolean LuefterLaueft;
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
void setup() {
Serial.begin(115200);
Serial.println( F("Setup-Start") );
PrintFileNameDateTime();
pinMode(PIN_RELAY2_LUFT, OUTPUT);
// Initialisierung mit Lüfter wird eingeschaltet
LuefterLaueft = true;
SchaltIntervall = LuefterLaueftIntervall;
digitalWrite(PIN_RELAY2_LUFT, EIN);
MyLuefterTimer = millis(); // In der Timer-Variable den akteuellen Zeitstempel speichern
}
void LuefterIntervallSchaltung() {
// dbgi: "printe" nur EINMAL alle 1000 Millisekunden
dbgi("1:",LuefterLaueft,1000);
dbgi("2:",SchaltIntervall,1000);
dbgi("Laufzeit",millis() - MyLuefterTimer,1000);
dbgi("",0,1000);
if ( TimePeriodIsOver(MyLuefterTimer, SchaltIntervall) ) {
// Luefter wird geschaltet.
// Der Zeitstempel des Schaltens wird in Variable MyLuefterTimer gespeichert
// und automatisch bei jedem "Ablauf" des Timers von der
// function TimePeriodIsOver aktualisiert = neu gespeichert
// wenn die Anzahl Millisekunden vergangen ist die in der Variable
// SchaltIntervall steht dann wird der Code in der If.Bedingung ausgeführt
if (LuefterLaueft) {
digitalWrite(PIN_RELAY2_LUFT, AUS);
LuefterLaueft = false;
SchaltIntervall = LuefterAusIntervall;
dbg("Lüfter",LuefterLaueft); // gib bei JEDEM Aufruf auf die serielle Schnittstelle aus
dbg("Lüfter",SchaltIntervall);
}
else {
digitalWrite(PIN_RELAY2_LUFT, EIN);
LuefterLaueft = true;
SchaltIntervall = LuefterLaueftIntervall;
dbg("Lüfter",LuefterLaueft);
dbg("Lüfter",SchaltIntervall);
}
}
}
void loop() {
BlinkHeartBeatLED(OnBoard_LED, 250);
LuefterIntervallSchaltung();
}
Die Zahlenwerte der function millis() springen nach 49,7 Tagen vom Maxwert auf 0.
aber
Wenn man die Variablen die man für das Timing benutzt als Variablen-Typ
unsigned long deklariert
dann funktioniert die If-Bedingung
if ( millis() - StartZeit >= Intervall)
immer
Die Berechnung millis() - StartZeit führt immer zu einem positiven Ergebnis.
Das ist eine Eigenheit der unsigned Integermathematik.
unsigned heißt ohne Vorzeichen = nur positive Zahlen.
Deswegen kann das Programm Jahrzehntelang laufen und es funktioniert.
vgs