L’objectif de cette séance est de commander un moteur à courant continu puis un moteur pas à pas par l’association de la carte de développement DE2 et d’une carte auxiliaire intégrant les circuits de puissances.
A travers la synthèse de ces projets, nous nous familiariserons avec la notion de machine d’état.
1 Descriptif de la carte auxiliaire
Nous utilisons pour notre carte auxiliaire un circuit L298, au sein duquel sont implantés deux ponts en H, associé à la logique de commande, comme l’indique la structure interne de ce circuit sur la figure suivante :
Comme on peut le noter sur la figure précédente, les diodes de puissance ne sont pas intégrées dans le L298, il faut les ajouter sur la carte, comme le montre la figure suivante. Il est alors possible de commander deux moteurs à courant continu (sortie OUT1-OUT2 ou bien OUT3-OUT4) ou un moteur pas à pas bipolaire deux phases (les deux phases étant connectée respectivement en OUT1-OUT2 et OUT3-OUT4).
L’alimentation Vss en 5V (partie commande) est faite directement par la carte DE2, tandis que l’alimentation de puissance Vs se fait par les entrées « + » et « masse » de la carte auxiliaire via une source externe, avec une tension dépendant des moteurs utilisés (maximum 46 V). Une diode de protection évite l’inversion de polarité de l’alimentation (mais crée une chute de tension de 0,7 V).
Deux résistances « shunt » RS1 et RS2 permette de mesurer le courant passant par les transistors de puissance.
Les bornes du FPGA reliées au circuit L298 sont données en annexe.
2 Alimentation de puissance de la carte et mesure
Pour alimenter la partie puissance le la carte, respecter le protocole suivant :
- utiliser pour Vs une alimentation stabilisée incluant une limitation de courant ; - l’alimentation étant déconnectée de la carte, régler sa sortie à 6 V ;
- mettre la sortie en court-circuit et limiter le courant à 0,5 A ;
- supprimer le court-circuit et relier maintenant l’alimentation à la carte auxiliaire.
Pour effectuer des mesures à l’oscilloscope, on placera les sondes aux points tests prévus à cet effet, et uniquement sur ces points. Les parties du schéma associées à ces points tests sont donnés en annexe.
3 Mise en œuvre de la commande d’un moteur à courant continu
3.1 Descriptif du programme
Nous allons tester notre carte en pilotant un moteur à courant continu. Nous implantons pour cela dans le FPGA de la carte DE2, le programme correspondant au descriptif suivant :
PIN_N2
H INPUTVCC
PIN_G26
BP1 INPUTVCC
PIN_N23
BP2 INPUTVCC
PIN_W26 VCC
RST INPUT
PIN_M19 S_MLI OUT PUT
PIN_M23 NS_MLI OUT PUT
PIN_K25 ENB OUTPUT
PIN_N24 OUTPUT ENA
PIN_R24 S_MLIB OUT PUT
PIN_R20 NS_MLIB OUT PUT
PIN_AE22 LED_BP1
OUT PUT
PIN_W19 LED_BP2
OUT PUT
PIN_AA20 LED_RST
OUT PUT H BP1 BP2
IMP_BP1 IMP_BP2 bp_imp
inst H C_OUT
S div_50
inst3
clock reset BPLUS BMOINS
CONS[7..0]
Seq
inst4
VCC RST
RST
BP1
H C_EN CONS[7..0]
S_MLI NS_MLI MLI
inst5
Ce programme génère en sortie un signal modulé en largeur d’impulsion, « S_MLI » est envoyé sur l’entrée In1 du circuit L298, tandis que son complémentaire « NS_MLI » est envoyé sur l’entré In2.
L’entrée ENA du L298 est fixée au niveau logique 1.
Les mêmes signaux « S_MLIB » « NS_MLIB » et Vcc sont envoyés sur les commandes du second pont via les entrées In3, In4 et ENB.
Les signaux modulé en largeur d’impulsion sont obtenus en comparant la valeur d’un signal de consigne « CONS[7..0] » sur huit bits, à la valeur de sortie d’un compteur huit bits, incrémenté par le signal d’horloge à 50 Mz lorsque le signal d’autorisation C_EN (Clock Enable), à environ 5 MHz le permet. Le cycle complet de 28=256 impulsions, correspond alors a une fréquence de découpage de 5 MHz/256, soit environ 20 kHz.
Le signal C_OUT (alimentant C_EN) à 5 MHz est obtenu par la division par 10 de l’horloge à 50 MHz de la carte DE2, par le bloc « div_50 ».
Grâce au bloc séquenceur « SEQ », ce programme test va permettre de régler 5 vitesses différentes pour le moteur, en fonction de l’appui sur les boutons poussoir BP1 et BP2 (ce qui générera les signaux BPLUS et BMOINS) de la carte DE2.
Pour passer à la vitesse supérieure ou inférieure ; ces 5 vitesses correspondent à 5 valeurs de la consigne « CONS » et donc à 5 valeurs de rapport cyclique aux bornes du moteur.
On établi sans difficulté que le rapport cyclique α est donné par l’expression : α= CONS/255,
et la tension moyenne aux bornes du moteur par la relation classique d’un pont en H : Umoy = Vs (2 α-1) Vs étant la tension d’alimentation du pont Les 5 valeurs de consigne imposées par le séquenceur sont :
- 0, ce qui correspond à une vitesse maximale du moteur en sens négatif (α=0, Umoy=-Vs) ; - 64, soit la moitié de la vitesse maximale du moteur, en sens négatif (α=0,25, Umoy=-Vs/2) ; - 128, soit une vitesse nulle (α=0,5, Umoy=0) ;
- 192, soit la moitié de la vitesse maximale en sens positif (α=0,75, Umoy=Vs/2) ; - 255, soit la vitesse maximale en sens positif (α=1, Umoy=Vs).
Le fonctionnement du séquenceur a été décrit par la machine d’état suivante (voir le sujet sur la machine d’état pour plus de précisions) :
Le passage d’un état au suivant, se fait à chaque coup d’horloge en testant les boutons poussoir : - pour augmenter la vitesse (en valeur relative), il faut vérifier la condition
BPUS . BMOINS
(ce qui se traduit par « BPLUS & ~BMOINS » dans la syntaxe de description de machine d’état au sein de Quartus),
- pour diminuer la vitesse, il faut vérifier la condition
BMOINS . BPLUS
;- une réinitialisation de la machine d’état, par appui sur le bouton poussoir « RST », place celle- ci dans l’état E128, qui correspond à l’arrêt du moteur ;
Remarques : l’utilitaire de description de machine d’état de Quartus impose que les conditions de passage d’un état à l’autre soit exclusives (deux conditions ne peuvent être valides en même temps) ; on ne peut donc avoir comme conditions BPLUS pour une branche et BMOINS pour l’autre.
L’horloge du système fonctionnant à 50 MHz, les informations BPLUS et BMOINS sont testées 50 millions de fois par secondes ; pour un fonctionnement correct, un appui sur les boutons poussoirs correspondants, doit donc durer une impulsion d’horloge.
Le bloc « BP_IMP » a pour rôle de convertir le NL0 de durée aléatoire, obtenu lors de l’appui sur les boutons poussoir BP1 et BP2, en signaux au NL1 de durée 20 ns (soit une période de l’horloge à 50 MHz).
Le bloc « BP_IMP » peut être vu comme un détecteur de front descendant.
Comme on peut le voir sur le schéma général associé au programme, les différents boutons poussoirs sont associés à des DEL, afin d’en visualiser l’appui.
3.2 Mise en œuvre
Ouvrir un nouveau projet dans Quartus.
Proposer un programme VHDL permettant de synthétiser les blocs « div_50 » et « MLI » ; simuler les solutions obtenues.
Etudier la syntaxe VHDL du bloc BP_IMP donné en annexe et dans le dossier ressource
« ressources/TP_Quartus/TP6_mcc_pap/mcc » et simuler le fonctionnement du programme.
Synthétiser le séquenceur « Seq » à l’aide de l’utilitaire de Quartus (voir le cours sur les machines d’état) et simuler le résultat.
Regrouper ces sous ensembles dans un schéma général, compiler le projet et programmer le FPGA sans alimenter la carte auxiliaire et vérifier à l’oscilloscope que le fonctionnement est bien celui attendu.
Connecter le moteur et l’alimentation suivant le protocole indiqué au chapitre 2, et tester le fonctionnement.
En cas de problèmes, on trouvera des exemples de solutions dans le dossier ressource et en annexe.
4 Mise en œuvre de la commande d’un pas à pas
4.1 Descriptif du programme
Le programme implanté dans le FPGA de la carte DE2 est associé au schéma suivant :
H C_OUT S div_1s
inst2
H INPUTVCC
RST INPUTVCC
Sens INPUTVCC
P_demiP INPUTVCC
P_demiP Sens
RST OUTPUT LED_RST
LED_SENS OUTPUT
LED_p_demip OUTPUT
SEG[6..0]
OUTPUT
PH[3..0]
OUTPUT
ENA OUTPUT
ENB OUTPUT VCC PIN_N2
PIN_G26
PIN_N23 PIN_W26
PIN_AE22 PIN_W19 PIN_AA20
PIN_N24 PIN_K25
PIN_M19 PIN_M23 PIN_R24 PIN_R20
PIN_AF10 PIN_AB12 PIN_V13 PIN_V14 PIN_AC12 PIN_AD11 PIN_AE11 BCD[3..0] SEG[6..0]
DECODEUR
inst1 C_EN
clock C_EN reset S P
PH[3..0]
ETAT[3..0]
SEQ
inst C_EN
Le bloc « div_1s » nous génère un signal d’horloge de période 1 secondes, en divisant par 50 millions l’horloge à 50 MHz de la carte DE2.
Cette horloge d’une seconde va commander un séquenceur, permettant au moteur de fonctionner dans un sens ou dans l’autre suivant que le bouton poussoir relié à l’entrée « Sens » est appuyé ou non, et en mode « pas entiers une phase » ou en mode « demi-pas » suivant que le bouton poussoir associé à l’entrée « P_demiP » est appuyé ou non.
La sortie « PH[3..0] » du séquenceur envoie les signaux adéquat sur les entrées In1 à In4 du circuit L298, suivant les chronogrammes représentés ci-dessous :
Fonctionnement en mode pas entier une phase (un seul sens de rotation représenté)
Fonctionnement en mode demi-pas (un seul sens de rotation représenté)
Un bouton poussoir associé à l’entrée « RST » permet de réinitialiser le séquenceur.
Des diodes électroluminescentes de la carte DE2 permettent de visualiser l’appui sur ces boutons.
On notera que le séquenceur est rendu synchrone grâce à une entrée d’autorisation d’horloge
« C_EN ». Contrairement au programme précédent, le rapport de division de l’horloge étant important, cette option est ici indispensable.
La machine d’état suivant décrit le fonctionnement de notre séquenceur :
Comme indiqué précédemment, le passage d’un état à l’autre se fait : - uniquement si « C_EN » est au NL1 quel que soit les états, - dans un sens ou dans l’autre suivant l’entrée « S »,
- en passant par tous les états, ou juste les états pairs, suivant l’entrée « P ».
La sortie « PH[3..0] du séquenceur commande les entrés Inx du L298, tandis que la sortie
« ETAT[3..0] » permet de visualiser le numéro de l’état actif, et de l’indiquer sur un afficheur 7
4.2 Mise en œuvre
Ouvrir un nouveau projet sous Quartus, importer le diviseur de projet précédent, le sauvegarder dans le nouveau projet afin d’éviter que sa modification n’affecte l’étude précédente, et modifier le programme pour répondre au nouveau cahier des charges.
Proposer un programme VHDL pour le décodeur.
Synthétiser le séquenceur à l’aide de l’utilitaire de Quartus et tester la solution obtenue.
Regrouper les sous ensembles en un schéma général et programmer le FPGA sans alimenter la carte auxiliaire, vérifier au niveau de l’afficheur que le fonctionnement est bien celui attendu (dans un sens dans l’autre, en mode pas entier, demi-pas).
Connecter la sonde de l’oscilloscope sur les points tests correspondants aux entrées In1 et In4 et vérifier l’effet des différents modes de fonctionnement.
Connecter le moteur et l’alimentation suivant le protocole indiqué au chapitre 2, et tester le fonctionnement.
En cas de problème, on trouvera un exemple de solution en annexe et dans le dossier ressources
« ressources/TP_Quartus/TP6_mcc_pap/pap »
Annexe 1 : connectique de la carte
Broche du L298 sur la carte
auxiliaire
Broche du FPGA sur la carte DE2
Nom de la borne sur la
carte DE2
Borne du connecteur
GPIO_1 Carte DE2
Repère sur la carte DE2
Couleur sur la
carte auxiliaire
5 : In1 M19 GPIO_1[4] 5 IO_B4 Blanc
6 : EnA N24 GPIO_1[10] 13 IO_B10 Vert
7 : In2 M23 GPIO_1[3] 4 IO_B3 Jaune
10 : In3 R24 GPIO_1[13] 16 IO_B13 Jaune
11 : EnB K25 GPIO_1[0] 1 IO_B0 Vert
12 : In4 R20 GPIO_1[14] 17 IO_B14 Blanc
Annexe 2 : Programmes associés à la commande d’un moteur à courant continu
Block BP_IMP : détecteur de front descendant
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--les paquetages std_logic_1164 et std_logic_unsigned de la bibliothèque ieee --permettent respectivement l'utilisation du type std_logic et l'addition avec ce type --à chaque appui sur les boutons poussoirs (NL0 sur la carte DE2),
-- les sorties correspondantes génère une impulsion unique --d'un seul coup d'horloge (détection du front descendant) ENTITY bp_imp IS
port ( H : IN STD_LOGIC;
BP1, BP2 : IN STD_LOGIC;
IMP_BP1, IMP_BP2 : OUT STD_LOGIC);
END bp_imp;
ARCHITECTURE arch OF bp_imp IS
SIGNAL BP10, BP11, BP20, BP21 : STD_LOGIC;
BEGIN
-- à chaque front d'horloge, le niveau de l'entrée BPx est affecté à BPx0 -- au coup d'horloge suivant BPx0 est affectée à BPx1
-- une fonction ET entre BPx0 et le complémentaire de BPx1 permet de détecter le front descendant sur BPx
PROCESS (H) BEGIN
IF (H'EVENT AND H = '1') THEN
BP10<= BP1; BP11<= BP10;
BP20<= BP2; BP21<= BP20;
END IF;
END PROCESS;
IMP_BP1<=BP11 AND NOT BP10;
IMP_BP2<=BP21 AND NOT BP20;
END arch;
Block div_50 : division de l’horloge
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--les paquetages std_logic_1164 et std_logic_unsigned de la bibliothèque ieee --permettent respectivement l'utilisation du type std_logic et l'addition avec ce type --H est le signal d'horloge à 50 MHz
--S est un signal de rapport cyclique 1/2, résultant de la division de l'horloge --C_OUT est le signal de retenue qui passe au NL1 lorsque le compteur est plein
--pour notre application on souhaite un signal à environ 256*20 kHz --il faut donc diviser par 10, ce qui nécessite 4 bits pour X
ENTITY div_50 IS
port ( H : IN STD_LOGIC;
C_OUT : OUT STD_LOGIC;
S : OUT STD_LOGIC);
END div_50;
ARCHITECTURE archdiv OF div_50 IS
SIGNAL X : STD_LOGIC_VECTOR (3 downto 0);
CONSTANT M : INTEGER :=10 ; BEGIN
PROCESS (H) BEGIN
--compteur modulo M
IF (H'EVENT AND H = '1') THEN
IF X >= M-1 THEN X <= (others=>'0');
--mise à 0 de tous les bits de X ELSE X <= X + 1 ;
END IF;
END IF;
END PROCESS;
--à la moitié du comptage on change la valeur de S (rapport cyclique 1/2) S<='1' when X>=M/2 else '0';
--mise à 1 de la retenue lorsque X passe à 0 C_OUT<='1' when X=M-1 else '0';
END archdiv;
Block MLI : Modulateur de largeur d’impulsion
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--les paquetages std_logic_1164 et std_logic_unsigned de la bibliothèque ieee --permettent respectivement l'utilisation du type std_logic et l'addition avec ce type ENTITY MLI IS
--génération d'un signal MLI et son complémentaire en S_MLI et NS_MLI --l'horloge H incrémente un compteur X , si C_EN l'autorise
--la sortie du compteur X est comparée à la consigne CONS
port ( H : IN STD_LOGIC;
C_EN : IN STD_LOGIC;
CONS : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
S_MLI : OUT STD_LOGIC;
NS_MLI : OUT STD_LOGIC);
END MLI;
ARCHITECTURE archdiv OF MLI IS
SIGNAL X : STD_LOGIC_VECTOR (7 downto 0);
CONSTANT M: INTEGER :=256 ;
BEGIN
PROCESS (H) BEGIN
--compteur modulo M
IF (H'EVENT AND H = '1') THEN IF C_EN='1' then
IF X >= M-1 THEN X <= (others=>'0');
--mise à 0 de tous les bits de X ELSE X <= X + 1 ;
END IF;
END IF;
END IF;
END PROCESS;
--lorsque la consigne devient supérieure au comptage S_MLI passe au NL1 S_MLI <='0' when X>= CONS else '1';
NS_MLI <='1' when X>= CONS else '0';
END archdiv;
Annexe 3 : Programmes associés à la commande d’un moteur pas à pas
Block div_1s LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
--les paquetages std_logic_1164 et std_logic_unsigned de la bibliothèque ieee --permettent respectivement l'utilisation du type std_logic et l'addition avec ce type ENTITY div_1s IS
--H est le signal d'horloge à 50 MHz
--S est un signal de rapport cyclique 1/2, résultant de la division de l'horloge --C_OUT est le signal de retenue qui passe au NL1 lorsque le compteur est plein --le rapport de division dépend du modulo M
--ajuster en conséquence le nombre de bits du compteur interne X --pour notre application on souhaite un signal à 1 Hz
--il faut donc diviser par 50 000 000, ce qui nécessite 26 bits pour X (2^26=67 108 864)
port ( H : IN STD_LOGIC;
C_OUT : OUT STD_LOGIC;
S : OUT STD_LOGIC);
END div_1s;
ARCHITECTURE archdiv OF div_1s IS
SIGNAL X : STD_LOGIC_VECTOR (25 downto 0);
CONSTANT M: INTEGER :=50000000 ;
BEGIN --compteur modulo M
IF (H'EVENT AND H = '1') THEN
IF X >= M-1 THEN X <= (others=>'0');
--mise à 0 de tous les bits de X ELSE X <= X + 1 ;
END IF;
END IF;
END PROCESS;
--à la moitié du comptage on change la valeur de S (rapport cyclique 1/2) S<='1' when X>=M/2 else '0';
--mise à 1 de la retenue lorsque X passe à 0 C_OUT<='1' when X=M-1 else '0';
END archdiv;
Bloc DECODEUR
-- la bibliothèque ieee contient les paquetages dont la déclaration suit library ieee;
--ce paquetage permet l'utilisation des types STD_LOGIC et STD_LOGIC_VECTOR use ieee.std_logic_1164.all;
-- permet d'utiliser le type STD_LOGIC_VECTOR avec des entiers use ieee.std_logic_unsigned.all;
entity DECODEUR is
port (BCD : in STD_LOGIC_VECTOR (3 downto 0);
SEG : out STD_LOGIC_VECTOR ( 6 downto 0) );
end DECODEUR;
0
-- ---
-- l 0 l
-- 5 l l 1
-- l l
-- ---
-- l 6 l
-- 4 l l 2
-- l l
-- ---
-- 3
architecture ARCH_DEC of DECODEUR is begin
-- attention les leds s'allument pour une sortie à 0
SEG <= "1000000" when BCD=0 else
"1111001" when BCD=1 else
"0100100" when BCD=2 else
"0110000" when BCD=3 else
"0011001" when BCD=4 else
"0010010" when BCD=5 else
"0000010" when BCD=6 else
"1111000" when BCD=7 else
"0000000" when BCD=8 else
"0010000" when BCD=9 else
"1111111" ; end ARCH_DEC ;