Millis funktioniert nicht

Hallo!

Hier erst mal der Code:

#include <math.h>

 
//Variablen deklarieren---------------------------------------------------------------------------------------------
 
long int Impuls=0;                  //Zählt die Anzahl der steigenden Flanken zur Messung der Drehzahl
long vorherigeMillisekunden = 0;    //Millisekunden - Variable für Drehzahl
long int Intervall = 2000;               //Zeit zwischen Drehzahl
int Drehzahl;                       //Drehzahlvar.
 

//Setup---------------------------------------------------------------------------------------------

void setup()
{  
  
    attachInterrupt(0, Impulszaehler, RISING);  //Wenn an Interrupt 0 (I/0 Eingang 2) steigende Flanke, dann Hilffunktion "Impulszaehler" ausführen
    Serial.begin(9600);    //Serielle Ausgabe initialisieren
} 


//Hauptprogramm---------------------------------------------------------------------------------------------

    void loop()
{
   
   unsigned long derzeitigeMillisekunden = millis();
   
   if(derzeitigeMillisekunden - vorherigeMillisekunden >= Intervall) {          //Wenn der Millisekundenzähler - vorherige Millisekunden >= Intervall
    vorherigeMillisekunden = derzeitigeMillisekunden;                           
    Drehzahl = (Impuls/3)*60;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)
   Serial.println(Drehzahl);
    Impuls=0;                                                                   //Impuls auf 0 setzen
    }
  
//Hilfsfunktionen---------------------------------------------------------------------------------------------
  
}
 
void Impulszaehler(){      //Hilfsfunktion Impulszählen bei steigender Flanke
  Impuls++;                //Variable Impuls inkrementieren    
}

Gemessen wird mit einem induktiven Sensor eine Drehzahl. Pro Umdrehung gibt es 3 Impulse.
Eigentlich müsste die Drehzahl doch auf Grund der millis-Funktion nur alle 2 Sek ausgegeben werden, richtig?
Die Ausgabe kommt aber dauerhaft!

Wo sitzt der Fehler?

Gruß
Morris

hi,

also mir gibt das programm alle 2 sekunden einen wert aus. keinen sinnvollen klarerweise, weil ich nichts am pin hängen hab', aber brav alle 2 sekunden...

gruß stefan

Komisch - an dem klappts nicht :drooling_face:

hi,

ich hab' winxp und ide 1.05.

klappt denn das blinkwithoutdelay bei Dir? kannst ja eine serielle ausgabe machen statt der led.
und nimm den sensor von pin.

gruß stefan

Die etwas unglückliche Stellung des Kommentars

//Hilfsfunktionen---------------------------------------------------------------------------------------------

lässt mich raten, dass bei dir im Originalcode die geschweiften Klammern anders sitzen ???

an dem klappts nicht :drooling_face:

ist mir leider etwas unverständlich.

Ich verstehe dein Problem so, dass die Serial.println - Ausgabe nicht alle 2 Sekunden, sondern erheblich häufiger ( "dauerhaft" ) kommt

michael_x:
Die etwas unglückliche Stellung des Kommentars

//Hilfsfunktionen---------------------------------------------------------------------------------------------

lässt mich raten, dass bei dir im Originalcode die geschweiften Klammern anders sitzen ???

Ne - passt so. Der Kommentar müsste hinter die geschweifte Klammer, aber das tut ja zum Programmablauf nichts zur Sache.

michael_x:
Ich verstehe dein Problem so, dass die Serial.println - Ausgabe nicht alle 2 Sekunden, sondern erheblich häufiger ( "dauerhaft" ) kommt

Korrekt

maeckes:
Hier erst mal der Code:
...
Wo sitzt der Fehler?

Bei dem geposteten Code erfolgt die Aktualisierung alle 2 Sekunden.
Der Fehler steckt also wohl nicht im geposteten Code.

Wenn das Programm größer ist als was Du gepostet hast und viel mehr RAM-Speicher verbraucht als der von dir gepostete Code, und das Programm aus einem nicht weiter erkennbaren Grund durchdreht, dann steht als Vermutung im Raum, dass Du möglicherweise zu verschwenderisch mit RAM-Speicher umgegangen bist und der Sketch nun mehr RAM benötigen würde als der Controller überhaupt eingebaut hat.

Füge mal diese Funktion in Deinen Code ein:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Und lasse Dir an verschiedenen Stellen im Code die Menge des verfügbaren RAM-Speichers anzeigen:

Serial.println(freeRam());

Was wird denn da angezeigt?

Nein - das Programm, was ich hier gepostet habe, ist 1zu1 das, was auf dem Arduino drauf ist.

Eventuell ein Defekt am Board?

Welche IDE nutzt du?

In der Arduino IDE sowie Visual Studio 2012 Pro gibt es kein Problem mit der Anzeige.

Kommentier mal im Setup die Zeile vom Interrupt aus.

maeckes:
Nein - das Programm, was ich hier gepostet habe, ist 1zu1 das, was auf dem Arduino drauf ist.

Eventuell ein Defekt am Board?

Welche Arduino-Version verwendest Du?
Welches Arduino-Board verwendest Du?
Verwendest Du eine alternative IDE?
Warum steht in Deinem Code "#include <math.h>" obwohl das in der Arduino-IDE nicht notwendig ist?

Was ist mit diesem Code, an dem ich einige kleine Modifikationen vorgenommen habe, aktualisiert der auch "ständig" und nicht nur alle zwei Sekunden?

#include <math.h>

 
//Variablen deklarieren---------------------------------------------------------------------------------------------
 
long Impuls=0;                      //Zählt die Anzahl der steigenden Flanken zur Messung der Drehzahl
unsigned long vorherigeMillisekunden = 0;    //Millisekunden - Variable für Drehzahl
#define Intervall 2000              //Zeit zwischen Drehzahl
int Drehzahl;                       //Drehzahlvar.
 

//Setup---------------------------------------------------------------------------------------------

void setup()
{  
    attachInterrupt(0, Impulszaehler, RISING);  //Wenn an Interrupt 0 (I/0 Eingang 2) steigende Flanke, dann Hilffunktion "Impulszaehler" ausführen
    Serial.begin(9600);    //Serielle Ausgabe initialisieren
} 


//Hauptprogramm---------------------------------------------------------------------------------------------

void loop()
{
   unsigned long derzeitigeMillisekunden = millis();
   
   if(derzeitigeMillisekunden - vorherigeMillisekunden >= Intervall) {          //Wenn der Millisekundenzähler - vorherige Millisekunden >= Intervall
    vorherigeMillisekunden = derzeitigeMillisekunden;                           
    Drehzahl = (Impuls/3)*60;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)
    Serial.println(Drehzahl);
    Impuls=0;                                                                   //Impuls auf 0 setzen
   }
  
//Hilfsfunktionen---------------------------------------------------------------------------------------------
  
}
 
void Impulszaehler(){      //Hilfsfunktion Impulszählen bei steigender Flanke
  Impuls++;                //Variable Impuls inkrementieren    
}

"long Impuls" sollte auch als volatile deklariert werden. Das wird aber nicht das Problem hier sein.

Testest du das mit dem Geber? Wenn ja welche Drehzahl?

evtl die serial Instanz mal vorm interrupt initialisieren.

und mal ansagen auf welchen arduino das laufen soll

Ist auch nicht das Kernproblem :
Beim Anfassen von "long Impuls" außerhalb der ISR sollten die Interrupt gesperrt werden, nur wenn byte benutzt wird geht es ohne.
Das wurde mir zumindest hier gesagt, wenn ich das richtig verstanden habe.

rudirabbit:
Ist auch nicht das Kernproblem :
Beim Anfassen von "long Impuls" außerhalb der ISR sollten die Interrupt gesperrt werden, nur wenn byte benutzt wird geht es ohne.
Das wurde mir zumindest hier gesagt, wenn ich das richtig verstanden habe.

Richtig, und nicht das Kernproblem, auch richtig.
Es muss schon ganz dumm kommen, dass das einen Fehler verursacht:
z.B. genau wenn Impuls gelesen wird, und die Variable den Wert 255 hat, kommt ein Interrupt.
Wenn zuerst das hi Byte gelesen wird und dann das lo, kann statt 255 oder 256 auch eine 0 rauskommen,
wenn zuerst das lo Byte gelesen würde, könnte auch eine 511 rauskommen.

Allerdings muss der Interrupt, der von 255 auf 256 hochzählt, genau den Lesebefehl unterbrechen.
Und dann muss auch einer zufällig hingucken :wink:

Wenn die weitere Behandlung von Impuls kritisch ist, schadet es nicht, das durch kurzzeitig geschlossene Interrupts in loop() abzusichern,
aber wenn es nur um eine Testausgabe auf SerialMonitor geht, ist die Wahrscheinlichkeit, dass man dieses Problem je bemerkt, sehr gering.

Als Erstes sollte "Impuls" volatile deklariert werden.

volatile long int Impuls=0;

Und Zweitens solltest Du sicherstellen, daß ALLE Zugriffe auf Impuls nicht unterbrochen werden können, also statt

    Drehzahl = (Impuls/3)*60;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)
    Serial.println(Drehzahl);
    Impuls=0;

besser

    noInterrupts();
    Drehzahl = (Impuls/3)*60;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)
    Impuls=0;
    interrupts();    
    Serial.println(Drehzahl);

Auch falls das noch nichts hilft, wenn Du das nicht tust wirst Du früher oder später merkwürdigen Fehlern in Deinem Programm hinterherlaufen.

Davon abgesehen ist

Drehzahl = (Impuls/3)*60;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)

deutlich schlechter als

Drehzahl = Impuls*20;                                                   //Drehzahl = (Impulse/2 Sek) * (60s/1min) * (1 Umdrehung / 3 Impulse)

Davon abgesehen würde ich an Deiner Stelle zwecks besserer Analyse auch die Werte von

derzeitigeMillisekunden, vorherigeMillisekunden und (derzeitigeMillisekunden - vorherigeMillisekunden >= Intervall)

per Serial ausgeben. Das ist garantiert sehr erhellend und sollte helfen den Fehler zu lokalisieren.