Arduino, Multi tache / priorité / comptage

Bonjour à tous :slight_smile:

Assez gourmand en tuto sur l'arduino, je me débrouille pour apprendre sur le tas :slight_smile:

J'arrive a faire "pas mal" de chose différente mais je bug sur certaines, la plus gênantes pour moi c'est le "multi-tache".

Une fonctionnalité que j'utilise souvent c'est mesurer une fréquence ou faire un comptage. Via pulsein ou millis()

Comptant généralement en millisecondes, cela ne me pose aucun souci si c'est la seule tache que l’Arduino effectue.

Si j'utilise d'autre fonction, même juste une supplémentaire (sans delay bien entendu) je perds en précision au point de ne pas pouvoir utiliser correctement mon programme.

Question bête, est ce que l'on peut sans souci faire un fréquence mètre, coupler a une autre fonction (lecture de sonde, gestion de led etc) sans souci, ou c'est quelque chose de réellement très compliqué?

Je comprends le principe d'attribution des ressources en mettant la priorité sur le calcul et si il reste du temps/ressources, l'utiliser pour des fonctions secondaire, mais je ne sais pas l'utiliser.

Si vous avez de bon article/tuto je suis totalement preneur :slight_smile:

Merci :slight_smile:

hello
oui, c'est possible
toutefois, ce n'est pas un vrai multitâches, les choses se font chacune à leur tour

regardes les "interruptions"

ton prg se déroule, un événement survient et déclenche une interruption dont l’exécution est prioritaire sur le programme. le micro donne la main à la fonction d'interruption.

l'interruption exécute sa fonction qui doit être très courte. (quelques cycles d'horloge)
puis l'interruption redonne la main au programme.

tu peux ainsi compter des pulses sur une entrée interruptible ( juste incrémenter un compteur)
et traiter ce compteur pour en faire une fréquence dans ton programme

Hello :slight_smile:

Je crois avoir partiellement compris les interruptions, mais pas tout ton message.

const byte PIN_SIGNAL = 2;


void setup() {

  Serial.begin(9600);
  pinMode(PIN_SIGNAL, INPUT);

}

void loop() {

 //noInterrupts();
  
  unsigned long periode = ((pulseIn(PIN_SIGNAL, HIGH)* 2) / 100) * 93; //93 correspond au 7% d'erreur de mesure dont je ne connais pas la provenance)

  int frequence = (1/ (periode*0.000001));
  
  //interrupts();


  Serial.println(frequence);
}

Par exemple si j'utilise ce code, avec noInterrupts(), la valeur lu correspond bien au signal généré mais est ce que la base te semble bonne? Parce-que je n'utilise pas "d'attachInterrupt" que je pense pas avoir compris :frowning:

Parce-que tu parle d'incrémenter un compteur, ce que fait directement pulsein si je ne me trompe pas.

Par exemple, j'aimerai essayer de compter les impulsions supérieur a "900" sur un port analogique (sans circuit RC), sans parler de code pure mais plutôt de méthode, l'idée serait:

(d'ailleurs je ne pense pas que je puisse utiliser une interruption sur un port analogique vu que sur nano/uno elle serait utilisable sur les pin 2 et 3)

-d'initialiser une variable à 0 pour le comptage

-de définir une durée de comptage (1 seconde?)

-d’initialiser une variable a millis(),

-d'incrémenter la variable de comptage d'un point a chaque passage au dessus de "900"

-de comparer le millis() actuel a celui stocké + durée de comptage

Si la "seconde" ne c'est pas écoulé, je continue le comptage, sinon je stocke la valeur de comptage comme une variable "fréquence" vu que la c'est pour une durée de 1 seconde.

Cela semble gourmand et a l'opposé de ce que tu dis :frowning: "'interruption exécute sa fonction qui doit être très courte. (quelques cycles d'horloge)"

Merci pour ton aide :slight_smile:

Ps: je crois comprendre que j'ai fais une erreur dans l'exemple de code, j'aurai du utiliser une variable type volatile dans mon interruption :confused:

Du coup j'ai ré-édité un code et je vais dormir :grin: (j'étais entrain de regarder des tutos et exemple de code...)

const byte PIN_SIGNAL = 2;


void setup() {

  Serial.begin(9600);
  pinMode(PIN_SIGNAL, INPUT);
  
}

void loop() {

  noInterrupts();
  
  volatile unsigned long periode = (500000 / pulseIn(PIN_SIGNAL, HIGH)* 1.08); //une demi-seconde (mon signal est carré) / la mesure) le tout multiplié par un taux de correction.
    
  interrupts();

  delay(1000);
  
Serial.println(periode);
}

J'ai volontairement ajouté un délai pour voir si il impactait la précision de la mesure mais non donc c'est cool :slight_smile:

Par-contre je ne comprends pas d’où viens le taux d'erreur sur la mesure (en simulation), là je suis bon au hertz près sur 30Hz/200Hz.

Je sais qu'il est existe de très bon code pour avoir des fréquences précises mais ce n'est pas le but recherché, la je pousse a "l’extrême" niveau précision pour l'usage dont j'ai besoin, mais j'ai envie de comprendre et d'apprendre les/mes limites, et bon normalement qui peut le plus peut le moins :slight_smile:

Il faudrait maintenant que je vois si c'est applicable a un signal analogique :cold_sweat:

Dans ton code, tu ne te préoccupes pas du tout de :

  • installer la routine (=fonction) d’interruption, c-à-d demander à l’Arduino de réagir à un événement donné en appelant cette routine,
  • de fournir le code de cette routine.
    Evidemment rien ne se passe.

Si tu utilises des interruptions, c’est pour virer pulseIn(), car cette fonction est bloquante, et ça ne te va pas.

Voici comment marche une interruption:

  • le processeur est gentiment en train de faire tourner le programme chargé dans l’Arduino
  • tout à coup, un octet arrive sur la ligne série. Le circuit spécialisé envoie un interruption au processeur.
  • le processeur cesse immédiatement de faire ce qu’il faisait, et exécute la routine associée à cette interruption. Cette routine lit l’octet juste arrivé sur le matériel et le stocke en mémoire. Vite.
  • a la fin de cette routine, le processeur reprend le travail qu’il avait mis en suspend.

Dans to cas , le signal qui va provoquer l’interruption me semble être un signal rectangulaire. Il faut le connecter à une broche capable de générer une interruption, choisir si l’interruption se fait sur front montant ou descendant. Ta routine t’interruption n’a qu’une ligne : elle incrémente une variable globale (volatile).

Ton prog principal lit cette variable quand il en a besoin. C’est le comptage.

un petit bout de code pour illustrer
compte les fronts montants, moniteur à 1000000 bauds

const byte puls = 2;//entrée interruptible
volatile byte top =0;
unsigned long deb=0;
unsigned long fin =0;
void setup() {
Serial.begin(1000000);  
pinMode(puls, INPUT_PULLUP);
attachInterrupt(0, isr_puls, RISING);
}
void loop() 
{
  if (top==1) {deb=millis();}
  if (top==10){fin=millis();Serial.print("10 top en : ");Serial.print(fin-deb);Serial.println(" ms");
  Serial.print((fin-deb)/top);Serial.println(" ms");top=0;}
}
void isr_puls()
{top++;}

Merci biggil et dfgh pour votre aide :slight_smile:

biggil,

Donc Pulsein est plutôt a bannir pour du "multitache" :slight_smile:

La ou j'avais faux si je comprends bien, c'est que je n'utilisais aucun déclencheur, je disais juste "cette fonction est prioritaire"

C'est quand même fonctionnel sous ce format, pour d'autre fonction autre que le comptage?

dfgh,

Donc si je comprends bien, tu compte le nombre d'impulsion sur le pin2 (qui devient prioritaire en cas d'entrée à 1) jusqu’à 10 et tu relève le temps nécessaire pour cela,

Donc toujours si je comprends bien c'est plus précis/fiable de définir le nombre d'impulsion a compter et de mesurer le temps nécessaire pour les totaliser, que de compter le nombre de d'impulsion dans un temps défini. Vu que l’incrémentation se fait 1 par 1, je pourrais me retrouver "entre deux" incrémentations, alors que la base temps est 1000x plus précise vu qu'on incrémente 1ms par 1ms?

Encore merci pour votre aide :slight_smile:

le code précédent n'est qu'un exemple

tu peux etre en attente d'interruption pendant xxx milliS ou minutes ou ...
les interruptions feront leur incrémentations....
et une fois le temps passé, tu fais tes comptes .

tu peux déclencher le chrono à la premiere interruption et le stopper à la deuxième
et ainsi avoir le temps entre deux interruptions.

ou ...

tout dépends de ce que tu veux faire

Oui c'était pour comprendre l'idée :wink:

Merci :slight_smile:

Oz91:
La ou j’avais faux si je comprends bien, c’est que je n’utilisais aucun déclencheur, je disais juste “cette fonction est prioritaire”

Euuuh, non, tu ne disais … rien du tout :slight_smile: