compteur d'impulsions

bonjour,
j'ai fais un petit code test en vue de faire un compte tour moteur 2 temps. il faut l'adapter par apport au capteur et faire le petit calcule pour le rpm.
Le problème c'est que ce n'est pas hyper précis, mais surtout c'est que au bout d'une trentaines de secondes, ça ne fonctionne plus.
j'ai un générateur de fonction Tektronix donc assez stable. j'ai testé aussi avec une onde carré sortie 13.

volatile int pulscount;
int nbpuls;
int temps;

void RPM()
{
  pulscount++;
}

void setup()
{
  Serial.begin(9600);
  pulscount = 0;
  nbpuls = 0;
  temps = 0;
}

void loop()
{
  if ((millis() - temps) >= 1000)
  {
    detachInterrupt (0);
    nbpuls = pulscount;
    Serial.println(nbpuls);
    temps = millis();
    pulscount = 0;
  }

  attachInterrupt(0, RPM, RISING);

  //tone(13, 50); // signal carré sortie sur pin 13 31Hz mini 65535Hz maxi
}

Le problème c'est que ce n'est pas hyper précis, mais surtout c'est que au bout d'une trentaines de secondes, ça ne fonctionne plus.

De l'autre côté du net, on a du mal à savoir ce qui ne marche plus, il faut souvent dire précisément ce qui ne marche plus. Par exemple au bout de 30 secondes le régulateur de la carte fume, ou au liei d'avoir un affichage de 100 pour 100Hz, j'ai un affichage de 200 ou au début, cela m'affiche 100 toutes les secondes et au bout de 30s, ça affiche des 1...
Bon, le piège est classique. millis() donne le temps en millisecondes et tu essaie de mettre cela dans un int qui est capable de mémoriser un nombre entre -32768 et +32767. Donc dans les 32 premières secondes tout va bien. 0 la 33ème seconde, millis() vaut 33000 et tu fais

temps = millis();

temps va déborder et il contiendra 33000-65536 soit -32536. A la boucle suivante il y a le test

if ((millis() - temps) >= 1000)

millis() n'a pas eu le temps de changer et on aura

if ((33000 - (-32536)) >= 1000)

soit:

if ((33000 + 32536) >= 1000)

test qui est encore vrai, on va ainsi rentrer dans la boucle à chaque fois. L'erreur arrive donc à la 33ème seconde. Je suppose que c'est ce que tu n'a pas décrit.

Pour éviter cela, comme millis() est un unsigned long, il faut aussi prendre temps en unsigned long. Il n'y ara plus le plantage à 33s.

Maintenant il y a es choses bizarres. Pendant une seconde on n'entre pas dans le if et il reste:

void loop()
{
  attachInterrupt(0, RPM, RISING);
}

Je ne sais pas trop ce qui se passe si on appelle attachInterrupt plusieurs fois par ms. Il vaudrait mieux mettre attachInterrupt dans le if? Ainsi il serait exécuté qu'une fois:

void loop()
{
  if ((millis() - temps) >= 1000)
  {
    detachInterrupt (0);
    nbpuls = pulscount;
    Serial.println(nbpuls);
    temps = millis();
    pulscount = 0;
    attachInterrupt(0, RPM, RISING);
}


  //tone(13, 50); // signal carré sortie sur pin 13 31Hz mini 65535Hz maxi
}

Mais si c'est pour faire cela, autant mettre en place l'interruption dans le setup, et dans loop suspendre les interruptions par noInterrupts() et les remettres à la fin par interrupts()


nbpuls ne sert que pour l'affichage, pourquoi l'utiliser plutôt que de mettre Serial.println(pulscount);


Les gens sont paresseux, si tu utilises la vitesse de 115200 bauds, c'est plus facile à tester pour les autres. Pour toi, cela ne change rien qu'une seule fois, il faut mettre ta console à cette vitesse une fois pour toutes.
Mais tu risques en passant à 115200bauds de trouver plus de monde qui pourra tester.


Dans la boucle il y a une instruction longue (attachInterrupt) Supposons qu'elle dure 0,3s (c'est beaucoup beaucoup moins que ça, mais c'est plus facile à comprendre)
On démarre t=0
t=0, pas de test
attachInterrupt dure 0,3s, il est t=300ms
t=300, pas de test
attachInterrupt dure 0,3s, il est t=600ms
t=600, pas de test
attachInterrupt dure 0,3s, il est t=900ms
t=900, pas de test
attachInterrupt dure 0,3s, il est t=1200ms
t=1200, test on affiche ce qui s'est passé pendant 1200ms
attachInterrupt dure 0,3s, il est t=1500ms
t=1500, pas de test
attachInterrupt dure 0,3s, il est t=1800ms
t=1800, pas de test
attachInterrupt dure 0,3s, il est t=2100ms
t=2100, test on affiche ce qui s'est passé pendant 1100ms
attachInterrupt dure 0,3s, il est t=1500ms
...

Si la boucle de mesure est longue, on va la terminer avec une erreur de l'ordre de sa durée. Pour pur qu'il y ait tone en plus de attachInterrupt...


Tone n'a rien à faire dans loop(); si on en a besoin, c'est pour avoir un signal carré, autant la mettre dans seup()


pulscount est un entier signé. Autant mettre un entier non signé.


Quand on déclare les variables, elles sont initialisées à 0. Ce n'est pas la peine de les réinitiliser dans le setup. Si on veut insister sur le fiat qu'o les veut à 0, on peut le faire dans la déclaration:

volatile unsigned int pulscount=0;

Merci beaucoup pour ces explications, ça va bien m'aider.
si j'ai bien compris, pour tester une seconde, il faudrait décompter le temps de l'instruction interupt pour être plus précis?.

volatile int pulscount;
int nbpuls;
unsigned long temps;

void RPM()
{
  pulscount++;
}

void setup()
{
  Serial.begin(115200);
  attachInterrupt(0, RPM, RISING);
}

void loop()
{
  if ((millis() - temps) >= 1000)
  {
    noInterrupts();
    Serial.println(pulscount);
    temps = millis();
    pulscount = 0;
    interrupts();
  }
}

Non, le temps mis par la fonction d'interruption n'intervient pas du tout dans le calcul du temps qui et fait par

if ((millis() - temps) >= 1000)

Mais il peut y avoir un retard entre ce test et le temps où l'on arrête le comptage par noInterrupts(); Mais ici ce n'est pas vraiment gérable.

Quand tu fais temps = millis(); c'est aussi à 1 ms près (en fait 2ms car il y a ds valeurs que millis saute). Si on voulait être plus précis, il faudrait utiliser micros().

Les 1s doivent être mesurées entre le moment où l'on commence à compter( interrupts():wink: et le moment ou on arrête le comptage (noInterrupts();), mais le temps est pris un peu avant e' le test aussi est fait un peu avant. Du coup c'est à peu près compensé;

Pour trouver la bonne valeur, je ne vois comme métode simple de mettre un signal de fréquence connue et d'ajuster le 1000 (ou le 1000000 si on utilise micros) pour avoir le bon affichage;

Mais fait comme cela c'est déjà très bien. La boucle est très courte et il doit y avoir peu de variations.

merci
Reste a intégrer ce code dans le sketch de mon instrument de bord de mon ULM.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.