Communication serie et interruption matériel

Bonjour à tous,

J'ai développé une application pour ma moto avec un arduino en début d'année, celui-ci contrôle un starter automatique et un indicateur de rapport engagés.

Je suis actuellement en train de développer un autre montage qui va cette fois piloter un régulateur de vitesse, toujours pour ma moto.

Dans chacun des montages j'utilise une interruption matériel pour comptabiliser les impulsions envoyer par les capteurs de vitesses moteur et vitesse moto (pour le moment vitesse moteur dans le premier montage et vitesse moto dans le montage régulateur en cours de montage).

Je voudrais établir une communication série entre les 2 cartes pour qu'elles s'échange quelques données (3 états de capteur et une valeur analogique).

Les faire dialoguer entre elle ne pose pas de problème, mais comme j'ai lu dans les docs sur les interruptions que les données série envoyer pendant l'interruption était perdu je me demande comment va réagir mon système.

Je fouille internet à la recherche d'une réponse depuis hier sans succès, aussi si vous pouviez m'éclairer sur la façon de gérer les interruptions avec une com série, ça m'aiderait énormément.

J'ai pensé à faire la transmission pendant que je détache l'interruption mais j'ai peur que ça ne fonctionne pas ou que ça ralentisse énormément le fonctionnement.

Voila, je précise que je suis automaticien et que la programmation de micro contrôleur est relativement récente pour moi.
Je donnerai autant d'informations qu'il le faudra pour éclairer vos lanternes.

Merci par avance pour votre aide.

Cam84

Effectivement, la plupart des micros (en fait, probablement tous!) dévalident les interruptions quand on est dans une routine d'interruption, mais il y a moyen de revalider les interruptions dans une routine d'interruption (en arduino: sei() ).

Le mieux tout de même, c'est de s'arranger pour en faire le moins possible dans l'interruption et de lever un flag pour continuer le travail dans une fonction ordinaire.

très grossièrement:

 bool flag = false;

ISR(vect)
// traiement PWM
{ 
  // on en fait le mons possible ici
  flag = true ;
}

void Traitement()
{
}

void loop()
{
  if (flag)
       {
         flag = true ;
        Traitement() ;        
      }
}

Merci pour ta réponse Guyt, je n'ai pas tout compris mais en faire le moins possible je pense que c'est déjà le cas, voici la portion de code de l'interruption :

} // fin de la fonction loop() - le programme recommence au début de la fonction loop sans fin


  // ------ gestion de l'interruption matériel de lecture du capteur de vitesse ------

void vt_fun()
 {
  ++comptVt; //comptage vitesse
 }



// ********************************************************************************

// --- Fin programme ---

Lors de l'interruption un compteur est incrémenté.

Ensuite, toute les 500ms je transfère la valeur du compteur dans une variable et je remets à 0 le compteur :

{
   detachInterrupt(VITESSE);
   vt = comptVt;
   comptVt = 0;
   Serial.print (vt); // envoie de la vitesse sur la carte de gestion de rapport engagé pour qu'elle envoie à son tour ses données
   while (Serial.available()== 0) {};
   delay(10);
   attachInterrupt(VITESSE, vt_fun, RISING);
   
 }

Je détache l'interruption pendant que je transfère la valeur de mon compteur.
J'ai rajouté la transmission de la vitesse de la moto pour l'autre carte afin de lui indiqué qu'elle pouvait envoyer les données, mais comme elle aussi est soumise à une interruption matériel, je pense que ça peut posé problème aussi, à moins d'envoyer une requête tant que l'autre carte ne répond pas mais avec le risque de faire tourner les deux cartes dans la semoule.

Je ne sais pas si j'ai été suffisamment clair dans les explications, je vais vous refaire un topo :

  • cartes Arduino :
    1 - carte 1, gestion du starter automatique, du rapport engagé. Cette carte récupère le signal du compte tour de la moto. Ce montage fonctionne depuis plusieurs mois déjà.
    2 - carte 2, gestion d'un régulateur de vitesse, cette carte récupère (entre autre) la vitesse de la moto. Ce montage est en cours.
  • les 2 cartes utilise une interruption matériel pour comptabiliser les impulsions venant des capteurs de vitesse.
  • les 2 cartes doivent dans l'idéal pouvoir communiquer par le port com série pour s'échanger des informations comme l'état du moteur (marche/arrêt), la position du sélecteur (repos ou actionné), la position du rapport engagé et enfin la valeur d'un capteur de luminosité (pour régler la luminosité des leds d'affichages).
  • Le problème, comment gérer la com avec les interruptions matériel?

Guys, peux-tu m'expliquer un peu plus sur la possibilité de maintenir l'interruption de la com pendant l'interruption matériel.

Encore merci pour ton aide :wink:

Je ne sais pas où tu en es avec les interruptions matérielles, alors je comence du début.

Une interruption matérielle permet l'appel de fonctions par un événement donné: un caractère reçu sur le port sériel, une transition de signal à une entrée etc.

Pour que le contrôleur puisse générer l'interruption, il y a 2 conditions:

  1. Le type d'interruption doit être validé (par exemple, sur réception de caractères). Ça ce fait généralement par un bit dans un registre

  2. Le système d'interruption doit être validé. ça se fait par l'appel d'une instruction machine accessible par ces fonctions:

sei() ; // valide
cli() ; // dévalide

Sur Arduino, les interruptions sont validés au démarrage du programme.

L'implantation des fonctions d'interruptions sur les Atmel est de toute beauté (à l'autre extrémité Microchip, de la pure me..de (je l'ai pas dit!)).

Une fonction d'interruption:

ISR(vecteur)
{
}

Il ne s'agit pas d'une fonction ordinaire, car elle doit sauver les registres en cours d'utilisation lorsque l'interruption est appelé. Avant d'effectuer le retour, elle remet les registres internes dans ses états initiaux.

en gros une fonction d'interruption ressemble à ça:

void InterruptHandler(void)
{
   cli() ;   // dévalide les interruption
   PushAll ; // Sauve les registres internes sur la pile
   
   // fait la job
   PopAll ; // remet les registres
   sei() ;   // revalide les interruptions
}

Au retour de l'interruption, si des interruptions sont en attentes, la plus prioritaire sera traitée.

On peut toujours revalider les interruptions dans une routine d'interruption, mais c'est une mauvaise idée, à mon avis. Y a pas mal de brassage de sauvegarde/remise des contenus de registres et le CPU finit par passer tout son temps à gérer les transferts sur la pile et n'a plus le temps de faire quoi que ce soit.

Je suis convaincu que ton problème se résout sans être obligé de revalider les interruptions dans les routines d'interruption (voir l'exemple que je te donne.

Si tu me donnes du temps pour y réfléchir, je pourrais te donner quelques indices supplémentaires.

C'est là que je vois le trou qu'il y a entre ce que je connais sur la programmation d'un arduino et ce que les programmeurs comme toi on niveau connaissance.

En tout cas c'est sympa de me donner un coup de main ça me permet non seulement de résoudre mon problème mais aussi de progresser.

L'idée que j'ai pour résoudre le problème (tu vas me dire si c'est pas trop idiot) serai d'utilisé les interruptions matériel de mes cartes que pendant un lap de temps, une demie seconde par exemple, laissant le champ libre le reste du temps pour le traitement du programme et la com.
Car au final, je n'ai pas spécialement besoin que ses interruptions soit permanentes, si je fais une mesure pendant 1/2 second toute les secondes ça devrait être suffisamment précis.

Est ce que ça tient la route?

Est ce que ça tient la route?

Absolument. Sois patient un petit peu, je vais finaliser un module de librairie qui devrait te faciliter la tâche. Là, je suis sérieusement malade (nous, les gars, quand on est malade, on est malade :wink: ).

ça me ferait même plaisir, parce quand on vieillit, on a peut-être de l'expérience, mais on a pas nécessairement des idées nouvelles. Tu sais, avec mes nouveaux Arduino, je sais comment faire, mais je ne sais pas quoi faire. :cry:

Pour bouleshitter un peu plus, je pense qu'on a une ou deux bonnes idées dans la vie, alors faut savoir les capitaliser quand ça passe.

A+

Salut Cam84,

Mon petit "TaskManager" est fonctionnel, regarde ici:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1290990435/15#15

Tu verras dans l'exemple "TestTaskManager" un "blinker" contrôlé par le port sériel. Tu verras dans le "loop", y a pas de code!

Si tu veux tester ça:

  1. Tu fais un copier/coller de "TaskManager.h" et "TaskManager.cpp"
    dans un nouveau répertoire dans "librairies", par exemple:

C:\arduino-0021\libraries\Guyt

Tu inclus la librairie Guyt dans ton programme via le menu:

Sketch|Import Library...

Bye!

Me revoila avec des news :slight_smile:

Donc finalement je me suis tourné vers une communication en i2c, pour plusieurs bonnes raisons :

  • ne bloque pas la com serie pour pouvoir débugger le programme avec le terminal
  • ne semble pas perturbé par les interruption matériel (en tout cas dans mon cas pas de soucis)
  • j'ai rajouté un afficheur digital piloté par un SAA1064 en i2c (une pierre deux coup comme on dit)

J'ai donc une carte maitre et l'autre esclave et un afficheur esclave aussi.
La carte maitre envoi des données à l'esclave et en récupère, elle gère également l'affichage.

L'envoi de donnée n'a pas posé de problème, la réception d'une donnée non plus mais j'ai pas mal pataugé quand j'ai voulut en recevoir 2 de l'esclave.

Pour ceux qui cherche la réponse, il faut envoyer les données dans un tableau et indiquer le nombre qu'on envois.
Au début je faisais plusieurs Wire.send() mais seul le dernier envoi était pris en compte.

Je vous explique rapidement ce que j'ai fait avec ces petites mais non moins puissante carte Arduino.

Comme je l'ai expliqué dans le premier post, j'ai réalisé en début d'année dernière un premier montage pour ma moto avec 2 fonctions, remplacer le starter manuel par un automatique (un servomoteur tire sur le câble du starter) et un indicateur de rapport engagé.

Le starter utilise les signaux de température moteur, de vitesse de rotation moteur, le bouton start.
L'indicateur de rapport engagé utilise un capteur (potentiomètre) qui détecte la position de la pédale du sélecteur, récupère le signal du capteur de neutre et un capteur de luminosité pour faire varier la luminosité des diodes de l'affichage.
Au lieux d'utilisé un afficheur digital, j'ai préférer intégrer 6 diodes dans le compte tour, une par vitesse positionnées en face des chiffres correspondant.

Le nouveau montage utilise donc une seconde carte arduino et un servomoteur qui vient tirer sur la commande des gaz en parallèle de la commande existante.
La sécurité est assuré en hard par une coupure de l'alimentation du relais de commande du servomoteur par les freins. Le signal des freins est doublement contrôler par l'arduino de 2 façons différentes.
L'activation du régulateur est faite uniquement par le bouton +, l'Arduino ne peut pas l'activé par contre il l'autorise sous plusieurs conditions (vitesse mini, boite sur rapport 4 mini, etc) et il peut donc le déactivé.
Le régulateur peut être mis sous et hors tension.
Le régulateur récupère plusieurs signaux, les freins, le relais de freins, l'embrayage, la béquille, la vitesse de la moto, le bouton start et un bouton basculant (+/- du régulateur).
La com en i2c permet de récupérer la vitesse de rotation du moteur, un signal indiquant que le moteur est démarré, la valeur du capteur de luminosité, la position du rapport engagé et si la pédale de sélecteur est appuyée.
Dans l'autre sens, le régulateur renvois la vitesse de la moto et une commande pour l'afficheur qui gère le mode de configuration.

J'ai rajouté sur le premier montage une lecture de la tension de la batterie et donc sur l'afficheur, moteur éteint, j'affiche la tension de la batterie, moteur allumé la vitesse instantané de la moto, les vitesses présélectionnées dont celles précédemment utilisée, et en mode de réglage, les paramètres du régulateur (PID).

Pour finir, j'ai rajouté 2 diodes au tableau de bord, une pour indiqué si la béquille est déployé et l'autre pour indiquer l'état du régulateur (vert sous tension, orange activé, rouge défaut).

A noté que régulateur n'affecte en rien le fonctionnement de la moto si celui-ci est en panne ou débranché.

J'avais fait une petite vidéo du rapport engagé : Indicateur de rapport engagé Honda 800 VFR - YouTube

Le servomoteur du starter automatique :

Le boitier du premier montage :

Le mécanisme du régulateur :

Les diodes et l'afficheur rajoutées :

Le boitier du régulateur :

A noté que j'ai aussi rajouté un relais qui bascule le bouton start pour être utilisé par le régulateur et en même temps il m'allume les phares/codes dès que le moteur a démarré.

Au niveau du programme tout fonctionne et je suis en train de faire les essais du régulateur pour le régler.

Voila, je me suis bien cassé les dents dessus mais content d'y être arrivé et surtout j'ai appris plein de truc sur la programmation en C, la com série/i2c et le régulateur PID.

Encore merci pour votre aide et notamment Guyt (je n'ai pas eu besoin de ton TaskManager mais il est intéressant et je le garde bien de coté).