Exercice — positionnement d'un chariot de transfert, programme MikroC avec interruption, dans l'esprit des sessions 2018–2025
Dans un entrepôt, un chariot de transfert roule le long de 60 allées numérotées de 00 à 59 ; il est à l'allée 00 à la mise sous tension. Un capteur inductif délivre une impulsion H à chaque allée franchie. L'opérateur choisit l'allée de destination No sur deux roues codeuses BCD, puis appuie sur START : le chariot avance (KM1) ou recule (KM2) jusqu'à ce que sa position Np soit égale à No. Un nouvel appui sur START met la carte hors service ; la position Np reste alors mémorisée.
Carte à PIC 16F877A : H sur RB0/INT ; RB1 et RB2 commandent, par les transistors T1 et T2, les relais KM1 (avance) et KM2 (recul) ; voyant rouge Dr (chariot en mouvement) sur RB3 ; voyant vert Dv (carte en service) sur RB4 ; RB5 et RB6 non connectées ; START sur RB7 (1 quand on appuie) ; port C vers deux décodeurs 7447 (dizaines sur RC7…RC4, unités sur RC3…RC0) ; roues codeuses sur le port D (SW2 dizaines sur RD7…RD4, SW1 unités sur RD3…RD0). Registre INTCON : bit 7 GIE (validation générale), bit 4 INTE (validation de RB0/INT), bit 1 INTF (indicateur de RB0/INT).
N.B : les broches non connectées sont considérées comme des sorties.
// Déclaration des variables
unsigned short Np, No, st;
sbit KM1 at RB1_bit;
sbit KM2 at ………… ;
sbit Dr at ………… ;
sbit Dv at ………… ;
// Procédure d'interruption : une impulsion H
void interrupt() {
if (KM1) Np = Np + 1; // le chariot avance
if (KM2) ……………… ; // le chariot recule
INTF_bit = 0;
}
void main() {
// Configuration des registres
TRISB = 0x…… ; TRISC = 0x…… ; TRISD = 0x…… ;
PORTB = 0; PORTC = 0;
INTCON = 0x…… ; // GIE et INTE
Np = 0; st = 0;
while (1) {
// Lecture de l'allée choisie
No = ……………… ;
// Mise en service / hors service par START
if (Button(&PORTB, 7, 1, 1)) st = 1;
if (st && Button(&PORTB, 7, 1, 0)) {
Dv = ……… ; st = 0; }
// Affichage de la position
PORTC = ……………… ;
// Commande des contacteurs
if (Dv && (Np < No)) { KM1 = 1; KM2 = 0; }
else if (Dv && (Np > No)) { KM1 = ……; KM2 = ……; }
else { KM1 = ……; KM2 = ……; }
// Voyant rouge : chariot en mouvement
Dr = ……………… ;
}
}1. Pourquoi a-t-on relié le capteur H à l'entrée RB0/INT plutôt qu'à une entrée lue dans la boucle ? Quelle autre broche du PIC permettrait de compter ces impulsions sans procédure d'interruption, et avec quel module ?
2. Compléter les déclarations sbit et la configuration des registres TRISB, TRISC, TRISD et INTCON.
3. Compléter la procédure d'interruption, qui met à jour le compteur de position Np. Pourquoi le sens du comptage est-il pris sur KM1 et KM2 ? Quel est le rôle de l'instruction INTF_bit = 0 ?
4. Compléter la lecture de la consigne et l'affichage de Np (fonctions Bcd2Dec et Dec2Bcd).
5. Compléter l'instruction qui bascule Dv. Expliquer le rôle des deux lignes qui utilisent Button et la variable st : à quel moment Dv change-t-il d'état ?
6. Compléter la commande des contacteurs et du voyant Dr.
7. Le chariot est à l'allée 18 ; les roues codeuses affichent 4 (dizaines) et 5 (unités). Donner PORTD en binaire et en décimal, la consigne No, le contacteur excité, le nombre d'impulsions H reçues avant l'arrêt, puis la valeur de PORTC au départ et à l'arrivée. Que se passerait-il si l'on avait écrit No = PORTD ?
Voir la correction commentéeAprès avoir posé votre démarche
1. Idée : une impulsion peut arriver pendant que la boucle est occupée ailleurs (Button attend 1 ms, les contacteurs sont en cours de mise à jour…). Sur RB0/INT, chaque front de H déclenche aussitôt interrupt() : aucune impulsion n'est perdue, quel que soit l'endroit où se trouve la boucle. L'autre solution est l'entrée RA4/T0CKI : le timer TMR0, en mode compteur (OPTION_REG, T0CS = 1), compte seul les fronts.
sbit KM2 at RB2_bit;
sbit Dr at RB3_bit;
sbit Dv at RB4_bit;
TRISB = 0x81; TRISC = 0x00; TRISD = 0xFF;
INTCON = 0x90;TRISB ; décodeurs en sortie (0x00) ; roues codeuses en entrée (0xFF) ; INTCON : GIE = 1, INTE = 1.
3. Np = Np - 1; Chaque impulsion vient d'un déplacement réel, dont le sens est fixé par le contacteur excité : KM1 = 1, le chariot avance et Np augmente ; KM2 = 1, il recule et Np diminue. Le front sur RB0 met INTF à 1 ; s'il n'est pas remis à 0, la procédure se relance sans fin dès sa sortie. INTF_bit = 0 réarme l'interruption pour l'impulsion suivante.
4. No = Bcd2Dec(PORTD); et PORTC = Dec2Bcd(Np); Les roues codeuses délivrent un chiffre BCD par quartet : 0100 0101 signifie 45, pas 69. Inversement, chaque 7447 attend un chiffre BCD.
5. La première ligne mémorise l'appui (st = 1 quand RB7 est resté à 1 pendant 1 ms, ce qui élimine les rebonds). La seconde attend le relâchement (RB7 = 0) : Dv = ~Dv; bascule alors une seule fois et st revient à 0. Dv change donc d'état au relâchement, une fois par appui, même si START est maintenu longtemps ; il sert de mémoire « en service » et allume le voyant vert.
else if (Dv && (Np > No)) { KM1 = 0; KM2 = 1; }
else { KM1 = 0; KM2 = 0; }
Dr = KM1 || KM2;7. PORTD ; Bcd2Dec(69) . : KM1 (avance) et Dr = 1. Le chariot reçoit impulsions. Au départ, PORTC = Dec2Bcd(18) (0x18 = 24) ; à l'arrivée, PORTC : les afficheurs montrent 45, KM1 = 0 et Dr = 0. Avec No = PORTD, la consigne vaudrait 69 : le chariot avancerait au-delà de la dernière allée (59) sans jamais trouver Np = No.