Go Down

Topic: plantage d'une interruption externe (Read 499 times) previous topic - next topic

Papa22

Bonjour.
Le 22 février 2016, EXYACC a eu le même problème que celui que je rencontre, affichage des deux premiers caractères d'un Serial.println("...") et deadlock.

ma config :

Arduino Uno R3
un capteur qui donne le cap compas (e-boussole)
un écran LCD 16x2
un capteur laser
un servomoteur
une photorésistance
quelques LEDs dont deux gérées par interruption timer.

Le laser est externe
l'écran est alimenté par une autre source.

une interruption externe (0 sur pin 2) se déroulait normalement puis s'est mise à planter.

Il s'agit d'allumer une LED ou de l'éteindre lorsqu'on coupe un faisceau laser.
Avec des sorties sur le moniteur série pour le debug.

j'ai modifié mon code pour allumer la LED pendant 1 seconde en cas de coupure.
surprise : le moniteur n'affiche que les deux premiers caractères du println, et deadlock.

j'ai remplacé le delay() par un comptage de microsecondes, pareil.
J'ai ôté les envois au moniteur série, idem.

Au final, le sous-pgm d'interruption n'accepte d'exécuter qu'une seule instruction.
J'ai positionné un flag et traité le cas dans la loop et ça marche, mais ça ne me convient pas du tout.
La loop a un cycle de plusieurs secondes et je veux une réponse instantanée lors de l'interruption.


J'ai transféré le programme sur arduino nano et c'est pareil.
A l'époque EXYACC n'avait pas eu d'explication à ce qui lui arrivait, on lui avait fait contourner le problème.

J'ai essayé sur l'interruption1 (pin3), même résultat.

J'ai réduit le code qui prenait 80% des possibilités du nano, ça n'a rien changé.
est-ce que ça parle à quelqu'un ? (avant de vous soumettre mon code)


dfgh

hello
j'ai du mal à suivre

"le moniteur n'affiche que les deux premiers caractères du println, et deadlock"
...
...

"J'ai ôté les envois au moniteur série, idem."

??????

Jambe

est-ce que ça parle à quelqu'un ? (avant de vous soumettre mon code)


Ben oui mais sans code, ce n'est pas facile de deviner ce qui ne va pas...

J'ai positionné un flag et traité le cas dans la loop et ça marche, mais ça ne me convient pas du tout.

C'est pourtant plutôt la bonne méthode, les interruptions doivent être les plus courtes possibles

La loop a un cycle de plusieurs secondes et je veux une réponse instantanée lors de l'interruption.

Il y a des "delay()" dans ta loop pour qu'elle dure si longtemps?

_pepe_

#3
Jul 27, 2017, 11:34 am Last Edit: Jul 27, 2017, 11:51 am by _pepe_
Bonjour

Il semble que la routine d'interruption réalise une grande variété de tâches qui prend beaucoup de temps. Or, en principe, l'exécution du code doit s'organiser de sorte que le programme principal (setup()+loop()) reste le principal code exécuté.

En temps normal, le microcontrôleur doit exécuter ce programme principal, puis quand une interruption survient, ce dernier est mis en attente pour exécuter la routine d'interruption, au terme de laquelle il est repris à l'endroit où l'on s'en était arrêté.


Néanmoins, si la routine d'interruption est trop longue, et dans la mesure où l'on continue de maîtriser la situation, on peut envisager d'autoriser le traitement d'autres interruptions (sei()) durant l'exécution de cette routine, afin qu'une seconde interruption puisse être traitée rapidement.

Toutefois, sauf à activer ou désactiver individuellement toutes les sources d'interruption, cette autorisation est donnée de façon générale, de sorte que la routine d'interruption en cours d'exécution pourrait être rappelée avant son terme et son retour au programme principal.

Mais si cela se produit trop souvent, alors la pile (stack) peut se remplir jusqu'à « déborder » sur le tas (heap), entraînant le dysfonctionnement du programme et du système.

De même, si la routine n'est pas « ré-entrante » (c'est-à-dire si son fonctionnement repose sur des données contextuelles dont l'état impose qu'elle soit terminée avant d'être recommencée), alors son rappel peut également provoquer un dysfonctionnement.


Inversement, si l'on n'autorise pas le traitement d'autres interruptions (ce qui est la situation par défaut), alors la routine d'interruption ne peut pas utiliser l'évolution des informations issues du traitement des autres interruptions, comme par exemple le temps écoulé ou la réception de nouveaux caractères sur une interface série.


Dans ton cas, il serait difficile de savoir ce qui se passe exactement sans une étude sérieuse du système. Mais je vois au moins comme causes possibles les deux que je viens de citer, à savoir :
- un débordement de pile ou une perte de données contextuelles, résultant d'une ré-autorisation des interruptions à l'intérieur de ta routine et d'une survenue trop fréquente de l'interruption par rapport à la durée de la routine ;
- une progression basée sur le temps écoulé (delay(), millis() ou micros()) alors que, faute de traitement périodique adéquat, le compteur correspondant en est réduit à reboucler dans un intervalle de 1,024 milliseconde.

Go Up