const byte pinInterruption = 19;
volatile int compteurImpulsion = 0;
const unsigned long tempoClignotementLed = 25;
unsigned long tempsEcouler = millis();
unsigned long tempoAffichageFrequence = 1000;
unsigned long tempsEcoulerFrequence = 0;
// __________________________ Bibliothèque Néopixel _________________________________
#include <Adafruit_NeoPixel.h>
#define ledPin 9
#define ledCount 17
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);
void setup() {
Serial.begin(115200);
strip.begin();
strip.show();
strip.setBrightness(60);
pinMode(pinInterruption, INPUT);
attachInterrupt(digitalPinToInterrupt(pinInterruption), detectionInterruption, FALLING);
}
void loop(){
if( millis() - tempsEcoulerFrequence >= tempoAffichageFrequence){
Serial.println(compteurImpulsion);
compteurImpulsion = 0;
tempsEcoulerFrequence = millis();
}
}
void detectionInterruption(){
static boolean ledOn; // Pour garder l'état de la LED
if (millis() - tempsEcouler >= tempoClignotementLed) // Si période
{
ledOn = !ledOn; // Inverser l'état de la LED
if (ledOn) // Allumer la LED
{
strip.setPixelColor(2, 0, 0, 255);
strip.show();
compteurImpulsion++;
}
else // Eteindre la LED
{
strip.setPixelColor(2, 0, 0, 0);
strip.show();
}
tempsEcouler = millis();
}
}
Après essai, le programme fonctionne bien, c'est à dire qu'à 0Hz, je n'ai pas de clignotement et le compteur reste à 0 toutes les secondes, à 1000Hz, j'ai un clignotement lent et mon compteur passe à 4 et ainsi de suite jusqu'à un certains point ( le compteur bloque autour des 17 à 19 impulsions max et ne monte pas plus haut ).
Une idée sur ce problème ?
Dans detectionInterruption() il faut se contenter d'incrémenter compteurImpulsion car sinon les autres actions peuvent de faire rater des interruptions. Tous les autres traitements doivent se faire dans loop() pour cela, dans detectionInterruption() tu peux positionner un booléen qui signalera à loop() qu'une IT a été générée.
Autre chose, la gestion des smartLEDs repose sur des timings assez critiques et en conséquence lors du transfert des consignes vers les LEDs le programme masque les interruptions donc là aussi tu va rater des interruptions.
vous modifiez compteurImpulsion dans la loop sans faire de section critique. L'opération n'est pas atomique et si une interruption intervient pendant ce temps, votre variable peut se retrouver modifiée.
vous utilisez strip.show() avec un bandeau qui comporte 17 neopixels vous bloquez les interruptions pendant 50µs + 17 x 30µs = 560 µs ➜ pendant ce temps là vous pouvez rater une impulsion.
J'ai réussi à créer un code qui fonctionne bien, le comptage des impulsions ne beug pas, l' affichage en Hz est égal au retour sur moniteur série et les flashs led ( la led 13 + led Néopixel ) réagissent bien aux variations d'impulsions.
const byte pinInterruption = 19;
bool etatInterruption = false;
volatile int compteurImpulsion = 0;
const unsigned long tempoClignotementLed = 25;
unsigned long tempsEcouler = millis();
unsigned long tempoAffichageFrequence = 1000;
unsigned long tempsEcoulerFrequence = 0;
// __________________________ Bibliothèque Néopixel _________________________________
#include <Adafruit_NeoPixel.h>
#define ledPin 9
#define ledCount 17
Adafruit_NeoPixel strip(ledCount, ledPin, NEO_GRB + NEO_KHZ800);
const byte led = 13;
void setup() {
Serial.begin(115200);
strip.begin();
strip.show();
strip.setBrightness(60);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
pinMode(pinInterruption, INPUT);
attachInterrupt(digitalPinToInterrupt(pinInterruption), detectionInterruption, FALLING);
}
void loop(){
if( millis() - tempsEcoulerFrequence >= tempoAffichageFrequence){
Serial.println(compteurImpulsion);
compteurImpulsion = 0;
tempsEcoulerFrequence = millis();
}
if( etatInterruption == true ){
clignotementLed();
}
}
void clignotementLed(){
static boolean ledOn; // Pour garder l'état de la LED
if (millis() - tempsEcouler >= tempoClignotementLed) // Si période
{
ledOn = !ledOn; // Inverser l'état de la LED
if (ledOn) // Allumer la LED
{
digitalWrite(led, HIGH);
strip.setPixelColor(2, 0, 0, 255);
strip.show();
}
else // Eteindre la LED
{
digitalWrite(led, LOW);
strip.setPixelColor(2, 0, 0, 0);
strip.show();
}
tempsEcouler = millis();
etatInterruption = false;
}
}
void detectionInterruption(){
compteurImpulsion++;
etatInterruption = true;
}
Commet peut on lier une variableetatInterruption; à une interruption sans la faire passer dans la fonction d'interruption ( detectionInterruption() ) elle même ?
vous prenez un risque qu'une interruption intervienne pile au moment ou le compilateur traite l'instruction compteurImpulsion = 0; ou lors de l'impression. Comme il y a plusieurs octets à mettre à 0, l'opération n'est pas atomique et si l'interruption se déclenche, vous pourriez vous retrouver avec une valeur bizarre dans le compteur
une approche classique sur petit AVR est de bloquer les interruptions pour quelques microsecondes quand on touche à ces valeurs partagées pour faire une copie avant remise à 0 et ensuite on travaille sur la copie.
si une interruption arrive pendant qu'on les a bloqué, on ne crée pas ainsi de souci de double accès à la variable et cette interruption sera prise en compte juste à la sortie après le interrupts() donc vous ne la ratez pas. (vous en rateriez si plusieurs interruption avaient eu lieu pendant l'exécution de la section critique, c'est pour cela qu'on la restreint aux minimum nécessaire)
Ça bloque les deux interruptions ou on peut sélectionner l'interruption que l'on souhaite manipuler même si j'ai bien compris qu'en laissant une interruption en route et l'autre bloquée ne change pas le risque de louper des interruptions
rien ne vous empêche d'avoir dans chaque if la section critique et de ne faire la copie et remise à 0 que du compteur qui vous intéresse
si vous avez un seul if pour les deux, vous n'avez qu'une seule section critique où vous faites la copie et remise à zéro des deux capteurs et comme chaque interruption a son drapeau, même si les 2 venaient à être déclenchées pendant que vous copiez leur valeur, les ISR seraient ensuite appelées dans l'ordre de priorité déterminé par la puce (sur 328P d'un UNO par exemple, le vecteur d'interruption INT0 (pin 2) est prioritaire par rapport à INT1 (pin 3), ce qui signifie que si les deux interruptions se produisent en même temps, l'interruption sur la pin 2 (INT0) sera traitée en premier).