Warum tötet die Erinnerung an unsigned long meine Abtastgeschwindigkeit?

Ich verwende einen Mega 2560, um mit einer Mischung aus analogen (dh über analogRead ()) und I2C-basierten Sensoren gemessenen Sensoren zu kommunizieren Ein 16-Byte-Array, das dann auf eine SD-Karte geschrieben wird, sobald ein 512-Byte-Puffer vollständig gefüllt ist. Das Problem, auf das ich stoße, besteht darin, dass ich Daten von einem MAX30102-Pulsoximeter mit

In meinem Code unten sinkt die Zykluszeit meiner collectHR () – Schleife auf ca. 20 ms. Wenn ich diesen Punkt vorab zuordne, indem ich die Zeile direkt darunter verwende (eine Konstante speichern, anstatt in jeder Schleife eine neue uint32_t zu lesen), beträgt meine Zykluszeit etwa eine halbe Millisekunde. Was mich verwirrt, ist, dass wenn ich uint32_t mit dtostrf in einen String umwandle:

dtostrf(pulseOx.getIR(),3,0,pOxBuf); // read pulseOx, convert it into a 3 byte string 

dauert es nur etwa 1,2 ms, um ein Sample tatsächlich zu lesen Der MAX30102. Es scheint mir, dass ich durch Bevorzugung einer Struktur gegenüber einer Zeichenfolge (aus einer früheren Iteration dieses Codes, der alle Daten als txt-Datei anstelle einer bin-Datei geschrieben hat), damit ich binär auf meine SD-Karte schreiben kann, “ Ich drossle absolut meine Geschwindigkeit. Sollte das byteweise Arbeiten nicht effizienter sein als das Arbeiten mit einem String? Was passiert mit den anderen 18 ms, die zwischen dem Lesen des vorzeichenlosen Longs und dem Platzieren in den Byte-Puffer buffer1 auftreten? Implementieren dieses Codes mithilfe von String-Arrays anstelle einer Struktur. Ich konnte mit ungefähr 125 Hz laufen. Jetzt bin ich mit ungefähr 50 Hz. Ich würde mich über jeden Einblick hier freuen. Relevanter Code unten gezeigt:

#include <Wire.h> #include "MAX30105.h" #include <SPI.h> #include <SdFat.h> #define moisture0 A0 // Upper back sensor analog pin #define moisture1 A7 // Trunk sensor analog pin #define ECGpin A3 // ECG analog pin SdFat SD; // replace SD with SDfat. File sdLog; // placeholder to create datalogger struct meas // a 16 byte structure to hold all of our measurements { unsigned long mils; int ECG; uint32_t pox; int tempInt; int m1; int m2; }; struct meas measure; // create an instance of the above structure byte buffer1[512]; byte *measureLoc = (byte *) &measure; // to access measure structure as bytes char fileName[] = "WIHMSlog.bin"; void setup { Serial.begin(230400); } void loop() { sdLog = SD.open(fileName, O_WRITE | O_CREAT | O_AT_END); // Create file for the datalogging and verify its existance collectHR(); sdlog.close() } void collectHR() { unsigned int loopCount = 0; int buffLen = 0; // starting position in buffer int buffSize = 16; while (loopCount < 3200) { // some multiple of 32 (since 512 byte/sd block divided by 16 bytes per loop cycle = 32 cycles per sd write cycle measure.ECG = analogRead(ECGpin); // read ECG and stick the int into measures measure.pox = pulseOx.getIR(); //measure.pox = 5555; // Placeholder value measure.mils = micros(); measure.m1 = analogRead(moisture0); measure.m2 = loopCount; // just a test to ensure this is actually iterating in the card if (buffLen == 512) { // SD buffer is full, time to write! sdLog.write(buffer1, 512); buffLen = 0; } memcpy(buffer1 + buffLen, measureLoc, buffSize); // place the 16 byte data structure into the buffer buffLen = buffLen + buffSize; // increase the index size in the array loopCount++; Serial.println(micros()); } } 

Kommentare

  • Die Sequenz Die Anzahl der Operationen sieht etwas seltsam aus. Überlegen Sie, was gleich zu Beginn passiert: buffLen ist anfangs 0, dann erhöhen Sie es sofort auf 16 und dann kopieren Sie die Daten mit dem Offset 16 in diesen Puffer. Aber was ist mit dem ersten 16 Bytes? Warum haben Sie sie unbenutzt gelassen? Es ist auch nicht klar, warum Sie ständig Bytes von measure nach buffer1 pumpen müssen Warum von ' deklarieren Sie nicht einfach ein Array von 32 struct measure Elemente und verwenden Sie es direkt?
  • Vielen Dank für Ihre Eingabe! Sie ' haben absolut Recht, dass die ersten 16 Bytes leer bleiben. Ich hatte ursprünglich gedacht, dass dies der Fall sein würde mach es Es ist einfacher festzustellen, wann jede collectHR () – Schleife in der Datei endete, indem nach 16 0 ' s gesucht wird. Jetzt, da Sie darauf hinweisen, scheint dies eine totale Speicherverschwendung zu sein. Ich habe das Inkrement nach unten verschoben. der memcpy-Aufruf, um dies zu berücksichtigen. Ich hatte ' nicht daran gedacht, ein Array von Strukturen zu gießen. Ich ' werde es versuchen. Haben Sie einen Einblick, warum speziell der Speicher des Aufrufs pulsOx.getIR () so viel langsamer ist als die Zeit, die zum Abrufen dieser 4 Bytes vom Sensor benötigt wird?
  • use unsigned int für buffLen, da 15 * 3200 mehr ist, als int in Anspruch nehmen kann
  • Sind Sie sicher, dass Sie 512 Byte freien RAM haben? Die SDfat-Bibliothek enthält ohnehin einen 512-Byte-Puffer und einen weiteren für das Dateisystem. Es schreibt ohnehin nur volle Blöcke physisch auf SD.
  • Juraj Guter Fang, danke! Ich ' habe dies oben geändert. @ DataFiddler Ich habe angeblich noch ungefähr 5800 Bytes zum Spielen. Ich ' bin mir bewusst, dass SDfat einen 512-Byte-Puffer verwendet. Bedeutet dies jedoch, dass jeder write () -Aufruf 512 Byte auf die Karte überträgt oder dass bis dahin überhaupt nichts an die Karte gesendet wird Write () im Wert von 512 Bytes werden angehäuft? Entschuldigung, millisSet () hat Sie beleidigt. Ich ' habe es entfernt. Ich habe versucht, nur die relevanten Teile des Codes zu veröffentlichen, aber anscheinend habe ich diese Variable im ersten Beitrag übersehen. Müll wird entfernt …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.