Je voudrais mesurer en permanence la longueur de l'état ON et de l'état OFF d'un signal rectangulaire assymétrique
Ces 2 valeurs varient en permanence
Je n'ai pas besoin que la mesure se fasse en temps mais en unité suffirait (genre T=T+1)
Mon but est de comparer ensuite ces 2 mesures dans la suite de mon programme .. une grande précision n'est donc pas nécessaire
J'ai fait des tentatives avec 2 boucles do..while successives mais en vain
J'ai des connaissances sur l'arduino mais je me considère comme débutant
J'ai lu qu'avec cette fonction, il n'était pas possible de mesurer deux états ON et OFF qui se présenteraient à la queue leu leu parce qu'elle se baserait sur deux fronts montants successifs ou deux montants descendants successifs .... ce que l'on a pas avec mon signal
Oui, c'est vrai.
Tu as toutes les chances de mesurer l'état haut sur une période et l'état bas sur la période suivante. Si le signal ne varie pas brusquement (et est répétitif), ce peut être suffisant.
Si par exemple vous voulez mesurer votre durée HIGH, il faut que la fonction voit le front montant
unsigned long dureeHIGH = pulseIn(pin, HIGH);
la mesure va commencer donc au front montant et s'arrêter au front descendant.
Le souci donc c'est que si vous essayez d'enchaîner avec un
unsigned long dureeLOW = pulseIn(pin, LOW);
la fonction ne va pas se déclencher tant qu'elle ne voit pas un front HIGH LOW et comme il vient de se produire vous n'allez mesurer que le suivant et rater celui en cours.
comme le dit @kamill, si le signal est court et répétitif, ce n'est peut être pas un drame d'avoir besoin de 2 cycles pour trouver les 2 valeurs.
Si cependant c'est un souci, vous pourriez mesurer différemment: au retour du premier pulseIn() vous savez que vous venez de passer à LOW, donc si vous notez le temps à cet instant et attendez le prochain front vers HIGH et mesurez le temps pris, ça peut marcher.
unsigned long dureeHIGH = pulseIn(pin, HIGH);
unsigned long t0 = micros();
while (digitalRead(pin) == LOW); // attente active
unsigned long dureeLOW = micros() - t0;
attention cependant la granularité de la mesure va dépendre maintenant de la vitesse d'exécution de digitalRead() qui n'est pas un foudre de guerre... Pour être précis il faudrait lire directement la valeur de l'état de la pin en lisant son PORT.
Vous avez parfaitement compris mon problème
Comme je dois impérativement mesurer tous les cycles sans en omettre un seul, je vais essayer ton astuce J-M-L
Encore une question:
Effectivement, je recherche à rendre ses mesures les plus rapides possibles et vous m'avez parlé pour y arriver de lire directement la valeur de l'état de la pin en lisant son PORT"
si le N° de pin est fixe et connu, vous pouvez aussi utiliser une bibliothèque qui offre un digitalReadFast (premier lien trouvé sur internet, pas le repo d'origine)
Avec attachInterrupt(), et le paramètre CHANGE, on peut avoir une fonction d'interruption qui donne les valeurs des niveaux. Genre si on a eu un front et que la broche est à l'état haut,
on range dans niveauBas millis()-tempsDuDernierFront
on range dans tempsDuDernierFront la valeur de millis()
Si on a eu un front et que la broche est à l'état bas,
on range dans niveauHaut millis()-tempsDuDernierFront
on range dans tempsDuDernierFront la valeur de millis()
Les valeurs de niveauBas et niveauHaut sont automatiquement mesurées à chaque niveau. et en plus le code n'est pas bloquant. On peut donc faire l’affichage ou autre chose pendant ce temps.
J'en profite pour faire remarquer qu'en éditant le premier post, il est possible de changer le titre des posts en adéquation avec la question et pas une phrase qui convient à 50% des posts.
on range dans niveauBas millis()-tempsDuDernierFront
on range dans tempsDuDernierFront la valeur de millis()
Oui - tout à fait.
Si on passe par des interruptions, je suppose que ce serait parce que le signal oscille rapidement, dans ce cas il vaut mieux prendre micros() que millis() en terme de granularité
il faudra aussi prévoir une section critique pour traiter les durées dans la loop (pour travailler sur une copie figée des mesures)
L'ordre de grandeur des durées que j'aimerais atteindre est de 4ms et mieux encore si on pouvait atteindre 1ms
Je n'ai pas compris pourquoi on raterait le front montant suivant si on introduit tes lignes dans une boucle
//Détection du front montant et déclenchement de l'horloge t0
unsigned long dureeHIGH = pulseIn(pin, HIGH);
unsigned long t0 = micros();
//attente du front descendant - mémorisation de la dureeHIGH - début de la mesure duréeLOW
while (digitalRead(pin) == LOW); // attente active
Toff=t0;
unsigned long dureeLOW = micros() - t0;
//détection du front montant suivant - mémoristion de dureeLOW - redémarrage de l'horloge
unsigned long dureeHIGH = pulseIn(pin, HIGH);
Toff=dureeLOW;
unsigned long t0 = micros();
On rate un front si on doit faire pulseIn(pin, HIGH); et pulseIn(pin, LOW); car ces fonctions on besoin des deux fronts. En faisant comme au dessus, on utilise la sortie de pulseIn comme front, et cela passe. Mais on a deux mesures différentes pour HIGH et LOW. Cela peut donner une erreur systématique par exemple des valeurs de HIGH systématiquement trop grandes et LOW systématiquement trop courte. En passant par les interruptions, c'est le même décalage systématiquement et le mesure est compensée (on a le mê retard quand on mesure le début er quand on mesure la fin.
Un problème du code ci dessus est qu'on est dans une boucle pour faire la mesure et quand on en sort,c'est pour faire la mesure suivante; On n'a donc plus le temps de traiter les mesures. On ne peut pas faire deux choses mesurer et analyser. Avec les interruptions on ne monopolise le micro qu'au moment des fronts, on a donc quasiment tout le temps pour traiter les mesures.
il vaut mieux prendre micros() que millis()
Pour 1ms, on n'a pas le choix. On peut très facilement avoir des mesures qui suivent même à 100µs. La question est quand même que va-tu-faire des mesures. 1ms s'est limite pour afficher sur la console.
Plus tu donnera d'informations sur ce que tu veux faire, plus la réponse sera adaptée.
Je n'ai pas besoin que la mesure se fasse en temps mais en unité suffirait (genre T=T+1)
Mon but est de comparer ensuite ces 2 mesures dans la suite de mon programme .. une grande précision n'est donc pas nécessaire
Oui mais il faut quand même se fixer une précision minimale.
En fait ce que tu cherches à connaître c'est la variation du rapport cyclique d'un signal modulé en PWM.
Est-ce bien cela ?
Si j'ai bon :
Le minimum d'information à fournir est la fréquence de répétition du signal PWM ainsi que la valeur min et max du rapport cyclique.
À partir de là deux solutions :
utilisation ou recopie du signal à mesurer et filtrage passe bas avec un filtre Résistance-condensateur.
En sortie du filtre on a une tension continue qui sera égale a 0 pour un RC = 0 % et égale à Vcc pour un RC = 100%. Puis mesure analogique de la tension filtrée.
Ce ne sera pas la solution la plus précise mais c'est probablement la plus simple si la précision suffit.
S'inspirer de la méthode utilisée dans les bibliothèques du DHT11 ou 22 où l'auteur détecte le temps passé dans un signal "0" et dans un signal "1" avec deux boucles while. Si seule la connaissance du rapport cyclique est recherchée il suffit d'ajouter un compteur dans chaque boucle while et d'exploiter la valeur de chaque compteur.
Pour la mesure des temps digitalRead() ou digitalWrite sont à proscrire il faut charger et utiliser la bibliothèque digitalFastRead() / digitalFastWrite() dont la version actuelle fait aussi bien que la lecture des registres mais en plus simple.
Explication : digitalRead() prend 60 cycles horloges, digitatalFastRead() prend 2 cycles horloge.
Pour information : si seule la connaissance des temps est recherchée et non pas la surveillance en permanence pourquoi ne pas utiliser un appareil de mesure ?
Un analyseur logique, clone de Saleae, à partir de 6 €, fera très bien le travail et sera un investissement très utile, aussi indispensable qu'un multimètre pour la suite.
Un analyseur logique sera plus utile qu'un oscilloscope, dont l'usage est bien moins évident qu'il n'y paraît.
On fait vite des bêtises avec un oscillo quand on connecte mal la masse des sondes.
autre option à base d'interruptions c'est de router le Signal sur 2 pins, une avec interruption sur front montant et l'autre sur front descendant.
la connaissance de l'état de la pin dans l'interruption et du moment du dernier appel (dans l'autre interruption) vous donnent la mesure de la durée du dernier plateau
ça permet sans doute de passer moins de temps de calcul dans une des interruptions.
cela dit, si la mesure c'est quelques ms et que l'on ne fait rien de très couteux entre temps, c'est un peu l'artillerie lourde pour faire cela, une petite machine à état fera l'affaire (cf mon tuto éventuellement)
Je suis radioamateur et mon but est de créer un décodeur morse personnel .. il en existe des tout fait mais j'aimerai tester mes idées là-dessus
Un signal morse est une suite de créneaux positifs T1 espacés entr'eux par des silences T2
Selon le rapport entre les longueurs de T1/T2, on en extrait les lettres et les mots
Comme la vitesse de manipulation fait varier les valeurs de T1 et T2, ce ne sont que leurs rapports qui me sont utiles pas leur valeur absolue
Mon approche est la suivante :
mesurer répétitivement T1 et T2 et calculer à chaque fois leur rapport afin de déterminer le moment où on passe de points/barres à lettres (T2=3) et de lettres à mots (T2=5)
(voir croquis ci-dessous)
ensuite viendra la conversion en caractères réels à partir de ce tri
C'est donc le point 1) qui fait l'objet de mon post