INFO: Dieses Forum nutzt Cookies...
Cookies sind für den Betrieb des Forums unverzichtbar. Mit der Nutzung des Forums erklärst Du dich damit einverstanden, dass wir Cookies verwenden.

Es wird in jedem Fall ein Cookie gesetzt um diesen Hinweis nicht mehr zu erhalten. Desweiteren setzen wir Google Adsense und Google Analytics ein.

Antwort schreiben 
 
Themabewertung:
  • 0 Bewertungen - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Delay ersetzen durch millis oder Interrupt
27.11.2014, 23:19
Beitrag #1
Delay ersetzen durch millis oder Interrupt
Ich habe mal ein paar Moeglichkeiten zum Durchtesten zusammengestellt.
Duch Eingang 1-12 werden die Einzelnen Teilprogramme aktiviert.
Soll ein anderes Programm ausgewaehlt werden Eingang "0" kurz gegen Masse
ziehen.
Z.B. "E3" kurz gegen Masse so wird der Programmteil "Einschaltverzoegerung_Millis"
Durch Schalten "E3" gegen GND kann man jetzt das Schaltverhalten testen.
Durch die LED Pin 13 wird das Ergebnis angezeigt.
Nicht vergessen!!!! bei Test eines anderen Programmteil Mit "E0" altes Programm
teil deaktivieren.
Viel Vergnuegen.
#include <Timer1.h> // Timer 1 benutzen -------------------------
int E0 = 0; // Reset Auswahl
int E1 = 1;
int E2 = 2;
int E3 = 3;
int E4 = 4;
int E5 = 5;
int E6 = 6;
int E7 = 7;
int E8 = 8;
int E9 = 9;
int E10 = 10;
int E11 = 11;
int E12 = 12;
int LED = 13;
byte Takt0 = 0;
word Takt1 = 0;
byte Takt2 = 0;
byte Takt3 = 0;
byte Takt4 = 0;
byte M0 = 0;
byte M1 = 0;
word M2 = 0;
byte M3 = 0;
unsigned long M4 = 0;
void setup() // --------------------------------------------------
{
pinMode(E0, INPUT_PULLUP);
pinMode(E1, INPUT_PULLUP);
pinMode(E2, INPUT_PULLUP);
pinMode(E3, INPUT_PULLUP);
pinMode(E4, INPUT_PULLUP);
pinMode(E5, INPUT_PULLUP);
pinMode(E6, INPUT_PULLUP);
pinMode(E7, INPUT_PULLUP);
pinMode(E8, INPUT_PULLUP);
pinMode(E9, INPUT_PULLUP);
pinMode(E10, INPUT_PULLUP);
pinMode(E11, INPUT_PULLUP);
pinMode(E12, INPUT_PULLUP);
pinMode(LED, OUTPUT);
startTimer1(100000L); // 100000 µS = 0.1 Sekunde
}
void loop() // ---------------------------------------------------
{
if (digitalRead(E1) == LOW) bitSet(M2, 0);
if (digitalRead(E2) == LOW) bitSet(M2, 1);
if (digitalRead(E3) == LOW) bitSet(M2, 2);
if (digitalRead(E4) == LOW) bitSet(M2, 3);
if (digitalRead(E5) == LOW) bitSet(M2, 4);
if (digitalRead(E6) == LOW) bitSet(M2, 5);
if (digitalRead(E7) == LOW) bitSet(M2, 6);
if (digitalRead(E8) == LOW) bitSet(M2, 7);
if (digitalRead(E9) == LOW) bitSet(M2, 8);
if (digitalRead(E10) == LOW) bitSet(M2, 9);
if (digitalRead(E11) == LOW) bitSet(M2, 10);
if (digitalRead(E12) == LOW) bitSet(M2, 11);


if (bitRead(M2, 0) == 1) Monoflop_Millis();
if (bitRead(M2, 1) == 1) Monoflop_Interrupt();
if (bitRead(M2, 2) == 1) Einschaltverzoegerung_Millis();
if (bitRead(M2, 3) == 1) Einschaltverzoegerung_Interrupt();
if (bitRead(M2, 4) == 1) Subroutine_mit_millis();
if (bitRead(M2, 5) == 1) Subroutine_Interrupt();
if (bitRead(M2, 6) == 1) Takt_Interrupt_0_2_Sek();
if (bitRead(M2, 7) == 1) Takt_Interrupt_0_8_Sek();
if (bitRead(M2, 8) == 1) Takt_Interrupt_3_2_Sek();
if (bitRead(M2, 9) == 1) Takt_Interrupt_13_Sek();
if (bitRead(M2, 10) == 1) Kurze_Impulse_Interrupt();
if (bitRead(M2, 11) == 1) Laengere_Impulse_Interrupt();

if (digitalRead(E0) == LOW) M2 = 0; // Programmauswahl loeschen Spaeter raus
}
// #######################################################################
void Monoflop_Millis() { // Nachgetriggertes Monoflop mit millis
if(M0 == 0) {
M4 = millis() + 5000; //
digitalWrite(LED, HIGH);
M0 = 1;
}
if (millis() >= M4) digitalWrite(LED, LOW);
if (digitalRead(E1) == HIGH) M0 = 0;
}
// #######################################################################
void Monoflop_Interrupt() { // Nachgetriggertes Monoflop mit Interrupt
if(Takt4 >= 1) { // Kontakt Entprellen
digitalWrite(LED, HIGH);
if (Takt1 >= 50) digitalWrite(LED, LOW);
}
if (digitalRead(E2) == HIGH) Takt1 = 0; Takt4 = 0;
}
// #######################################################################
void Einschaltverzoegerung_Millis() { // Einschaltverzoegerung
if(M0 == 0) {
M4 = millis() + 5000; //
M0 = 1;
}
if (millis() >= M4) digitalWrite(LED, HIGH);
if (digitalRead(E3) == HIGH) {
digitalWrite(LED, LOW);
M0 = 0;
}
}
// #######################################################################
void Einschaltverzoegerung_Interrupt() { // Einschaltverzoegerung
if(Takt4 >= 1) { // Kontakt Entprellen
if (Takt1 >= 50) digitalWrite(LED, HIGH);
}
if (digitalRead(E4) == HIGH) {
digitalWrite(LED, LOW);
Takt1 = 0; Takt4 = 0;
}
}
// #######################################################################
void Subroutine_mit_millis() { // Aufruf Subroutine mit millis Takt 5 Sek.
if(M0 == 0) {
M4 = millis() + 5000; //
M0 = 1;
}
if (millis() >= M4 && M1 == 0 && M0 == 1) Sub_LED_Ein();
if (millis() >= M4 && M1 == 1 && M0 == 1) Sub_LED_Aus();
if (digitalRead(E5) == HIGH) {
M0 = 0;
digitalWrite(LED, LOW);
}
}
// #######################################################################
void Subroutine_Interrupt() { // Aufruf Subroutine Subroutine Takt 3 Sek.
if(M3 == 0) {
Takt0 = 0;
M3 = 1;
}
if (bitRead(Takt0, 5) == 1) Sub_LED_Ein(); // Alle 3.2 Sek.
if (bitRead(Takt0, 5) == 0) Sub_LED_Aus();
if (digitalRead(E6) == HIGH) {
M3 = 0;
digitalWrite(LED, LOW);
}
}
// #######################################################################
void Takt_Interrupt_0_2_Sek() { // Takt alle 0.2 Sek. Interrupt
if (M0 == 0) {
Takt0 = 0;
M0 = 1;
}
if (bitRead(Takt0, 1) == 1) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);
if (digitalRead(E7) == HIGH) M0 = 0;
}
// #######################################################################
void Takt_Interrupt_0_8_Sek() { // Takt alle 0.8 Sek. Interrupt
if (M0 == 0) {
Takt0 = 0;
M0 = 1;
}
if (bitRead(Takt0, 3) == 1) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);
if (digitalRead(E8) == HIGH) M0 = 0;
}
// #######################################################################
void Takt_Interrupt_3_2_Sek() { // Takt alle 3.2 Sek. Interrupt
if (M0 == 0) {
Takt0 = 0;
M0 = 1;
}
if (bitRead(Takt0, 5) == 1) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);
if (digitalRead(E9) == HIGH) M0 = 0;
}
// #######################################################################
void Takt_Interrupt_13_Sek() { // Takt alle 13 Sek. Interrupt
if (M0 == 0) {
Takt0 = 0;
M0 = 1;
}
if (bitRead(Takt0, 7) == 1) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);
if (digitalRead(E10) == HIGH) M0 = 0;
}
// #######################################################################
void Kurze_Impulse_Interrupt() { // Impulsfolge mit Interrupt
if (Takt2 != 156 && Takt2 != 158 && Takt2 != 160) digitalWrite(LED, LOW);
if (Takt2 == 156 || Takt2 == 158 || Takt2 == 160) digitalWrite(LED, HIGH);
}
// #######################################################################
void Laengere_Impulse_Interrupt() { // Impulsfolge mit Interrupt
if (Takt3 >= 35 && Takt3 <= 85) digitalWrite(LED, HIGH);
if (Takt3 < 35 || Takt3 > 85) digitalWrite(LED, LOW);
}
// #######################################################################
void Sub_LED_Ein() { // SUB LED Ein
digitalWrite(LED, HIGH);
M1 = 1; M0 = 0;
}
// #######################################################################
// ............... SUB LED Aus .......................................
void Sub_LED_Aus() { // SUB LED Aus
digitalWrite(LED, LOW);
M1 = 0; M0 = 0;
}
// #######################################################################
ISR(timer1Event) // Timer Interrupt 0.1 Sekunde
{
resetTimer1(); // Interrupt Timer wieder auf Anfangswert
++Takt0;
++Takt1; // Zykluszeit + 0.1 Sekunde
++Takt2;
++Takt3;
++Takt4; // Kontakt-Entprellung
}
// #######################################################################
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 00:55
Beitrag #2
RE: Delay ersetzen durch millis oder Interrupt
Das mit den millis kann nach etwa 50 Tagen schief gehen, wenn man's so macht. Das sollte doch inzwischen bekannt sein.
Gruß,
Thorsten

Falls ich mit einer Antwort helfen konnte, wuerde ich mich freuen, ein paar Fotos oder auch ein kleines Filmchen des zugehoerigen Projekts zu sehen.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 08:14
Beitrag #3
RE: Delay ersetzen durch millis oder Interrupt
Beste Variante meiner Ansicht nach ist die Lösung mit z.B. Zählen von Interrupts statt dem millis()

Liebe Grüße,

xuino
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 09:49
Beitrag #4
RE: Delay ersetzen durch millis oder Interrupt
Sollte auch nur ein Beispiel sein wie man ein Delay ersetzen kann.
Da ich auch erst seit ca. 4 Monaten einen Arduino programmiere und vorher
keinerlei Erfahrung mit "C" hatte; habe groessere Programme mit Powerbasic
und IOW56 als Chip programmiert.
Ich denke an die Neueinsteiger die im Forum immer mal diese Fragen haben.
Besser ist es immer ein funktionierendes Beispiel mal durchzutesten, das man dann
für seine eigenen Zwecke anpassen kann.
Vielleicht sollte man eine Datenbank anlegen mit kurzen Beispielen.
Die Hilfe der IDE ist manchmal sehr ????
In der naechsten Zeit wollte ich noch ein paar Beispiele posten.

Uebertragung von dem Monitor der IDE nach Arduino und Speichern im EE-Prom
als Configurationsdaten. Daten als Byte, Word und Long

AD-Wandler mit I2C und MCP3424
AD-Wandler mit SPI und AD7793
AD-Wandler mit SPI und ADS1248

Gruss.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 09:53 (Dieser Beitrag wurde zuletzt bearbeitet: 28.11.2014 10:22 von Thorsten Pferdekämper.)
Beitrag #5
RE: Delay ersetzen durch millis oder Interrupt
(28.11.2014 08:14)xuino schrieb:  Beste Variante meiner Ansicht nach ist die Lösung mit z.B. Zählen von Interrupts statt dem millis()

Hi,
genau das macht millis() eigentlich auch:
Code:
volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
    // copy these to local variables so they can be stored in registers
    // (volatile variables must be read from memory on every access)
    unsigned long m = timer0_millis;
    unsigned char f = timer0_fract;

    m += MILLIS_INC;
    f += FRACT_INC;
    if (f >= FRACT_MAX) {
        f -= FRACT_MAX;
        m += 1;
    }

    timer0_fract = f;
    timer0_millis = m;
    timer0_overflow_count++;
}

unsigned long millis()
{
    unsigned long m;
    uint8_t oldSREG = SREG;

    // disable interrupts while we read timer0_millis or we might get an
    // inconsistent value (e.g. in the middle of a write to timer0_millis)
    cli();
    m = timer0_millis;
    SREG = oldSREG;

    return m;
}
...mit dem Unterschied zu den meisten Implementierungen, die man so sieht, dass bei der Abfrage richtigerweise die Interrupts deaktiviert und wieder aktiviert werden. Außerdem sind die Variablen als volatile deklariert, was auch noch ein paar Fehlerquellen ausschließt. Dann fällt mir dazu noch ein, dass die millis() sozusagen langzeitstabiler sind, als die Lösung mit dem reset eines Timers, da man den zugrunde liegenden Timer einfach immer weiterlaufen lässt.
Gruß,
Thorsten

(28.11.2014 00:55)Thorsten Pferdekämper schrieb:  Das mit den millis kann nach etwa 50 Tagen schief gehen, wenn man's so macht. Das sollte doch inzwischen bekannt sein.
Hi,
vielleicht wurde nicht ganz klar, worauf sich das bezieht. Im Originalposting sieht man etwas wie das hier:
Code:
if(...) {
  M4 = millis() + 5000;
  ...
}
if (millis() >= M4) ...;
Das prinzipielle Problem an der Geschichte ist, dass die millis nach 2^32 Millisekunden (ungefähr 49 Tagen 17 Stunden) überlaufen. Jetzt nehmen wir mal an, dass der Arduino schon fast diese Zeit lang an war. 4 Sekunden vor dem Überlauf passiert dann folgendes:
M4 wird 2^32 - 4000 + 5000 = 2^32 + 1000 = 1000 (2^32+1000 passt nicht rein, also Überlauf).
Gleich danach, sagen wir mal 10 Millisekunden, wird aus
millis() >= M4 => 2^32 - 4000 + 10 >= 1000 => true
Das geht auch die nächsten vier Sekunden so weiter. D.h. ungefähr 5 Sekunden lang wird die Bedingung jedesmal wahr sein, obwohl noch gar keine 5 Sekunden seit "M4 = millis() + 5000" vergangen sind!

Das Problem kann man ganz einfach vermeiden, indem man es so hinschreibt:
Code:
if(...) {
  M4 = millis();
  ...
}
if (millis() - M4 >= 5000) ...;
Mathematisch ist das erstmal genau dasselbe. Aber betrachten wir's mal wieder 4 Sekunden vor dem Überlauf:
4 Sekunden vor dem Überlauf passiert dann folgendes:
M4 wird 2^32 - 4000.
Nach 10 Millisekunden sieht jetzt die Bedingung so aus:
millis() - M4 >= 5000 => (2^32 - 4000 + 10) - (2^32 - 4000) >= 5000
=> 10 >= 5000 => false
Überläufe treten hier keine auf.
Wer das bis hierher verfolgt hat, sagt vielleicht: "Aber Moment mal, viereinhalb Sekunden später habe ich aber ein Überlauf, und dann klappt das wieder nicht!". Schau mer mal (millis ist jetzt 500, da 2^32 - 4000 + 4500 überläuft und 500 übrig bleibt):
millis() - M4 >= 5000 => (500) - (2^32 - 4000) >= 5000
Tja, wie geht das weiter? Subtraktionen werden durch Addition des 2er-Komplements ausgeführt. Man kann auch sagen, zuerst wird die nagative Zahl von 2^32 abgezogen. Es ergibt sich also:
(500) - (2^32 - 4000) = (500) + 2^32 - (2^32 - 4000)
= (500) + 2^32 - 2^32 + 4000 = 4500
...und das alles sozusagen ohne Überläufe.
4500 >= 5000 => false, also immer noch richtig.
Wer will, der kann das ganze auch direkt im Binärsystem nachrechnen. Ich würde dann aber mit nur 4 Bit rechnen.

Die einzige Voraussetzung ist, dass man es "oft genug" aufruft und dass das Warte-Intervall wesentlich kleiner als die 49 Tage ist. "Oft genug" ist auf jeden Fall bei einmal in der Woche erfüllt.

Gruß,
Thorsten

Hallo nochmal,
ich wollte noch schreiben, warum ich so darauf rumreite:
Das fiese an diesem Fehler ist: Man kann das ganze einen ganzen Monat lang gründlich testen und es passiert nichts. Möglicherweise passiert auch nichts, wenn es das erste Mal überläuft (je nachdem wie sich die Werte genau ergeben). Aber irgendwann schlägt es garantiert zu und dann hat man ein "nicht nachvollziehbares Problem".
Gruß,
Thorsten

Falls ich mit einer Antwort helfen konnte, wuerde ich mich freuen, ein paar Fotos oder auch ein kleines Filmchen des zugehoerigen Projekts zu sehen.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 10:58
Beitrag #6
RE: Delay ersetzen durch millis oder Interrupt
super gut erklärt!

[Bild: thumbs-up.jpg]
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
28.11.2014, 11:02
Beitrag #7
RE: Delay ersetzen durch millis oder Interrupt
(28.11.2014 10:58)HaWe schrieb:  super gut erklärt!
Danke!

Falls ich mit einer Antwort helfen konnte, wuerde ich mich freuen, ein paar Fotos oder auch ein kleines Filmchen des zugehoerigen Projekts zu sehen.
Alle Beiträge dieses Benutzers finden
Diese Nachricht in einer Antwort zitieren
Antwort schreiben 


Möglicherweise verwandte Themen...
Thema: Verfasser Antworten: Ansichten: Letzter Beitrag
  mit if aus do-while oder while Schleife aussteigen Nafetz 6 105 05.12.2016 21:41
Letzter Beitrag: Pit
  while Schleife nach sleep mode interrupt tklaus 13 247 23.11.2016 17:40
Letzter Beitrag: Tommy56
  NRF24L01 Interrupt MeisterQ 22 515 02.11.2016 15:50
Letzter Beitrag: MeisterQ
  Welche IDE? Arduini.cc oder .org Bilbo 1 208 17.10.2016 21:03
Letzter Beitrag: ardu_arne
  Ardublock übertragt nicht an IDE oder UNO R3 tobi83 5 340 16.10.2016 14:07
Letzter Beitrag: Pit
  Interrupt matthias3579 5 221 15.10.2016 13:23
Letzter Beitrag: hotsystems
  Unterschiedliche Programme durch Switch/ Case SpeedShifter 26 608 04.10.2016 15:29
Letzter Beitrag: SpeedShifter
  Interrupt und Sicherung der Prozessorregister MKc 5 224 31.08.2016 11:17
Letzter Beitrag: MKc
  Programmspeicher auf i2c_EEPROM oder SD_Card erweitern? avoid 11 346 11.07.2016 15:46
Letzter Beitrag: avoid
  Delay nurmili 2 218 10.07.2016 16:55
Letzter Beitrag: nurmili

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste