Comptage des impulsions avec interruption


10

J'ai essayé de compter les impulsions d'une onde carrée de 12 500 Hz pour déclencher une sortie. Voici le code que j'ai jusqu'à présent. Lorsque l'Arduino est réinitialisé, il imprime 315 sur la série sur un échantillon de 25 ms. 315 x 40 = 12600. Ce qui me semble fonctionner parfaitement.

Mon seul problème est qu'il ne renvoie ce numéro qu'une fois lors de la réinitialisation de la carte. Maintenant, si je déplace ce même code vers le bas void loop, cela compte consécutivement en me donnant des retours inconstants.

Je ne comprends pas ce que je dois mettre dans la section de boucle afin que je puisse compter à plusieurs reprises et avec précision le nombre de basculements de la broche d'entrée que je reçois sur une période de temps afin que je puisse faire quelque chose à la sortie en fonction de la présence des 12 500 Signal Hz ou non.

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2

void setup() {
   // Put your setup code here, to run once:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
  delay(25);
  detachInterrupt(pin);
  Serial.print(F("Counted = "));
  Serial.println(IRQcount);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // Put your main code here, to run repeatedly:
}

En utilisant le code ci-dessus, chaque fois que j'appuie sur le bouton de réinitialisation, j'obtiens une ligne dans la fenêtre série.

Counted = 441
Counted = 442
Counted = 441
Counted = 441
Counted = 441

Maintenant, je veux obtenir le même résultat, mais en répétant encore et encore. De cette façon, si le signal tombe, je peux déclencher une sortie pour la désactiver (LOW). Lorsque le signal est présent, la sortie passe à l'état haut.

Ma tentative était de déplacer l'interruption d'attachement vers le bas void loop, afin qu'elle se répète. Voici à quoi ça ressemble.

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2

void setup() {
  // Put your setup code here, to run once:
  Serial.begin (9600);
}

void IRQcounter() {
   IRQcount++;
}

void loop() {
  // Put your main code here, to run repeatedly:

  attachInterrupt(pin_irq, IRQcounter, RISING);
  delay(25);
  detachInterrupt(pin);
  Serial.print(F("Counted = "));
  Serial.println(IRQcount);
}

Le retour que j'obtiens s'auto-met à jour, mais le "compte" au lieu de partir de 0 chaque fois commence à partir du compte précédent. Alors ça devient de plus en plus gros. Je cherche à retourner une valeur constante qui représente mon signal 12500 Hz afin que, et seulement cela, déclenche ma sortie.

Counted = 442
Counted = 886
Counted = 1330
Counted = 177
Counted = 2221
Counted = 2667
Counted = 3112
Counted = 3557
Counted = 4002
Counted = 4448
Counted = 4893
Counted = 5338
Counted = 5784
Counted = 6229
Counted = 6674
Counted = 7120
Counted = 7565
Counted = 8010
Counted = 8456
Counted = 8901
Counted = 9347
Counted = 9792
Counted = 10237
Counted = 10683
Counted = 11130
Counted = 11576
Counted = 12022
Counted = 12469
Counted = 12915
Counted = 13361
Counted = 13808
Counted = 14254
Counted = 14700
Counted = 15147
Counted = 15593
Counted = 16040
Counted = 16486
Counted = 16932
Counted = 17378
Counted = 17825
Counted = 18271
Counted = 18717
Counted = 19164
Counted = 19610
Counted = 20056
Counted = 20503
Counted = 20949
Counted = 21395
Counted = 21842
Counted = 22288
Counted = 22735
Counted = 23169
Counted = 23616
Counted = 24062
Counted = 24508
Counted = 24955
Counted = 25401
Counted = 25730
Counted = 25756
Counted = 26200
Counted = 26646
Counted = 27093
Counted = 27539
Counted = 27985
Counted = 28432
Counted = 28878
Counted = 29324
Counted = 29770
Counted = 30217
Counted = 30663
Counted = 31110
Counted = 31556
Counted = 32002
Counted = 32449
Counted = -32641
Counted = -32195
Counted = -31748
Counted = -31302
Counted = -30855
Counted = -30408
Counted = -29962
Counted = -29515
Counted = -29069
Counted = -28622

"Maintenant, si je déplace ce même code vers le bas dans la boucle vide, cela compte consécutivement, ce qui me donne des retours inconstants." signifie quoi exactement?
Ignacio Vazquez-Abrams

J'ai édité ma question pour essayer de mieux m'expliquer
Brandon Whosville

Réponses:


9

Vous devez réinitialiser IRQCount 0avant de rattacher à nouveau l'interruption. Sinon, il continuera simplement à compter d'où il s'est arrêté la dernière fois.

Je voudrais en fait garder l'interruption attachée et réinitialiser la variable juste avant le délai. De cette façon, la surcharge d'attachement / de détachement n'est pas ajoutée au délai de 25 ms.

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2

void setup() {
  // put your setup code here, to run once:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // put your main code here, to run repeatedly:
  IRQcount = 0;
  delay(25);
  int result = IRQcount;
  Serial.print(F("Counted = "));
  Serial.println(result);
}

Étant donné qu'un int est égal à 2 octets, une interruption peut se produire au milieu de la définition / lecture de ces deux octets. Cela peut entraîner une valeur incorrecte occasionnelle. Pour éviter cela, vous devez désactiver l'interruption lors de la définition / lecture de la valeur

volatile int IRQcount;
int pin = 2;
int pin_irq = 0; //IRQ that matches to pin 2

void setup() {
  // put your setup code here, to run once:
  Serial.begin (9600);
  attachInterrupt(pin_irq, IRQcounter, RISING);
}

void IRQcounter() {
  IRQcount++;
}

void loop() {
  // put your main code here, to run repeatedly:

  cli();//disable interrupts
  IRQcount = 0;
  sei();//enable interrupts

  delay(25);

  cli();//disable interrupts
  int result = IRQcount;
  sei();//enable interrupts

  Serial.print(F("Counted = "));
  Serial.println(result);
}

Merci Gerben! En utilisant ce code, j'obtiens le retour indésirable occasionnel. Quelle serait la manière la plus simple de dénoncer cela? Faire une sortie permet de dire 3 lectures avant de décider quoi faire. Ou faire la moyenne des impulsions sur une durée au lieu d'un nombre brut? Voici un exemple de retour, je reçois l'anomalie toutes les quelques secondes. Compté = 439, compté = 438, compté = 430, compté = 48, compté = 318, compté = 438,
Brandon Whosville

1
J'ai allongé le délai pour donner un échantillon plus grand. Cela me donne un retour exploitable depuis ma source d'entrée bruyante. Cela semble fonctionner parfaitement! Je vous remercie!
Brandon Whosville,

Je suppose que vous avez utilisé le code avec le clis et le seis. Plutôt étrange d'avoir deux mauvaises valeurs consécutives.
Gerben

1
Gerben, oui j'ai utilisé le code avec le cli et le sei dedans. Voulez-vous dire qu'il est étrange d'obtenir les deux mauvais retours d'affilée? Il semble que les retours soient corrects, c'est le signal entrant qui n'est pas stable donnant des retours indésirables. Si j'échantillonne, disons 100 ms, cela donne beaucoup d'impulsions par échantillon pour activer ou tuer le circuit en toute sécurité. J'apprécie vraiment votre aide!
Brandon Whosville

Mais les 48 et 318 que vous avez sont tous deux inférieurs à la moyenne d'environ 435. Je ne connais pas le circuit connecté, il pourrait donc tout aussi bien être le circuit, au lieu du code Arduino. Quoi qu'il en soit, tant que vous êtes satisfait du résultat final ... Heureux d'avoir aidé.
Gerben
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.