J'ai 2 questions sur cette fonction pulseIn() que je découvre :
1° - Peut-on me confirmer que la fonction "gèle" le déroulement du programme durant le temps qui s'écoule entre les 2 fronts. En gros, on est plus près d'un comportement de type delay() que millis() me semble-t-il.
2° - quel est le Timer utilisé pour mesurer le temps écoulé (Timer0 ou Timer1) ?
Plus généralement, je suppose que les fonctions "Arduino" sont implémentées dans la bibliothèque <Arduino.h> (ou ailleurs ? )
Comment puis-je avoir accès à cette bibliothèque ?
A vous lire,
je ne saurais répondre : je n'utilise pas l'IDE Arduino, seulement les cartes à base de 328 et 2560
mais si tu comptes utiliser ces dernières, il existe sur ces µC une fonction InputCapture (fonction hardware, associée aux timers - absente des Tiny) qui pourrait te permettre de réaliser ta propre fonction C/C++ comme tu l'entends
chez moi c'est dans
.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/wiring_pulse.c et .arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/wiring_pulse.S
Merci pour vos réponse exhaustives.
Apparemment pulseIn() utilise micros() donc par défaut, le Timer0.
Je me le note et je vais aller voir de plus près cet Arduino AVR Core.
Le code lit directement l’état d’une broche du microcontrôleur. Il attend d’abord qu’une impulsion en cours se termine, puis Il attend ensuite le début de la prochaine impulsion.
Pendant toute la durée de l’impulsion, il boucle et compte des cycles processeur.
➜ connaissant le nombre de cycles comptés et la durée de ce cycle (puisque l’auteur sait exactement quelles instructions en assembleur ont été utilisées) on peut calculer la durée de l’impulsion (en connaissant aussi la fréquence du CPU théorique - 16MHz le plus souvent)
C'est quand même dommage de ne pas utiliser en Assembleur ou en Language C l'interruption "PCINTx Pin Change Interrupt Request x" du µC associée à la lecture du temps pour ne pas bloquer les traitements en fond de tâche ;-)
en l'absence d'ICP sur les ATTiny...5 c'est effectivement la meilleure solution (mais comme on ne connaît toujours ni la cible ni les fréquences de travail...)
Armement d'un timer matériel 8 ou 16 bits sur le front souhaité
Lecture dudit timer sur l'autre front + maj dans un ou 2 registres
Le contexte à sauvegarder/restaurer de l'It peut être réduit aux registres SREG et le ou les 2 registres utilisés dans l'It (soient quelques centaines de nS à 16 MHz - 62.5 nS / Cycle instruction ;-)
NB: C'est grosso modo comme cela que je gére en Assembleur une liaison série UART full duplex de 300 bauds à 19200 bauds sur un ATtiny45/85 au travers de 2 FIFO/Tx et FIFO/Rx avant d'implémenter au mêmes vitesses de transmission l'utilisation de l'Universal Serial Interface (mais malheureusement en half duplex)
Écrire une fonction générale pulseIIn() qui fait ça n’est pas simple.
Suivant la pin, ce n’est pas la même interruption donc il y a un peu de setup à faire
Ensuite Vous aurez la latence variable du déclenchement de l’isr que vous pourrez estimer en moyenne mais pas précisément (vous ne pourrez pas désactiver les interruptions comme recommandé pour pulseIn() puisque vous en dépendrez).
Je me dis que vous aurez donc une incertitude plus grande qu’avec la fonction bloquante (utilisée généralement pour de très courts instants) qui compte précisément un nombre de cycles ?
Sinon effectivement si ICP est dispo (1 seule pin je crois sur UNO) et qu’on peut utiliser cette feature alors c’est fait pour ça et ce sera le
Plus précis.
ce n'est pas à la résolution que je pense (elle ne dépend que du timer utilisé) c'est à l'exactitude du temps relevé : avec l'ICP c'est du hard que l'on peut lire quand on veut, avec une PCINT on ne peut lire cette valeur que directement dans le registre TCNTxà l'intérieur de l'ISR, c-à-d avec un décalage ... et pas toujours le même si une une autre ISR était déjà en cours d'exécution, ou si dans l'ISR on fait des tests de durée variable.
il faut tout considérer : fréquence des événements, durées min/max des impulsions, besoin de relever des valeurs extrèmes (proches du min et du max du timer), autres ISR pouvant perturber les chronos, etc... et bien sûr : ICP ou pas
mais là on sort (un peu) du cadre de la question initiale ... même si je trouve ce sujet fort intéressant
en fait, si, et même à l'utilisation : on peut très bien envisager une fonction (ISR) de captures/calculs qui tourne en tâche de fond et mémorise les 2 temps fronts montant/descendant, pour ensuite n'avoir qu'à les consulter dans la boucle
Le faire à la main pour une pin, pourquoi pas (et encore faudrait pouvoir être sûr de lire le front que l’on veut et pas celui de la derniere fois) mais faire une fonction générique qui s’adapte à la pin que l’on veut c’est une autre affaire je pense.
Mais surtout mon point était sur la précision obtenue par rapport à la boucle en assembleur où on compte les cycles d’horloge surtout si on mesure quelque chose de très court. Comme vous le dites la PCINT peut ne pas être déclenchée immédiatement si on est dans une autre ISR plus prioritaire. Donc ça va jouer sur la précision et à mon avis c’est pour cela qu’ils ont écrit la fonction sous cette forme plutôt qu’une interruption.
Indépendamment des réserves que tu as ajoutées et que je trouve parfaitement recevables, on n'est pas là pour travailler pour la Terre entière, on peut faire du cousu main.
L'important est de faire quelque chose qui fonctionne.
L'écriture et l'utilisation de bibliothèques ne sont aucunement une obligation.
Heureusement que l'on peut, que l'on pourra toujours, faire des réalisations bien ciselées et cuites aux petits oignons.
Ce sera une application spécifique.
Par contre, il y a un point qui me choque.
Le sujet est particulier et difficile.
Je ne comprends pas la démarche qui consiste à imposer un modèle de microcontrôleur sans tenir compte de l'adéquation du modèle choisi avec les impératifs techniques du projet.
Pire, on fait le développement avec un modèle, probablement parce qu'il était disponible au fond d'un tiroir, et la réalisation définitive sera avec un autre modèle forcément différent.
C'est mettre la charrue avant les bœufs et se mettre des bâtons dans les roues.