J'utilise un Arduino Uno pour envoyer des informations de temps et de tension sur le port série à Python pour tracer. Cependant, les intervalles de temps entre les horodatages successifs semblent augmenter au fil du temps, affectant mon tracé. Cela est particulièrement vrai lorsque le débit en bauds est défini sur 9600, où mes différences de temps initiales peuvent être de 1320 et augmenter à 16400 après une période de temps relativement courte. Lorsque ce taux est mis au maximum à 115200 bps, le changement est plus lent et moins perceptible, d'environ 1340 à 1500, même après un cycle d'envoi relativement long. Toutes les heures sont données en microsecondes.
Je voudrais savoir si je peux réduire ou éliminer cet effet, et sinon comprendre pourquoi il existe. J'ai lu des choses sur les interruptions et les retards provoquant cela, mais je n'apprécie pas pleinement la complexité de l'électronique à portée de main et je voudrais savoir:
- Puis-je obtenir une plus grande précision dans le timing?
- Qu'est-ce qui cause ce changement de timing?
Voici ce que j'ai actuellement:
#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;
}
}
}
}
}
la source
eHealth.getECG()
-il? Cet appel dure-t-il toujours le même temps?Réponses:
Utilisez une minuterie et un ISR (routine de service d'interruption) pour rendre le chronométrage plus précis.
Jetez un œil à ma preuve de concept d'interruption temporisée de 1 ms . L'idée est d'avoir un rythme cardiaque de 1 ms raisonnablement précis dans le système qui peut être utilisé pour déclencher d'autres événements. Dans le PoC, il est utilisé pour faire clignoter une LED à ½ Hz, mais ayant accès aux nouvelles variables
millisecondCounter
etsecondCounter
vous permet de déclencher des événements dans la boucle principale à des moments arbitraires (mais précisément synchronisés).la source
loop()
), cette valeur étant modifiée par un ISR. Il peut arriver que seloop()
lit une mauvaise valeur (au milieu d'une modification par l'ISR). J'ai publié un commentaire à ce sujet sur votre blog.loop()
: mon échantillon vient d'obtenir la valeur en millisecondes, la comparer à la valeur de lecture précédente et si la différence> 0 (autre que réinitialiser le compteur à 0), afficher un message.Je peux penser à quelques éléments qui peuvent avoir un impact sur la "cohérence" des horaires d'écriture en série:
c'est peut-être la chose la plus évidente à laquelle penser, mais en effet, plus vous imprimez, plus il vous faudra pour le gérer.
Solution: imprimez le format de la chaîne en une chaîne de longueur connue.
sous unix, vous pouvez accéder au port série en utilisant une méthode tamponnée ou non tamponnée. L'utilisation de la méthode tamponnée pendant une longue période peut ralentir un peu le remplissage du tampon, cela se produit généralement lorsque les données arrivent plus rapidement que vous ne les lisez…
Solution: utilisez la ligne série sans tampon ( par exemple : sur Darwin / OSX c'est à la
/dev/cu.usbmodemXXX
place de/dev/tty.usbmodemXXX
)il semble que vous utilisiez une interruption TC, et les AVR ont des priorités dans la façon dont les interruptions sont gérées, je ne connais pas l'ordre de priorité pour l'Atmega328, et ce n'est pas l'une des fonctionnalités les plus documentées, donc je ne sais pas la sécurité de TC0 par rapport à l'interruption UART.
Solution: cherchez plus loin dans la documentation / fiche technique sur les priorités d'interruption et modifiez la minuterie si nécessaire; et / ou faire un test sans que l'autre minuterie ne fonctionne.
certains pilotes doivent faire la moyenne ou effectuer certaines opérations sur les valeurs précédentes, donc plus vous mesurez de valeurs, plus le tampon est long et plus il faut de temps pour calculer la valeur, jusqu'à ce que vous ayez atteint la taille maximale du tampon.
Solution: regardez le code source de la bibliothèque que vous utilisez et optimisez-le, supprimez le calcul s'il y en a un ou tenez compte de ce temps de traitement croissant.
mais si vous voulez vraiment optimiser la sortie série de l'arduino, vous devriez éviter d'utiliser la surcharge de l'arduino… Mais c'est beaucoup moins élégant et confortable à utiliser.
Je suis sûr qu'il y a d'autres points qui me manquent, mais ce sont les premières choses que je vérifierais avant de creuser davantage.
HTH
la source
Votre code inclut la durée de la sortie dans les mesures suivantes. Ainsi, en fonction de la longueur de la sortie, vous mesurerez différents moments. Cela peut être corrigé en formatant sur une sortie de longueur fixe.
Le problème suivant est que l'ONU a une très mauvaise base de temps. Jetez un œil ici pour une comparaison des différents types d'Arduino par rapport à la référence temporelle DCF77.
Conclusion: si vous avez besoin d'un timing précis, procurez-vous un Arduino avec cristal ou optez pour un RTC. Je peux fortement recommander les RTC DS3231 / DS3232 car ceux-ci atteignent généralement une précision de 2 ppm hors de la boîte.
la source