Heart Rate Monitor Sensor SKU: SEN0213 mit Arduino Uno

Hi,

ich habe den Heart Rate Monitor Sensor SKU: SEN0213 von DFrobot Heart_Rate_Monitor_Sensor_SKU__SEN0213-DFRobot --> (Code Sample 1)mit dem Arduino Uno über den AnalogPin angeschlossen.

Wie ihr sehen könnt, kann damit ein EKG-Signal generiert werden indem ich den Anolgwert auslese. Diese Auswertung kann ich direkt über den Serial Plotter von der IDE aisgeben, doch ich würde gerne die EKG daten via ZigBEE an einem anderen Knoten (am PC verbunden) senden, damit dieser es anzeigen kann. Meine Frage ist folgende: Wenn ich nur den Analogwert weitersende (y-Achse) bringt mir das nicht viel, ich bräuchte auch zum jeweiligen Analogwert auch die millisekunden. Weil wenn ich es z.b. in Excel auswerte als EKG graph, brauche ich zwei Parameter( y-Achse= Analogwert, x-Wert= Zeit für jeden Messwert).
Wisst ihr eventuell wie ich die Zeit von jedem Messwert rausbekomme? Dachte an millis() , doch in dem Code kann ich es nicht sehen, und der Arduino Plotter zeigt eine Zeit an, auf der X-Achse die ich in dem Code nicht abfrage (sample Code 1 aus dem obigen link):

/*!

* @file HeartRateMonitor.ino

* @brief HeartRateMonitor.ino  Sampling and ECG output 

*

*  Real-time sampling and ECG output

* 

* @author linfeng(490289303@qq.com)

* @version  V1.0

* @date  2016-4-5

*/

const int heartPin = A1;

void setup() {

  Serial.begin(115200);

}

void loop() { 

int heartValue = analogRead(heartPin);

Serial.println(heartValue);

delay(5);

}

milito:
Wisst ihr eventuell wie ich die Zeit von jedem Messwert rausbekomme? Dachte an millis() , doch in dem Code kann ich es nicht sehen, und der Arduino Plotter zeigt eine Zeit an, auf der X-Achse die ich in dem Code nicht abfrage (sample Code 1 aus dem obigen link):

Also laut deinem Code ca. alle 5ms. Genauer könntest du es mit delayMicroseconds() gestalten.

Link: delayMicroseconds() - Arduino Reference

Was du auch machen könntest nach jeder Messung mit millis() oder micros() die Zeitstoppen und diese auch Seriell schicken. Je nach dem was du brauchst.

Besser ist, glaube ich, wenn man das delay lässt da es eine weile geht bis ein unsigned long übertragen ist. Aber falls ich falsch liege verbessert mich ruhig.

Hi danke für dein Feedback, also das ist der Sample Code von DFrobot, den habe ich zum Testen übernommen. Also laut dem Code wird ja kein Zeitstempel gesetzt, doch der Serial Plotter (Arduino IDE) schafft es irgendwie die Zeit darzustellen.
Ich wollte halt die Zeit für jeden Messpunkt haben z.b:
1.Messwert - 5ms
2.Messwert- 10ms
3.Messwer- 15ms

d.h. millis nach dem delay setzen oder vor dem delay?

milito:
d.h. millis nach dem delay setzen oder vor dem delay?

Vor dem delay! ansonsten misst du die Zeit von dem Delay auch noch mit.

Was eventuell Hilfreich wäre eine Startzeit zuspeichern. Im Setup eine unsigned long variable mit millis() beschreiben. Diese natürlich erst am Ende des Setups.

Wenn du nun Serial.println(aktuelle Zeit - Startzeit) druckst bekommst du nacheinander ungefähr das was du möchtest.

Ich habe das allerdings nicht getestet, ein Feedback wäre Klasse von dir :smiley:

MfG
bdorer

Hi okay mit dem millis nach dem delay wäre es folgendermaßen:

const int heartPin = A1;

void setup() {

  Serial.begin(115200);

}

void loop() {

int heartValue = analogRead(heartPin);
unsigned long timeMeasuringPoint = millis();

Serial.print(heartValue);
Serial.print(";");
Serial.print(timeMeasuringPoint);
delay(5);

}

--> Das war dein erster Ansatz

Oder mit Start und EndZeit:

const int heartPin = A1;
unsigned long start, finished;
void setup() {

  Serial.begin(115200);
  start = millis();

}

void loop() {

int heartValue = analogRead(heartPin);
unsigned long timeMeasuringPoint = millis();
finished = millis();
Serial.print(heartValue);
Serial.print(";");
Serial.print(start - finished);
delay(5);

}

--> Müsste ich die Start Zeit nicht im Anfang der Loop schleife setzen?

Hi

Wenn Du alle 5ms eine Messung ausführen willst, wäre meine Herangehensweise ungefähr so:
Setup:

  • aktuelle Zeit merken

  • Warte, bis die Wartezeit vorbei ist (millis()-merkzeit>=wartezeit)

  • aktuelle Zeit merken

  • Deine Messung auslösen

  • Werte seriell ausgeben

  • eine LED blinken lassen (oder so)

  • Rücksprung zur Warteschleife

Ich warte, bis die 5ms 'seit der letzten Warterei' vorbei sind, das Ende ist immer genau 5ms nach dem letzten Ende
Dann merke ich mir die aktuelle Zeit (ggf. besser, zähle zu der Merkzeit einfach die Wartezeit hinzu)
Jetzt erst mache ich zeitintensive Aufgaben, muß halt in 5ms fertig werden
Dann springe ich wieder auf die Warterei, um das Ende des 5ms-Takt abzuwarten

Wenn noch Mehr gemacht werden soll, statt Warten nur mit einer IF verzweigen und dort die zeitlich relevanten Aufgaben abarbeiten.

MfG

Hi postmaster-ino vielen Danke für dein Feedback, das verstehe ich nicht ganz, kannst du es vllt. anhand eines Beispiels erklären. Was hältst du von den Vorangehensweisen, die ich gepostet habe?

In der IDE gibt es ein Beispiel BlinkWithoutDelay, da kannst Du anstelle des Blinkens die Messung durchführen und die Ausgabe machen.

Hi

Joha - Mal wieder 'nur eine State-Maschine' - war mir aber, bis Du Das so sagtest, nicht aufgefallen :o

@milito
Bei Deinem Sketch verstehe ich nicht wirklich, wieso Du Dir mehrfach millis() merkst.
Weiterer Nachteil dabei: millis() kann dabei auch unterschiedliche Werte haben, da das Programm halt auch Zeit braucht.
Auch machst Du Nichts (ok, nicht Viel) mit den gemerkten Werten.
Wenn ich Deinen Code recht interpretiere, bekommst Du eine analoge Spannung 'äquivalent zum Herzschlag' - also so eine EKG-Kurve, halt die Einzelpunkte da drauf.
Mit dem Blink_without_delay wirst Du die 5ms genau einhalten können, so, wie Du Dir Das vorgestellt hast.

MfG

Hi vielen Dank für den Tipp an euch mit dem BlinkwithoutDelay, das stimmt, dass es wäre geschickter ohne delay zu arbeiten. Ich habe gelesen, dass man delay eigentlich vermeiden sollte, stimmt das?- da man die ganzen resourcen blockiert.

ja genau die analoge Spannung ist äquivalent zum Herzschlag, das ist richtig. Doch damit die Werte für den Empfänger brauchbar sind muss ich zu jedem Messpunkt auch die Zeit mitsenden. D.h. mein currentMillis wäre der Zeitstempel für den Jeweiligen Messpunkt, wenn ich das richtig verstehe :).

hab es ausprobiert, funktioniert einigermaßen gut, habe zwei Schönheitsfehler:

1.Bei millis läuft die Zeit immer weiter, auch wenn ich den Serial Monitor neustarte, da millis bis 49 Tage läuft(solange man nicht die Versorgung abzieht) --> Gibt es da keine andere möglichkeit die Zeit abzugreifen?

  1. Da ich auch die ZigBee-Verbindung vor jedem Senden überprüfen muss, dauert es leider länger als 10ms.

Hi

Du kannst vom millis()-Wert eine beliebige Zahl abziehen - bestimmt auch die letzte Einschaltzeit.
Wenn Du alle 5ms eine Aktion auslösen willst, aber pro Runde 10ms brauchst, wird's echt eng.

Wie lange braucht diese Prüfung, wenn die Verbindung besteht?
Bzw. wenn Du NICHT prüfst, was passiert dann beim Senden und kannst Du Das bemerken und in der nächsten Runde das Senden abstellen?

MfG

Hi also ich brauche mit dem Prüfen insgesamt 16ms, ohne dem Prüfen 10ms. 10ms sind auch noch ausreichend.

Wenn ich nicht prüfe, kann ich nicht sehen, ob ich verbunden bin, muss dann auf gut Glück senden und schauen, ob was ankommt. Das das ZigBee eine LED hat, die anzeigt, dass ich verbunden bin unddazu brauche ich diese CheckFunktion.

Hi eine Frage,

wenn ich Serial.print(currentTime-previousTime); ausgebe ergibt es immer 0.
Das sind zwei unsigned long variablen. Ich bräuchte die DIfferenz, d.h. (currentTime-previousTime) *counter hätte ich die Zeit für jeden Messpunkt, doch leider ergibt die Differenz immer 0. Wisst ihr woran es liegen kann?

Übrigens wenn ich einen Overflow der 49Tage habe, renne ich damit nicht in Probleme, wenn ich den millis nehme für den Timestamp?

Hi

Da diese Variablen in Deinen Code-Fragmenten nicht vorhanden sind, kann ich Dir auch nicht sagen, wo Du Welche davon falsch benutzt.
Sieht aber so aus, daß Du BEIDE immer wieder auf den gleichen Wert setzt - ggf. aktualisierst Du previous bereits vor diesem Seria.print, musst also nur die Aktualisierung hinter das Print verschieben.

MfG

if(ZigBee.status() == CONNECT)
  {
    int counterTime= 0;
    currentTime = millis();
    digitalWrite(LED, HIGH);
    if(currentTime - previousTime >= Interval)
    {
      measureTime = (currentTime-previousTime)*counter;
      previousTime = currentTime;
      ECGvalue = analogRead(Pin);
      Serial.print(ECGvalue);
      Serial.print(";");
      Serial.println(measureTime);
      counterTime ++;

    }
  }

Das ist der Teil wo ich es einsetze. Normalerweise sollte es gehen, da ich es vorher abgreife, bevor ich previous = current setze.. Oder sehe ich den Fehler gerade nicht?

Eine weitere Frage ist, ob ich nach 49 Tagen mit der Abfrageprobleme habe, da mein current Wert kleiner ist als der vorherige?

So hab es hinbekommen soweit, d.h. (messpunkt, messzeit zum jeweiligen Messpunkt).

d.h. ich habe (currentTime-previousTime)*counter ---> um zum jeweiligen Messwert den Messzeitpunkt zu haben. Doch manchmal passen die Werte nicht z.B :

513,240
514,256 -> (240+16)
516, 255 ----> hier müsste eigentlich 255+16 sein, warum ist das der Fall? Mache ich etwas Falsch?

(siehe gelbe Markierung

test.PNG

Zeige doch mal die Deklaration der beteiligten Variablen und den Code. Evtl. Byte verwendet? Da ist bei 255 Schluß.

Gruß Tommy

Hi danke für dein Feedback,
also ich habe die unsigned long variablen folgendermaßen deklariert:

unsigned long measureTime=0UL;  //UL damit Compiler die Zahlen als unsigned long behandelt
unsigned long measureTime = 0UL;


if(ZigBee.status() == CONNECT)
  {
    int counterTime= 0;
    currentTime = millis();
    digitalWrite(LED, HIGH);
    if(currentTime - previousTime >= Interval)
    {
      measureTime = (currentTime-previousTime)*counter;
      previousTime = currentTime;
      ECGvalue = analogRead(Pin);
      Serial.print(ECGvalue);
      Serial.print(";");
      Serial.println(measureTime);
      counterTime ++;
    }
  }

Also ich glaube ich habe das Problem gefunden und zwar :
Wenn man sich das Bild vom Output anschaut, welches ich im vorherigen Thread hochgeladen habe -->

513,240
514,256 -> (240+16)
516, 255 ----> hier müsste eigentlich 255+16 sein, warum ist das der Fall? Mache ich etwas Falsch?

mach ich ja folgendes: measureTime = (currentTime-previousTime)*counter;
so im Schnitt ist (currentTime-previousTime) nicht immer = 15ms, sondern manchmal 16 oder manchmal 17. und wenn ich es mit dem Counter multipliziere, passiert, das wenn das Ergebnis aus der Subtraction größer oder kleiner als 15 ist --> die Darauffolgende Zahl kleiner ist wie z.B. bei
514;256 >516, 255. Nun habe ich res folgendermaßen gelöst, dass ich miir das vorherige Ergebnis von (currentTime-previousTime) merke und es immer dazu addiere, damit ich zu jedem Messpunkt eine Zeithabe, um dies später auszuwerten.

Hast du vllt eine bessere Idee, wie man das lösen kann (vllt das ich etwas anderes als millis() verwende?

Außerdem, da ich millis verwende habe ich aus das Risiko einen Rollover nach 49 Tagen zu haben.
Hätte jemand einen Tip, wie ich es lösen könnte, dieses Risiko nicht einzugehen? - Dazu habe ich mal recherchiert und folgendes gefunden gehabt: programming - How can I handle the millis() rollover? - Arduino Stack Exchange
Da wird behauptet, dass man solange keine Vergleiche mit den Timestamps macht, der Rollover kein Problem sei. Nur das ist mir noch nicht so klar und ich glaube bei mir wäre es ein Problem oder verstehe ich es falsch?

milito:

      measureTime = (currentTime-previousTime)*counter;

Hast du vllt eine bessere Idee, wie man das lösen kann (vllt das ich etwas anderes als millis() verwende?

Wenn ich mal in aller Freundlichkeit meine Meinung von mir geben darf: Die Sache mit dem Zähler ist entweder so genial, daß ich sie nicht verstehe, oder einfach gagga.

Verschicke zum Meßwert doch einfach currentTime, dann hast Du eine Zeitbasis. Die läuft nach 49 Tagen über, aber das tut measureTime auch. Interessant würde die Sache, wenn Du uint64_t measureTime verwenden würdest.

if(currentTime - previousTime >= Interval)

Das ist überlaufsicher, das wurde hier im Forum schon öfter bewiesen. Wenn Du es selbst "erfahren" möchtest, dann baue Dir einen Byte-Zähler, der ja schon bei 255 überläuft, und beobachte, was passiert.