Zeit zwischen attachInterrupt (Watt berechnung)

Hallo liebe Leute,
irgendwie sitzt das Problem wohl mal wieder zu lange vorm Bildschirm... :~

Ich versuche die Zeit zu messen zwischen 2 Impulsen um dann daraus die Wattzahl zu errechnen. (S0-Stromzähler)
Und irgendwie sehe ich nicht wo es hapert..
Kann mir bitte jemand Licht ins Dunkle bringen ?
Ich bekomme keine Wattzahl angezeigt...

Hier mein Sketch:

volatile unsigned long last_irq0=millis();
volatile int bounceTime  = 100;
unsigned long millisBetween;
unsigned long lastMillis;
unsigned long prev_time;
double counter0 = 0;

double time;

unsigned long watt;

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, Count0, FALLING);
  Serial.print(F(" Starte Test ..."));
}

void loop()
{
 prev_time=millis();
 
 watt = 36000000 / time;
 Serial.print(F("time : "));
 Serial.println(time);

 Serial.print(F("Watt : "));
 Serial.println(watt);
 delay(1000);
 
}

void Count0()
{
  unsigned long act_irq0;
  act_irq0=millis();
  if(act_irq0 - last_irq0 > bounceTime)
  {
    millisBetween = lastMillis - prev_time;
       lastMillis = prev_time;
    counter0++;
    if(counter0>255) counter0 = 0;
    last_irq0=act_irq0;
  }
  time = millisBetween;
  
  
}

Cetax:
Und irgendwie sehe ich nicht wo es hapert..
Kann mir bitte jemand Licht ins Dunkle bringen ?
Ich bekomme keine Wattzahl angezeigt...

Versuchst Du den Code auf einem UNO laufen zu lassen?
Oder auf was für einem Board?

Jaein UNO .

das Zählen klappt super,
aber irgendwie happerts bei den millis()

Cetax:
das Zählen klappt super,
aber irgendwie happerts bei den millis()

Kann ein elektronischer Geber tatsächlich prellen, wie ein mechanischer Taster?
Wozu ist der Entprellcode gut?

Und was speicherst Du in "lastMillis" und was in "prev_time"?
Ich sehe eigentlich nur, dass Du die Werte dieser beiden Variablen gleichsetzt und beim nächsten Interrupt die Differenz bildest. Aber wenn Du die Variablen vorher gleichgesetzt hast, dann ist die Differenz der Variablen null. Was soll das?

Was hälst du von der herangehensweise das du im Interrupt nur den aktuellen millis speicherts wenn der Interrupt aufgerufen wurde und eine boolean Variable das ein Interruot war und du die berechung in der Loop machst.
In der Mainloop rechnest du dann und wenn du fertig gerechnet hast speicherst du dir den irq_millis als last_irq_millis und setzt den Boolean zurück für den nächsten Interrupt.
Man sollte die ISR so kurz wie nur möglich halten.
Gruß
Der Dani

Definiere alle Variablen, die Du sowohl im Hauptcode, als auch im Interrupt-Handler benützt, als "volatile", sonst kann es zu unvorhergesehenen Überraschungen kommen.

Irgendwie hast du jede Menge Variablen, in denen die immer gleichen Zeiten abgespeichert werden.

die Funktion von count ist mir unklar, lastMillis und prev_time auch.

Meiner Meinung nach sollte es gehen, wenn du die Interrupt Routine so kürzt:

void Count0(){
  unsigned long act_irq0=millis();
  if(act_irq0 - last_irq0 > bounceTime) {
    time = act_irq0 - last_irq0;
    last_irq0=act_irq0;
  }
}

Hallo allerseits,
erstmal vielen Dank für super Beteiligung...
Habe mich jetzt mal rangesetzt und von vorn angefangen, das ich einen nackten Sketch habe der die Impulse Zählt.

Aber ich kapiere es nicht, wie ich die millis() einsetzten muss, das ich eine difference bilden kann... :blush:

act_irq0=millis(); Ist der Start... Zählt also los, wenn ein Impuls kommt
last_irq0=act_irq0; Wäre doch der nächste Start, wenn also der zweite Impuls kommt... Oder nicht ?

Also müsste ich doch last_irq0 - act_irq0 machen um die difference zubekommen, oder nicht ?

Irgendwie sitzte ich hier wie ein Ochs vorm Berg :blush:

Hier der Sketch zum Impulse zählen:

volatile unsigned long act_irq0;
volatile unsigned long last_irq0;
volatile int bounceTime  = 100;

volatile double counter0 = 0;

double kwh = 0.000;  //Kilowattstunden
char tmp1[16];

void setup()
{
  Serial.begin(9600);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, Count0, FALLING);
  Serial.print(F(" Starte Test ..."));
}

void loop()
{
 display_Counter();
 
 delay(1000);
 
}

void Count0()
{
  act_irq0=millis();
  if(act_irq0 - last_irq0 > bounceTime)
  {
    counter0++;
    if(counter0>255) counter0 = 0;
    last_irq0=act_irq0;
  }  
}

void display_Counter(){
  kwh = counter0 / 1000;
    dtostrf(kwh, 1, 3, tmp1);
    
    Serial.print(tmp1);
    Serial.println(F(" KWh"));
}

Wo wird was eingesetzt ?? Kann jemand helfen ??
Vieleicht mit Erläuterung ? :blush:

DANKE

Cetax:
Wo wird was eingesetzt ?? Kann jemand helfen ??

vom Prinzip her ist Dein Stromzähler-Sketch nichts anderes als ein Fahrradtacho-Sketch.

Beim Fahrradtacho gibt ein Reed-Kontakt immer einen Impuls pro Radumdrehung, aus den Radumdrehungen pro Zeit kann man die Geschwindigkeit ermitteln.

Auch bei Dir kommen Impulse pro irgendwas, und aus den Impulsen pro Zeit kann man die Leistung in Watt berechnen.

Hier mal mein abgestrippter Fahrradtacho-Sketch mit einigen umbenannten Variablen und Funktionen:

Wegen der Berechnungsformel müßtest Du mal mit ein paar technischen Daten rüberkommen, die ist vermutlich falsch. Benötigt wird die Zahl "Impulse pro Kilowattstunde" Deines Stromzählers.

#define S0PIN 2
#define S0INTERRUPT 0

void setup(){
  Serial.begin(9600);
  pinMode(S0PIN, INPUT_PULLUP); 
  attachInterrupt(S0INTERRUPT, S0ISR, FALLING);
}

volatile unsigned int impulseCountSum;
volatile long impulseMillisSum;

unsigned long lastImpulseMillis;

void S0ISR()
{
  if (millis()-lastImpulseMillis>=25)  // 25ms Entprellzeit
  {
    impulseCountSum++;                 // einen Impuls zählen
    impulseMillisSum+=millis()-lastImpulseMillis;   // Zeit addieren
    lastImpulseMillis=millis();       // Zeit merken
  }
}

void wattAnzeige()
{
  unsigned int impulse;
  unsigned long zeit;
  float watt;
  noInterrupts();               // Interrupts sperren
    impulse=impulseCountSum;    // Zählvariable umkopieren
    impulseCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=impulseMillisSum;      // Zeitzähler umkopieren
    impulseMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();                 // Interrupts wieder zulassen
  if (impulse>0)
   watt = 3600000.0 / zeit * impulse;
  else
    watt=0.0;  
  Serial.println(watt);
}


unsigned long letztesIntervall=0;
void loop()
{
#define ANZEIGEINTERVALL 5000
  unsigned long diesesIntervall=millis()/ANZEIGEINTERVALL;
  // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
  if (letztesIntervall != diesesIntervall)
  {
    wattAnzeige();
    letztesIntervall=diesesIntervall;
  }
}

Und das kannst Du dann als Basis nehmen.

Was ich aus Deinem Sketch als Timings entnommen habe, eine Bouncetime von 100 und eine Aktualisierungsdauer von 1000 ms, erscheint mir ziemlich unsinnig zu sein. Eine Bouncetime von 100 ms würde ja bedeuten, dass höchstens 10 Impulse pro Sekunde gezählt werden können und eine Zähldauer von 1000 ms würde bedeuten, dass wenn nicht mindestens 1 Impuls in 1 Sekunde gezählt wird, die Wattanzeige 0 Watt anzeigt. D.h. der Anzeigebereich des Zählers wäre überhaupt nur von 1 Impuls/s bis 10 Impulse/s.

Mein Sketch ist so gemacht, dass Du die Zähldauer = Anzeigedauer getrennt einstellen kannst, über
#define ANZEIGEINTERVALL 5000
Ich habe im Sketch mal 5 Sekunden gesetzt, die immer gezählt wird, bis zur nächsten Aktualisierung,

Und die Entprellzeit, die mindestens zwischen zwei gezählten Impulsen vergehen muss, habe ich auf 25ms gesetzt. Wie sinnvoll das ist, na ja, fehlende technische Daten zu Deiner Zähleinrichtung...