Arduino Delay für eine Sekunde?
Hallo, ich wollte eine Uhr für einen Display programmieren und diese mit einer Fernbedinung ansteuern. Nur habe ich ein Problem, meine Uhr ist etwas langsamer als eine normale Uhr (Atomuhr). Obwohl ich einen Delay von 1000 habe.
ich bin im Besitz des Arduino Elegoo Mega 2560
Falls es interessant ist, kopiere ich hier den kompletten Code:
#include <LiquidCrystal.h>
#include "IRremote.h"
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int offTimer;
int onTimer;
int s=15; //sekunden
int m=49; //minuten
int h=19; //stunden
int tag=3; //tage
int monat=6; //monate
int jahr=2018; //Jahr
int receiver = 6;
int lcdsize[] = {16, 2};
IRrecv irrecv(receiver);
decode_results results;
void translateIR() // takes action based on IR code received
// Beschreibt Remote-IR-Codes
{
switch(results.value)
{
case 0xFFA25D: onTimer++; offTimer=0; break;
case 0xFFE21D: offTimer++; onTimer=0; break;
case 0xFF629D: Serial.println("VOL+"); break;
case 0xFF22DD: Serial.println("FAST BACK"); break;
case 0xFF02FD: Serial.println("PAUSE"); break;
case 0xFFC23D: Serial.println("FAST FORWARD"); break;
case 0xFFE01F: Serial.println("DOWN"); break;
case 0xFFA857: Serial.println("VOL-"); break;
case 0xFF906F: Serial.println("UP"); break;
case 0xFF9867: Serial.println("EQ"); break;
case 0xFFB04F: Serial.println("ST/REPT"); break;
case 0xFF6897: Serial.println("0"); break;
case 0xFF30CF: Serial.println("1"); break;
case 0xFF18E7: Serial.println("2"); break;
case 0xFF7A85: Serial.println("3"); break;
case 0xFF10EF: Serial.println("4"); break;
case 0xFF38C7: Serial.println("5"); break;
case 0xFF5AA5: Serial.println("6"); break;
case 0xFF42BD: Serial.println("7"); break;
case 0xFF4AB5: Serial.println("8"); break;
case 0xFF52AD: Serial.println("9"); break;
case 0xFFFFFFFF: Serial.println(" REPEAT");break;
default:
Serial.println(" other button ");
}
}
void setup() {
irrecv.enableIRIn(); // Startet den Empfänger
lcd.begin(lcdsize[0], lcdsize[1]);
}
void loop() {
if (irrecv.decode(&results)) // Haben wir ein IR-Signal erhalten?
{
translateIR();
irrecv.resume(); // Erhalte den nächsten Wert
}
delay(990);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("----");
if(h<10){
lcd.print("0");
}
lcd.print(h);
lcd.print(":");
if(m<10){
lcd.print("0");
}
lcd.print(m);
lcd.print(":");
if(s<10){
lcd.print("0");
}
lcd.print(s);
lcd.print("----");
lcd.setCursor(0, 1);
if(tag<10){
lcd.print("0");
}
lcd.print(tag);
lcd.print(".");
if(monat<10){
lcd.print("0");
}
lcd.print(monat);
lcd.print(".");
lcd.print(jahr);
s++;
if(s>=60){
m++;
s=0;
}
if(m>=60){
h++;
m=0;
}
if(h>=24){
tag++;
h=0;
}
if(tag==31&monat==4){
monat++;
tag=1;
}
if(tag==31&monat==6){
monat++;
tag=1;
}
if(tag==31&monat==9){
monat++;
tag=1;
}
Ab hier kommen noch ca. 40 weitere Zeilen.
2 Antworten
Delay ist beim Mikrocontroller gar nicht so gut. Wie RareDevil schon geschrieben hat, brauchen die anderen Funktionen auch Zeit. Das kannst du aber gerade bei Arduino kaum aus dem Code herauslesen, weil dir die IDE gar nicht den "echten" Code zeigt und vor dem compilieren noch eine automatische Optimierung (optimize for size, wenn ich nicht irre) stattfindet. Dadurch wird die Uhr sehr ungenau.
Ein weiterer Nachteil von Delay ist, dass der Watchdog praktisch unbrauchbar wird, weil du ihn während des Delay nicht zurücksetzen kannst.
Die Methode, millis() zu pollen ist um Längen besser. Dabei muss man aber wissen und berücksichtigen, dass millis() nach knapp zwei Monaten überläuft.
Eine dritte Möglichkeit wäre, Interrupts zu verwenden. Der ATMega2560 hat 4 Stück 16bit Timer dabei, die von der Arduino IDE nicht für andere Sachen verwendet werden (im Gegensatz zum 8bit Timer0). Diese Variante ist allerdings etwas komplexer zu programmieren.
Ein ganz anderer Ansatz ist die Verwendung eines Uhrenchips. Der Klassiker ist der DS1307, der an den I2C Bus angehängt wird.
wenn Du ein Delay von 1000ms nutzt, benötigen die restlichen Befehle danach aber auch noch Zeit zur Abarbeitung. Dadurch läuft dein Programmzyklus insgesamt länger. Entweder musst Du alternativ zum Delay statt dessen mit millis() einen Timer bauen, der nicht den Programmcode für eine Sekunde anhält (Delay stoppt den Programmablauf für die Zeit), oder deine Laufzeit analysieren (Je Zyklus die Laufzeit messen und das Delay anpassen), was aber bedeutet, wenn was passiert, was länger dauert wie normal, verzögert sie doch wieder.