Ich verwende ein Arduino Uno, um Zeit- und Spannungsinformationen über die serielle Schnittstelle an Python zu senden, um sie zu zeichnen. Die Intervallzeiten zwischen aufeinanderfolgenden Zeitstempeln scheinen jedoch mit der Zeit zuzunehmen, was sich auf meine Darstellung auswirkt. Dies gilt insbesondere dann, wenn die Baudrate auf 9600 eingestellt ist, wobei meine anfänglichen Zeitunterschiede möglicherweise 1320 betragen und nach relativ kurzer Zeit auf 16400 ansteigen. Wenn diese Rate auf maximal 115200 Bit / s eingestellt wird, ist die Änderung langsamer und weniger auffällig, von etwa 1340 auf 1500, selbst nach einer relativ langen Sendezeit. Alle Zeiten sind in Mikrosekunden angegeben.
Ich würde gerne wissen, ob ich diesen Effekt reduzieren oder eliminieren kann und wenn ich nicht verstehe, warum er existiert. Ich habe Dinge über Interrupts und Verzögerungen gelesen, die dies verursachen, aber ich schätze die Komplexität der vorhandenen Elektronik nicht ganz und möchte wissen:
- Kann ich das Timing präziser gestalten?
- Was verursacht diese zeitliche Änderung?
Folgendes habe ich derzeit:
#include <eHealth.h>
extern volatile unsigned long timer0_overflow_count;
float fanalog0;
int analog0;
unsigned long time;
byte serialByte;
void setup() {
Serial.begin(9600);
}
void loop() {
while (Serial.available()>0){
serialByte=Serial.read();
if (serialByte=='S'){
while(1){
fanalog0=eHealth.getECG();
// Use the timer0 => 1 tick every 4 us
time=(timer0_overflow_count << 8) + TCNT0;
// Microseconds conversion.
time=(time*4);
//Print in a file for simulation
//Serial.print(time);
//Serial.print(" ");
Serial.print(fanalog0,5);
Serial.print("\n");
if (Serial.available()>0){
serialByte=Serial.read();
if (serialByte=='F') break;
}
}
}
}
}
quelle
eHealth.getECG()
das Dauert dieser Anruf immer genauso lange?Antworten:
Verwenden Sie einen Timer und ISR (Interrupt Service Routine), um das Timing genauer zu gestalten.
Schauen Sie sich meinen 1ms zeitgesteuerten Interrupt Proof of Concept an . Die Idee ist, einen einigermaßen genauen 1-ms-Herzschlag im System zu haben, der zum Auslösen anderer Ereignisse verwendet werden kann. Im PoC wird es verwendet, um eine LED mit ½ Hz zu blinken, hat jedoch Zugriff auf die neuen Variablen
millisecondCounter
undsecondCounter
ermöglicht es Ihnen, Ereignisse in der Hauptschleife zu beliebigen (aber genau zeitgesteuerten) Zeitpunkten auszulösen.quelle
loop()
), wobei dieser Wert von einem ISR geändert wird. Es kann vorkommen, dassloop()
ein schlechter Wert gelesen wird (mitten in einer Änderung durch den ISR). Ich habe einen Kommentar dazu in Ihrem Blog gepostet.loop()
Beispiel tun : Mein Beispiel hat gerade den Millisekundenwert erhalten, vergleicht ihn mit dem vorherigen Lesewert und zeigt eine Meldung an, wenn die Differenz> 0 ist (außer den Zähler auf 0 zurückzusetzen).Ich kann mir einige Dinge vorstellen, die die "Konsistenz" der seriellen Schreibzeiten beeinflussen können:
Dies mag am offensichtlichsten sein, aber je mehr Sie drucken, desto mehr wird es dauern, um damit umzugehen.
Lösung: Drucken Sie die Zeichenfolge in eine Zeichenfolge bekannter Länge.
Unter Unix können Sie gepuffert oder ungepuffert auf die serielle Schnittstelle zugreifen. Wenn Sie den gepufferten Weg für längere Zeit verwenden, wird er möglicherweise etwas langsamer, wenn sich der Puffer füllt. In der Regel geschieht dies, wenn Daten schneller eingehen als Sie sie lesen.
Lösung: Verwenden Sie die ungepufferte serielle Leitung ( z. B. unter Darwin / OSX
/dev/cu.usbmodemXXX
anstelle von/dev/tty.usbmodemXXX
)Es sieht so aus, als würden Sie einen TC-Interrupt verwenden, und AVRs haben Prioritäten in der Art und Weise, wie Interrupts behandelt werden. Ich kenne die Prioritätsreihenfolge für den Atmega328 nicht und es ist keine der am meisten dokumentierten Funktionen, daher weiß ich es nicht Wie sicher ist TC0 gegenüber dem UART-Interrupt?
Lösung: Informieren Sie sich in der Dokumentation / im Datenblatt über Interrupt-Prioritäten und ändern Sie den Timer bei Bedarf. und / oder einen Test durchführen, ohne dass der andere Timer läuft.
Einige Treiber müssen die vorherigen Werte mitteln oder einige Operationen ausführen. Je mehr Werte Sie messen, desto länger ist der Puffer und desto länger dauert die Berechnung des Werts, bis Sie die maximale Größe des Puffers erreicht haben.
Lösung: Sehen Sie sich den Quellcode der Bibliothek an, die Sie verwenden, und optimieren Sie ihn entweder, entfernen Sie den Kalkül, falls vorhanden, oder berücksichtigen Sie diese zunehmende Verarbeitungszeit.
Wenn Sie jedoch die serielle Ausgabe des Arduino wirklich optimieren möchten, sollten Sie die Verwendung des Arduino-Overheads vermeiden. Die Verwendung ist jedoch weitaus weniger elegant und komfortabel.
Ich bin mir ziemlich sicher, dass mir noch andere Punkte fehlen, aber das sind die ersten Dinge, die ich überprüfen würde, bevor ich weiter grabe.
HTH
quelle
Ihr Code enthält die Dauer der Ausgabe in nachfolgenden Messungen. Je nach Länge der Ausgabe messen Sie also unterschiedliche Zeiten. Dies kann durch Formatieren auf eine Ausgabe mit fester Länge behoben werden.
Das nächste Problem ist, dass die UNO eine sehr schlechte Zeitbasis hat. Schauen Sie sich hier einen Vergleich verschiedener Arduino-Typen mit der DCF77-Zeitreferenz an.
Fazit: Wenn Sie ein genaues Timing benötigen, besorgen Sie sich entweder ein Arduino mit Kristall oder eine RTC. Ich kann DS3231 / DS3232-RTCs nur empfehlen, da diese normalerweise sofort eine Genauigkeit von 2 ppm erreichen.
quelle