Interrupt

Hallo Leute,
Ich habe als Projekt eine Grundumsatzmessung zu realisieren mit verschiedenen Sensoren.
Da aber der CO2 und der O2 unterschiedlich lang messen müssen muss (CO2 sowei berechnung des Flusses 20ms und O2 nur alle 5s).
Wenn ich das Programm mit Delay() ausführe wie bisher, sind die Messungen jedoch zu langsam und zu ungenau da die Sensoren verschiedene ansprechzeiten haben.
Ich verwende einen Arduino UNO und dachte daran dieses Problem mit einem Interrupt zu lösen.

Da ich mich mit arduino so gut wie kaum auskenne und mit den Angaben zu Interrupts nicht viel anfangen konnte wollte ich euch um Tipps oder mögliche Hilfestellungen bitten um mein Problem lösen zu können.

Ich hoffe ihr könnt mir weiterhelfen.

Hier mein Derzeitiger Programmcode:

#include <SDP6x.h>

#include <SoftwareSerial.h>
#include <Wire.h>

char buf[50];
int state = 0;
float difPressure;
String co2wert;
String o2wert;
int i = 0;
float dt = 0.06;
float volumen = 0;
float pres1 = 0;
float pres2 = 0;
float dif = 0;
int n = 0;
float avolumen = 0;
int l = 0;
float flow = 0.0;


SoftwareSerial co2Serial(2, 3);
SoftwareSerial o2Serial(4, 5);

void setup() {

  Serial.begin(9600);
  co2Serial.begin(9600);
  o2Serial.begin(9600);
  Wire.begin();
  difPressure = 0.0;

}

void loop() {

while(true){
  
  i = i + 1;
  l = l + 1;
  
  // Geradengleichung 25Pa Sensor.....fluss = 0.143267 * difPressure + 0.003008;
  
  // Ausgabe des Differenzdruckes:
  
  difPressure = SDP6x.GetPressureDiff();

  Serial.print("Differenzdruck:  ");
  Serial.print(difPressure);
  Serial.print(" Pa ");

  // Ausgabe und Brechnung des Volumsfluss:

  flow = 0.12137 * difPressure + 0.026848;

  Serial.print("     Volumenfluss:  ");
  Serial.print(flow);
  Serial.print(" l/s ");

  // Ausgabe und Berechnung des Volumens:

  if (i == 1)  {
    pres1 = 0.12137 * difPressure + 0.026848;

  }
  if (i > 1)   {
    pres2 = 0.12137 * difPressure + 0.026848;

    dif = (pres2 + pres1)/2;
    volumen = volumen + dif * dt;

    pres1 = pres2;

//    Serial.print("     Volumen:  ");
//    Serial.print(volumen);

  } 
  
  if (difPressure < 0.1) {
    if (l > 0) {
      n = n + 1;
      avolumen = volumen;
      volumen = 0;
      l = 0;
     
    }
  } 

  
  // Ausgabe und Berechnung der O2 und CO2 Konzentrationen:
  
  // Ausgabe und Berechnung der O2-Konzentration
  
  o2Serial.listen();

  if (o2Serial.isListening()) {
    Serial.print("      O2:  ");

    sprintf(buf, "M 0 \r\n");
    sprintf(buf, "O\r\n");
    o2Serial.print(buf);  //Befehl wird dem Sensor übergeben
    delay(80);
    while (o2Serial.available()) {

      char c = o2Serial.read();

      if (c == 'O' && state == 0) {
        state = 1;
      }
      else if (state == 1) {  // blank after Z is ignored
        state = 2;
      }
      else if (state == 2) {
        o2wert = c;
        state = 3;
      }
      else if (state == 3) {
        o2wert = o2wert + c;
        state = 4;
      }
      else if (state == 4) {
        o2wert = o2wert + c;
        state = 5;
      }
      else if (state == 5) {
        o2wert = o2wert + c;
        state = 6;
      }
      else if (state == 6) {
        o2wert = o2wert + c;
       Serial.print((float)o2wert.toInt()/10,3);
       Serial.print(" %   ");
        state = 0;
      }

    }

  }

  Serial.print("      O2 Ausatem:  ");
  Serial.print(((float)o2wert.toInt()/10)-((float)co2wert.toInt()/1000)); 
  Serial.print(" % ");
  

  // Ausgabe und Berechnung der CO2-Konzentration

  co2Serial.listen();

  if (co2Serial.isListening()) {
    Serial.print("     CO2:  ");

    sprintf(buf, "K 1 \r\n");
    sprintf(buf, "Z\r\n");
    co2Serial.print(buf);
    delay(80);

    while (co2Serial.available()) {

      char c = co2Serial.read();

      if (c == 'Z' && state == 0) {
        state = 1;
      }
      else if (state == 1) {
        state = 2;
      }
      else if (state == 2) {
        co2wert = c;
        state = 3;
      }
      else if (state == 3) {
        co2wert = co2wert + c;
        state = 4;
      }
      else if (state == 4) {
        co2wert = co2wert + c;
        state = 5;
      }
      else if (state == 5) {
        co2wert = co2wert + c;
        state = 6;
      }
      else if (state == 6) {
        co2wert = co2wert + c;
        Serial.print((float)co2wert.toInt()/1000,3);
        Serial.print(" % ");
        Serial.print("  ");
        Serial.println("  ");
        state = 0;
  
      }

    }

  } 

  //Berechnen des Grundumsatzes:

  if(avolumen > 0.1){
    
    Serial.print(" VolZug: ");
    Serial.print(avolumen);

    Serial.print("      Grundumsatzumsatz: ");
    Serial.print((((float)o2wert.toInt()/10)-((float)co2wert.toInt()/1000))*4.83*avolumen);
    Serial.println(" kcal/kg ");
  
  }
  
}
    
}

delay() ist eigentlich nur für Beispielcode geeignet und das Problem kannst Du eh viel besser mit der non-blocking millis() lösen. Interrupts wirst Du vermutlich nicht brauchen.

Ganz kurz das Codebeispiel "blink without delay" lesen, um das Konzept zu verstehen.

Hallo,

stellvertretend hier gefragt. Wo kommen neuerdings immer diese Konstrukte her?

void loop() {
  while(1) {

  ...
  ...

  }
}

Zum eigentlichen Thema.
Die Sensoren sollen nur unterschiedlich lang messen?
Spielt es wirklich eine Rolle ob die einzelne Messung 20,0ms oder 20,1ms dauert?

Wo kommen neuerdings immer diese Konstrukte her?

Wahrscheinlich per copy & paste aus Tutorials für Controller die keine loop() haben.

@Doc_Arduino nein macht keinen unterschied

Ich verstehe dein Problem nicht so ganz warum es ein Problem ist das die Sensoren unterschiedliche Ansprechzeiten haben.
Vlt kannst du das kurz erklären.

Hallo,

gut, dann reicht die millis() Genauigkeit vollkommen aus.
Du musst dir jetzt einzelne Funktionen bauen die immer zyklisch aller 20ms oder aller 5s aufgerufen werden.
Da ich bei deinem Sketch nicht durchblicke, kann ich dir nur eine Vorlage geben. Bitte auch mit millis selbst nochmal beschäftigen.

Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung
http://forum.arduino.cc/index.php?topic=423688.0

Dein gesamter Code darf bei sowas keine hartes Delay haben. Sonst gehen zum Bsp. lesende serielle Daten verloren.
Deine erste while(true) ist auch überflüssig, loop ist deine Endlosschleife.

void setup() {

}

void loop() {

  messen_aller_20ms();

}


void messen_aller_20ms ()
{
  static unsigned long last_millis = 0;
  const unsigned int intervall = 20;

  if (millis() - last_millis < intervall)  return;
  last_millis = millis();

  // ab hier das was die Funktion zyklisch machen soll
  // ...
  // ...
}

@Hypec da bei meiner Messung die CO2-Konzentrartion und der Volumsfluss, welcher mittels Druckdifferenzsensor von hoher Bedeutung für die weitere Berechnungen sind müssen diese Messwerte möglichst genau sein.....wenn ich jetz in dem Programmcode so wie ich ihn habe die Abfragezeit geringer mach, dann kommt der langsamere O2 Sensor nicht mehr mit dem messen nach und die gesammten Messergebnisse werden noch mehr verfälscht.

Gibt es ein Signal, das die Beendigung einer Messung des CO2 Sensors anzeigt?

Hallo,

es wäre auch gut zu wissen welche Sensoren das genau sind (Link, Datenblatt) und vielleicht nochmal eine genauere Ablaufbeschreibung was das Programm im Detail machen soll. Wenn ich die Antwort von thmi lese ist die Handhabung der Sensoren selbst wohl schon nicht ohne.

Bei dem CO2 Sensoren handelt es sich um einen SprintIR CO2 Sensor:

Beim O2 Sensor handelt es sich um einen CM0201 UV FLUX Sensor :

Des weiteren wird für meine Messung ein Sensirion SDP610 125Pa Druckdifferenz-Sensor verwendet mit dem ich in Kombination eines Atemwiderstandes das Volumen bzw den Vollumsfluss berechne.

Wichtig für die Messung sind die CO2 Konzentration und das Volumen, wie schon erwähnt haben diese sensoren unterschiedliche Ansprechzeiten und über Delay wird die Messung ungenau. Um auf den Grundumsatz rückrechnen zu können müssen die Werte für CO2 und das Volumen so genau wie möglich sein, da diese quasi die ganze Messung entscheiden.

Da der O2 Wert der Luft ca gleich bleibt ist der O2 Wert für diese Messung nicht so wichtig, deswegen soll dieser auch nur alle 10 Sekunden Messen und bis zur nächsten O2-Messung sollte der alte Wert für die Berechnung des Grundumsatzes verwendet werden.

Grundumsatz = O2-CO24.83Volumen

Das ist was mein Projekt im grundlegenden ausführen sollte.

Also sollte alle 20 msek ein neuer wert für die CO2 Konzentration und des Volusflusses geliefert werden.
Der Volumsfluss wird für den Ausatemvorgang aufsummiert um das Volumen zu erhalten.
Der Grundumsatz soll dann nach jedem Ausatemvorgang berechnet werden, sprich nach jener Zeit wenn die der Differenzdruck-wert des Differenzdruck-Sensors wieder einen negativen Wert (Einatemvorgang) erreicht.
Wird dieser neg. Wert erreicht soll der Grundumsatz mit den gemessenen Werten von dieser Atemperiode berechnet werden, sprich dem CO2-Gehalt und dem aufsummierten Volumsfluss(Volumen). Für den O2-Wert soll eben nur jener Wert verwendet werden der alle 10sek gemessen wird.

Ich hoffe ich habe es etwas verständlicher machen können was mein Programm machen sollte bzw. wie die Messung abläuft soll.

Du kennst den Unterschied zwischen einer URL und einem Link?

Gruß Tommy

Dem User Manual nach (11.3 Polling Mode) mißt der Sensor nur 20 mal pro Sekunde. Es wäre also unsinnig, häufiger Daten anzufordern. Zur Überprüfung kann man ja die übertragenen Werte inspizieren.

Im "streaming mode" sendet der CO2 Sensor die Messwerte automatisch. Man muß sich um nichts kümmern, nur die eintreffenden Daten konvertieren und als aktuellen CO2 Wert speichern.

Wenn so viele serielle Schnittstellen verwendet werden, würde ich einen Mega nehmen. Der hat 4 Serials in Hardware, da geht nichts verloren.