Cette rubrique PicTrain est assez nouvelle (deux mois) pour que vous puissiez aisément nous rattraper et sauter en marche ! Aujourd´hui à notre menu :
10.
10.1.
10.2.
10.3.
10.4.
10.5.
10.6.
10.7.
 3e application : PicTrain2 : le programme
 Initialisation
 Traitement des commandes
 Inertie
 Freinage et accélération
 Changement de sens
 Le traitement de l´interruption
 Conclusion
Pictrain2 : le programme
Il y a trois parties principales dans le programme pictrain2-1.asm  :
Les initialisations : Timer, interruptions et entrées-sorties,
Le traitement des commandes,
L´interruption Timer0.
10.1. Initialisation
10.1.1. Les définitions
PTI+   Les listings de programme respectent un code de couleurs choisi par Jidé pour Jidé mais dont nous n'hésitons pas à vous faire profiter ;–)
Une constante (“littéral”) égale à 6 est définie comme C_Cran. On en verra l´utilisation dans les parties accélération et freinage.
Les 6 ports d´E/S du microP sont utilisés ici, GP0 et GP1 en sortie, de GP2 à GP5 en entrée.
Nous déclarons également les trois variables (registres généraux).
10.1.2. Initialisation des paramètres
On déclare d´abord les ports 2 à 5 en sortie, avec résistances de rappel (il n´existe pas de résistance de rappel sur le port 3).
On initialise ensuite le pré-diviseur, par trois des bits du registre OPTION_REG selon les valeurs du tableau ci-contre  :
Dans notre cas (4 ligne du tableau : pour diviser par 16), il faut mettre à les deux bits de poids faible. On voit l´ensemble de ce registre dans la fiche ci-dessous prêt à imprimer sur une fiche en carton au format standard 125 x 75 mm :
 

Ensuite, on active les interruptions en mettant à les bits du registre de contrôle des interruptions INTCON :
GIE : activations des interruptions d´une manière générale,
T0IE : activation Timer0.
Toutes les autres interruptions sont désactivées (les autres bits de INTCON sont à ).
ATTENTION : tous ces registres sont dans BANK1.
10.2. Traitement des commandes
Dans la boucle principale nous allons traiter toutes les commandes, accélération et freinage, l´arrêt d´urgence et le changement de sens.
Rappel des principes :
D´une manière automatique et indépendante, l´interruption Timer0 génère le signal rectangulaire, de fréquence 240 Hz, de rapport cyclique variable proportionnel à la variable VA_Vitesse ;
Les commandes, gérées dans notre boucle principale, ne font que modifier la valeur de cette variable VA_Vitesse ;
Une inertie est prévue, dans le cas d´un appui continu sur un bouton la modification de la vitesse est effectuée tous les 1/6 de seconde ;
Le changement de sens ne peut être fait que si la vitesse est zéro (VA_Vitesse = ) ; une led indique quand cette condition est réalisée.
10.3. Inertie
Pour introduire de l´inertie (et également pour faire fonction d´anti-rebond), nous avons une première boucle qui fait que le traitement des commandes ne s´exécute que tous les 1/6 de seconde (0,15 seconde).
On verra plus loin que nous avons 42 “crans” de vitesse, passer de zéro à vitesse maximum (ou l´inverse), le balayage complet s´effectuera donc en 7 secondes.
Tant que le compteur VA_Compteur_Inertie est supérieur à , on tourne dans la boucle BouclePrincipale ; au moment où le compteur passe par zéro, on saute à la suite du programme. Ce compteur est décrémenté à passage au créneau haut dans l´interruption Timer0, soit à la fréquence de 240 Hz, ce qui veut dire que si on le “charge” avec la valeur 40, il passe par zéro tous les 240/40 secondes, soit 0,15 seconde.
Indicateur d´état Z : pour tester la valeur du compteur, nous utilisons “l´indicateur d´état Z”. Ce n´est pas Z comme Zorro, mais évidemment Z comme zéro. Cet indicateur est le bit Z dans le registre spécial STATUS.
Cet indicateur est à lorsque le résultat d´une instruction est zéro, comme par exemple la soustraction : si nous avons le chiffre 1 dans un registre général, et que soustrayons le chiffre , le résultat est zéro, mais surtout l´indicateur STATUS,Z est à pour nous indiquer que le résultat (donc le contenu du registre) est zéro.
Cet indicateur est utilisé dans beaucoup d´instructions comme les additions ou soustractions, les décréments ou incréments, les opérations logiques et dans certains move.
Dans notre cas, il s´agit de l´instruction movf, qui copie le contenu du registre donné en opérande soit dans W (avec ,W), soit dans le même registre (avec ,F comme ici). Si vous avez tout compris, vous vous rendez compte que l´instruction movf VA_Compteur_Inertie,F ne fait rien, car elle copie le contenu du registre dans le même registre, ce qui semble assez inutile ! Détrompez-vous, c´est la meilleure manière que nous avons de tester si le registre est à , ce qui nous intéresse ici.Lorsque le registre est à , c´est-à-dire que nous allons exécuter le traitement des commandes, nous remettons d´abord 40 dans ce registre.
10.4. Freinage et accélération
Nous sommes passés dans le traitement des commandes (boutons) proprement dit.
Il y a ici trois actions possibles :
Accélérer : augmenter la vitesse d´un cran,
Freiner : diminuer la vitesse d´un cran,
Stop : mettre la vitesse à zéro.
La vitesse est proportionnelle à la valeur VA_Vitesse (revoir le chapitre sur le Timer0), est peut varier de 0 à 255. D´une manière pratique, pour augmenter ou diminuer la vitesse, il faut se limiter à une quarantaine de “crans”, on va donc additionner (ou soustraire) 6 à chaque action sur un bouton.
Notre vitesse va donc varier de 0 à 255 mais par pas de 6, soit 255/6 = 42 crans, ce qui est plus raisonnable. On va maintenant traiter en détail les trois actions :
10.4.1. Accélération
Pour nous faciliter la vie, on commence par copier la vitesse dans W, rappelez-vous que de toute façon on doit toujours passer par W ; on verra à la fin des traitements que l´on aura la nouvelle vitesse (modifiée ou non) toujours dans W, et on la recopiera à ce moment dans le registre VA_Vitesse.
Pour l´accélération on teste l´entrée IO_Acceleration : si elle est à on passe à l´instruction suivante qui est un saut, et on ne fait rien. Rappelez-vous aussi que l´on utilise en général une logique “inverse” due à l´électronique, qui fait qu´au repos l´entrée est au + 3 volts par la résistance de rappel, et active (bouton poussoir enfoncé) au niveau zéro volt. On traite donc l´accélération si le bit IO_Accélération est à (c´est-à-dire clear).
Ensuite on va aborder une nouvelle instruction : addlw (add litteral to W). Cette instruction ne fait qu´additionner un littéral à W (qui contient notre vitesse initiale) et qui contiendra notre nouvelle valeur après.
RAPPEL : Où est mon littéral ? On retrouve ici une des “facilités de programmation” : j´ai en effet remplacé le littéral par une constante définie au début du programme. Cette définition se fait par une directive C_Cran EQU d´6´ placée en début de programme, et qui indique au logiciel MPLAB que chaque fois qu´il rencontre C_Cran, il doit le remplacer (EQU=équivalence) par la valeur d´6´ qui est bien un littéral.
Donc addlw C_Cran est égal (équivalent) à addlw d´6´.
Dans l´instruction suivante, on teste (btfsc) un autre “indicateur d´état”, C : celui-ci est l´indicateur de “retenue” (carry) ou de dépassement. Je m´explique : lorsque vous additionnez à la main 8 et 6, vous écrivez “4 et je retiens 1” (= 14) ; vous avez bien un “dépassement” sur vos unités, et un 1 de retenue.
Ici c´est pareil, sauf que l´on raisonne sur des octets, c´est-à-dire des valeurs entre 0 et 255. Que se passe-t-il lorsque le registre contient 252 et que l´on ajoute 6 ?
Pour vous le résultat est 258, mais cela notre microP ne sait pas faire. Pour lui le résultat est 2 avec un débordement (une retenue) et c´est ce débordement qui est signalé par l´indicateur d´état STATUS,C.
Si vous avez suivi, revenons à notre programme : en additionnant 6 dans W, le résultat peut être supérieur à 255, il faut donc tester le débordement, et si oui remettre 255 dans W. Si vous continuez d´accélérer (d´appuyer sur le bouton “accélérer”), à chaque fois il y aura débordement (255 plus 6), mais la valeur sera toujours ramenée à 255.
Avant de passer au freinage, relisez encore une ou deux fois cette partie, il y a beaucoup de nouveautés, et il faudrait avoir bien compris, car la suite utilise exactement les mêmes notions, mais dans l´autre sens (en moins !).
PTI+   Les bits STATUS. — La plupart des instructions effectuant des opérations sur des registres peuvent activer des bits indiquant le “statut” du résultat, dont les deux plus importants sont :
Zéro (STATUS,Z), qui indique que le résultat de l´opération est 0, donc que le registre est à 0,
Carry (STATUS,C), qui indique un dépassement de capacité (ou une “retenue”), c´est-à-dire que le résultat est supérieur à 255 ; dans ce cas, la valeur dans le registre est XXX (=résultat de l´opération) moins 256.
D´autres bits de statut existent dans ce microP, mais ils sont peu utilisés.
10.4.2. Freinage
On retrouve ici la même séquence que pour l´accélération : d´abord on teste l´entrée IO_Freinage, si elle est à (inactive), on saute.
Si elle est à , on rentre dans le traitement de freinage.
On utilisera ici l´instruction de soustraction subwf (substract W from F), qui soustrait la valeur de W du registre en opérande. On charge donc d´abord notre valeur dans W (movlw C_Cran), valeur qui est toujours notre constante d´inertie, puis on soustrait W du registre VA_Vitesse qui contient la vitesse actuelle.
Le résultat de la soustraction peut être rangé au choix dans le même registre (par ,F) ou dans W (par ,W), ce que nous faisons ici car j´ai besoin de la nouvelle vitesse dans W. Remarquez que dans ce cas, le registre initial VA_Vitesse n´est pas modifié.
Comme pour l´addition, on a ici un risque de débordement, par exemple si la vitesse est à 4 et on soustrait 6, le résultat n´est pas —2 (il n´existe pas de nombre négatif), mais 254, et on va donc utiliser l´indicateur d´état STATUS,C pour tester le débordement.
MALHEUREUSEMENT, il fonctionne ici à l´envers, il est actif (C = 1) s´il n´y a pas de débordement. Je ne m´étends pas sur le sujet, aucun intérêt pour nous, retenez juste que les soustractions sont l´inverse d´une addition (ça, vous le saviez déjà), mais aussi pour le fonctionnement de STATUS,C.
Dans notre programme on saute donc à la suite si STATUS,C est à (set), sinon (ce qui veut dire qu´il y a débordement au sens soustraction), on est passé en dessous de zéro, et on ramène donc notre vitesse dans W à zéro. Pour ce faire, on utilise l´instruction clrw (clear W), qui met à le registre W : c´est la même chose que clrf qui mettait à un registre, mais appliqué à W.
Donc une fois la vitesse à zéro, tout appui sur freinage ne change rien, la vitesse reste à zéro.
Si vous aviez compris l´accélération, le freinage n´a pas posé de problème, sauf cette inversion de l´indicateur, mais il n´y a rien à comprendre : c´est comme ça.
10.4.3. Stop
Ici c´est tout simple, il s´agit d´un arrêt immédiat (d´urgence), donc on met W à par clrw si le bouton STOP est appuyé, c´est-à-dire IO_Stop à .
Nous avons maintenant traité les trois boutons qui ont une action sur la vitesse, et le résultat est toujours dans W. Il nous reste à ramener cette nouvelle vitesse dans VA_Vitesse par :
La dernière chose à faire est de traiter le changement de sens, c´est-à-dire la dernière entrée IO_SENS.
10.5. Changement de sens
10.5.1. Logique et électronique
On s´est imposé la contrainte de ne pouvoir changer de sens que lorsque la vitesse est à zéro, encore faut-il savoir quand la vitesse atteint ce niveau. En effet, dans les crans très bas (1 ou 2 ou 3...), suivant la locomotive, elle n´avancera pas, même si dans notre microP la vitesse n´est pas encore à zéro. Il est donc visuellement impossible de savoir quand la vitesse est effectivement à zéro .
J´ai donc introduit une led qui s´allume lorsque la vitesse est réellement à zéro (VA_Vitesse), et c´est seulement dans cet état-là que le sens peut être inversé.
Comme nous n´avons que 6 entrées-sorties sur ce microP, qui sont déjà toutes occupées (2 en sortie, 4 pour les boutons en entrée), et qu´il nous en faut une supplémentaire, on peut soit changer de microP pour un modèle plus puissant, soit réfléchir un peu et utiliser une des E/S soit en entrée soit en sortie selon le cas.
C´est bien entendu (!) cette dernière solution que nous allons mettre en œuvre dans ce schéma électronique  :
En fonctionnement normal, l´E/S 4 (commande STOP) est configurée en entrée, relié au 3 V par R6 (220 K), et au 0 V par R7 (4,7 K) si on appuie sur le bouton poussoir.
La led montée en parallèle n´est pas allumée, le courant est bien trop faible.
Lorsque la vitesse est à zéro (le poussoir STOP n´est donc plus utile), l´E/S est en sortie, état haut (= 1) et alimente la led qui nous indique que la vitesse est zéro et que l´on peut donc changer de sens de marche.
PTI+   Pour les électroniciens. — Le montage proposé sur le poussoir S2 peut sembler curieux, mais il marche.
Les caractéristiques électriques du microP sont en effet assez différentes des circuits plus classiques CMOS : pour une entrée à 0, elle doit être vraiment proche de 0 V, typiquement inférieure à 0,8 V ou 1 V selon l´entrée.
Dans notre montage, l´entrée est à 1,7 V, suffisant pour détecter un 1 par le microP.
10.5.2. Le programme
Nous n´entrons dans cette partie du programme lorsque, à la fin du traitement de la vitesse, celle-ci est à 0. On s´impose en effet comme contrainte que le changement n´est possible qu´à l´arrêt de la locomotive.
La première chose est d´allumer la led, il faut donc passer l´E/S 4 en sortie, état 1. On attend ensuite une action :
soit un changement de sens (bouton S1 SENS),
soit un redémarrage de la loco (bouton S4 accélération).
Dans les deux cas, pour éviter les problèmes de rebond, une seule action nous fait sortir immédiatement de ce traitement et revenir dans la situation standard du chapitre précédent.
Test vitesse zéro :
Nous allons ici aussi utiliser l´instruction movf, qui copie un registre sur lui-même, et qui nous permet par l´indicateur d´état Z de tester le zéro de la vitesse.
Si ce n´est pas le cas, on revient au début du programme principal.
Allumage LED :
Ici on allume la LED en changeant l´E/S 4 en sortie (TRISIO,4 à ) et en positionnant la sortie à .
Rappel 1 : C´est dans le registre TRISIO que l´on indique les sens des E/S, bit à pour sortie (zéro comme O, comme Output) ou à pour entrée (1 comme I comme Input).
Rappel 2 : BANK0 et BANK1 : Certains registres spéciaux, dont TRISIO, sont situés dans la deuxième partie de la mémoire du microP, et il faut donc d´abord se positionner dans cette partie (BANK1), et ne pas oublier de revenir après (BANK0).
Changement de sens :
Nous avons ici une boucle d´attente d´une des deux actions possibles :
accélération : on saute à la fin de cette section sans changer de sens ;
changement de sens (IO_SENS) : dans ce cas on exécute l´inversion du bit zéro de GPIO avec un “ou exclusif” (xorwf) de GPIO et du chiffre b'00000001'.
Rappel : xorwf (cette instruction a déjà été vue dans l´introduction et le montage Klaxon). Un “ou exclusif” (xor) entre deux bits donne 1 si les deux bits sont différents (0 et 1), et 0 si les bits sont identiques (00 ou 11).
Si le bit n° zéro de GPIO était à zéro : zéro xor 1 le met à 1 (cf. ligne 3 du tableau ). Si le bit visé était à  : 1 xor 1 le met à zéro (ligne 4 du tableau).
On ramène ici l´E/S 4 en entrée (TRISIO,4 à ), et surtout on met la vitesse (qui est à 0) à 1 avant de revenir au programme principal, ce qui évitera de revenir dans la boucle de changement de sens.
10.6. Le traitement de l´interruption
Cela doit être la troisième ou quatrième fois que nous reprenons le fonctionnement du Timer, et si vous êtes certains d´avoir tout compris, sautez tout de suite au morceau de programme plus loin. Mais je vous recommande cependant de lire les quelques lignes ci-dessous, moi-même je trouve que ce n´est pas évident du tout, et une nouvelle couche ne vous fera pas de mal.
Notre Timer compte, il s´incrémente de 1 toutes les 16 µS, et déclenche une interruption chaque fois qu´il passe de 255 à zéro.
Nous allons donc inverser (de à ou de à ) notre sortie IO_Sortie_Train à chaque interruption. Nous avons par ailleurs notre variable VA_Vitesse, qui contient la valeur le la vitesse.
Si la sortie est à , on la passe à , puis on charge le timer avec la valeur de VA_Vitesse, ce qui fait qu´il va compter 255 – VA_Vitesse avant la prochaine interruption.
Si la sortie est à , on la passe à , et on va compter 255 – (255 – VA_Vitesse), c´est-à-dire VA_Vitesse jusqu´à la prochaine interruption.
Une période à 1 plus une période à étant égale à 255 – VA_Vitesse + VA_Vitesse, c´est-à-dire toujours 255, donc une fréquence fixe de 240 Hz, quelle que soit la valeur de VA_Vitesse. C´est ce qui est réalisé dans le morceau de programme ci-dessous (il n´y a pas de nouvelle instruction, vous devriez pouvoir le lire et le comprendre).
À chaque passage de la sortie à , nous avons un décrément du compteur d´inertie, qui permet de tenir compte de l´inertie dans l´accélération ou le freinage, voir plus haut. decf est une nouvelle instruction, qui ne fait que soustraire 1 au registre indiqué en opérande. Le résultat peut être soit rangé dans le même registre (si on indique ,f comme ici), soit rangé dans le registre W (si on indique ,W).
Dans ce dernier cas, si on récupère la valeur initiale moins 1 dans W, le registre général initial reste inchangé.
10.7. Conclusion
Ce montage fonctionne sans problème, ni réglages, il a été testé chez moi et chez Jidé avec différents types de locos.
Plusieurs variantes sont possibles : par exemple on pourrait ajouter, sur le circuit de puissance, un dispositif permettant de récupérer un courant continu proportionnel au rapport cyclique.
Pire, certains songent déjà à récupérer la F.C.E.M. (voir ce terme dans les ouvrages spécialisés) pour améliorer encore le rendement ! Et avec ça, on peut faire rouler au ralenti une 020 Decauville Hoe Jouef de 1967, qui ne marchait même pas en 1967 ! [Montage à venir dans Ptitrain.]
En ce qui concerne le programme, vous pouvez bien entendu modifier les paramètres pour avoir plus ou moins de crans dans la vitesse, ou changer l´inertie, ou la fréquence de 240 hertz... je fais confiance à votre imagination.
On pourrait aussi sophistiquer le programme en calculant une valeur de cran différente pour les crans bas et les crans haut, sachant que la vitesse réelle de la locomotive n´est pas une fonction linéaire de la variable VA_Vitesse.
Bref, beaucoup de choses sont possibles*, ce montage est une base pour de futurs développements ; je sais par exemple que Jidé souhaite l´appliquer à des automatismes plus compliqués comme par exemple une version du Numerax à microP (bonne chance !).

* Il serait également possible de remplacer carrément le transistor de puissance directement par un LM317**, ce qui permettrait de profiter des sécurités en cas de surcharge et de court-circuit, de ce composant. Idée de Jidé, fondée sur ce schéma de National Semiconductor , pas encore testée.
** J.P.M. de l'A.M.F.N. nous écrit :
“Malheureusement, nous sommes plusieurs à avoir essayé, et ça ne donne pas de bons résultats, parce que cette fonction du LM317 est très surfaite : en pratique, il se met en limiteur de courant, surchauffe un max et finit par griller si on n'a pas prévu un radiateur surdimensionné... à moins que ce soit une autre partie du circuit (palpeurs de prise de courant des locos...) qui grille !”

Psi

11/1/08
N.B. — Textes, schémas, programmes © Psi pour Ptitrain. Photos Jidé ou D.R. quand signalé. — Toutes vos remarques et commentaires sont bienvenus, et les pages de Ptitrain ne sont pas statiques : les erreurs sont corrigées sitôt connues, les améliorations, éclaircissements, etc. feront l´objet de mises à jour fréquentes.
Ptitrain, l´e-magazine du train éclectique. — Directeur de la publication : Christophe Franchini.
Rédacteur en chef : Jean-Denis Rondinet