Micro contrôleurs AVR/Les PORTs
Le nombre de PORTs disponibles sur les AVR dépend de la série. À part la série TINY qui sont des composants de petites tailles, les AVRs de la série Mega comportent au moins les PORTs B, C et D.
Le PORT pour entrer et sortir des informations
modifierOn rappelle que l'opérateur d'affectation = du C est asymétrique. Écrire
var1 = var2; // met la valeur de var2 dans var1
est complètement différent de
var2 = var1; // met la valeur de var1 dans var2
Profitons-en pour rappeler que dans le premier cas, seule la valeur de var1 change (pas celle de var2).
Le registre DDRB
modifierCe registre est d’un fonctionnement très simple et est lié au fonctionnement du PORTB.
Chaque bit de DDRB positionné à 0 configure la broche correspondante en entrée. Chaque bit à 1 configure la pin en sortie.
Au reset de l'AVR®, toutes les pins sont mises en entrée, afin de ne pas envoyer des signaux non désirés sur les pins. Les bits de DDRB seront donc mis à 0 lors de chaque reset.
Notez que l'entrée est faite à l'aide de PINB et non de PORTB :
PORTB = val;
mais
val = PINB;
Les entrées des PORTx peuvent être connectées à une résistance de rappel au +5 V de manière interne, cette sélection s’effectuant par une écriture dans le registre PORTx (écriture d'un '1' avec bit correspondant en entrée pour pullup et écriture d'un '0' pour désactiver le pullup). Cela veut dire que les pull-up peuvent être choisis individuellement dans un PORT, contrairement aux PIC 16F !
Les registres PORTC et DDRC
modifierCes registres fonctionnent exactement de la même manière que PORTB et DDRB, mais concernent bien entendu les seules 7 pins PC6 ... PC0. Les seuls 7 bits utilisés sont les bits de poids faibles.
Voyons maintenant les particularités du PORTC.
Les 7 bits de DDRC sont désignés par DDC0 ... DDC6. Mais si vous ne voulez pas vous encombrer la mémoire, utilisez PC0 ... PC6, cela fonctionnera de la même façon !
Des LEDs et des boutons poussoirs sur des PORTs
modifierLe but de cette section est d'étudier quelques connexions électriques à partir des PORTs d'un microcontrôleur. Nous nous contenterons des Diode électroluminescente et des boutons poussoirs.
Le PORT et sa modélisation électrique
modifierLe modèle électrique est très simple : on le modélise comme d'habitude à l'aide de Thevenin.
Il est raisonnable de prendre un Imax de 40 mA pour un ATMega8.
Contrairement à ce qu'indique la figure on prendra toujours un Rth de 50 Ohms. |
Connecter et dimensionner des LEDs
modifierUne LED (ou Diode électroluminescente) est une diode et par conséquent se modélise de la même manière :
Retenez les valeurs typiques notées dans la figure pour Ud=1,8 V et rd=0 Ohm.
Il y a deux façons typiques pour connecter des LEDs :
À gauche c’est le microcontrôleur qui est à l'origine du courant. À droite c’est lui qui reçoit le courant passant par la LED et provenant d'une alimentation. Évidemment, il faut un un logique sur le bit PA1 pour allumer la LED de gauche et un zéro logique sur le bit PA2 pour allumer la LED de droite.
Exercice 1
modifierNous allons essayer de dimentionner R1 dans les montages ci-dessus.
1°) Une led rouge (Kingbright λ = 627 nm 15mcd à 10 mA VD = 1,95 V) est montée comme à gauche sur le bit b0 du PORTB d'un ATMega8. À l'aide du modèle de Thévenin du PORT, on vous demande d'évaluer la résistance R1 à mettre pour avoir un courant ne dépassant pas 5 mA.
2°) Une led verte (Kingbright λ=565 nm 12mcd à 10 mA VD = 2,09 V) est montée comme sur le schéma de gauche (sur le bit b2 du PORTB). Calculer R1 sans prendre l'approximation de Rth pour avoir un courant qui ne dépasse pas les 4 mA.
3°) On désire commander deux leds rouge en série. Faire le schéma et dimensionner correctement la résistance.
Connecter des boutons poussoirs
modifierIl est naturellement possible de connecter des boutons poussoirs à un PORT et de demander au micro-contrôleur de dire si le bouton est appuyé ou relâché. (Sur un robot mobile on peut utiliser ce principe pour détecter des objets)
Regardez attentivement le dessin de gauche et en particulier la connexion sur le bit PB4. On sait parfaitement ce qu’il se passe si le bouton est appuyé : on est relié à Vcc on aura donc un un logique en lecture. Mais qu'en est-il si on lâche le bouton poussoir ? Tout dépend de la technologie du PORT. La technologie TTL fournirait un un logique donc aucune différence suivant que le bouton est appuyé ou pas !
- L'idée qui consiste à croire que puisqu'on est relié à rien, alors on lit systématiquement un zéro logique est parfois une idée fausse !!!
- Le bit PB4 du schéma de droite ne fonctionne pas forcément comme on l'attend : lâché est un un logique, appuyé est un zéro logique !
- Le bit PB0 du schéma de droite fonctionne normalement : appuyé = un logique, relâché = zéro logique
Il faut donc utiliser une résistance supplémentaire que l’on appelle résistance pullup (ou Résistance de tirage en français). Soit elle existe à l'intérieur du PORT, soit il faut l'ajouter à l'extérieur du PORT.
La gestion des résistances internes de tirage dépend fortement du processeur. Sur le PIC c’est un seul bit pour tous les PORTs. Ici, pour les AVR, il suffit de passer le PORTx en entrée à l'aide du registre DDRx associé d'écrite un '1' logique dans PORTx là où vous voulez la résistance pull-up.
Exercice 2
modifierOn connecte deux interrupteurs comme indiqué dans la figure sans utiliser de résistance pull-up interne (puisqu'elle est externe). Les deux LEDs de l'exercice 1 sont elles aussi connectées.
1°) On désire écrire un programme C qui ne fait rien si on n'appuie sur aucun bouton poussoir, fait clignoter la LED rouge si l’on appuie sur un bouton, fait clignoter la led verte si on appuie sur l'autre bouton, et les deux LEDs si l’on appuie sur les deux boutons.
1-a) Donner les 4 valeurs possibles de la variable interrupteurs avec l'instruction
interrupteurs = PINB & 0x60;
1-b) Compléter alors le morceau de code ci-dessous pour en faire un programme :
#undef F_CPU
#define F_CPU 25000000UL
#include "util/delay.h"
leds = 0x00;// variable de gestion des LEDs
// boucle d'attente ATTENTION PB6=1 et PB5=0 au repos
while(interrupteurs == 0x20)
interrupteurs = PINB & 0x60;
switch(interrupteurs) {
case 0x60 : PORTB = leds^0x10;break;
case 0x00: PORTB = leds^0x80;break;
case 0x20 : PORTB = leds^0x90;break; // les deux
}
_delay_ms(1000);
2°) Peut-on modifier facilement le programme pour que les deux LEDs fonctionnent à deux fréquences différentes ?
1-a) Nous appelons les interrupteurs par le nom des broches auxquels ils sont connectés.
- PB6 et PB5 lâchés : 0x40
- PB6 lâché et PB5 appuyé : 0x60
- PB5 lâché et PB6 appuyé : 0x00
- PB6 et PB5 appuyés : Ox20
1-b)
#undef F_CPU
#define F_CPU 25000000UL
#include "util/delay.h"
int main() {
unsigned char leds = 0x00;// variable de gestion des LEDs
// setup()
DDRB |= 0x90; //PB7 et PB4 en sortie
// loop()
while(1) {
// boucle d'attente ATTENTION PB6=1 et PB5=0 au repos
while(interrupteurs == 0x20)
interrupteurs = PINB & 0x60;
switch(interrupteurs) {
case 0x60 : PORTB = leds^0x10;break;
case 0x00: PORTB = leds^0x80;break;
case 0x20 : PORTB = leds^0x90;break; // les deux
}
_delay_ms(1000);
} // while(1)
return 0;
} // main
2°) L’idée est de calculer le PGCD des deux périodes et de faire tourner la boucle infinie à période correspondante, ou plutôt à la demi-période si on utilise une technique de basculement avec un OU exclusif. On incrémentera ensuite deux compteurs, un pour chacune des leds, qui compteront jusqu'à réaliser les demi-périodes correspondantes et réaliseront alors le basculement.
Exercice 3
modifierOn désire réaliser un dé comme indiqué sur le schéma ci-dessous.
Pour simplifier la lecture du schéma : D1 est relié à PD1, D2 à PD2, D3 à PD3, D4 à PD4, D5 à PD5, D6 à PD6 et enfin D7 à PD7.
1°) Calculer les sept valeurs prédéfinies pour allumer correctement le dé et les ranger dans un tableau si la première case du tableau éteint tout.
Quel est l’affichage du dé correspondant à :
unsigned char tableau[7]={0x00,0x10,0x44,0x54,0xAA,0xBA,0xEE};
2°) Écrire un programme complet qui affiche les 6 valeurs du dé avec un délai d'attente de 3s utilisant la fonction "_delay_ms()" de la librairie libc.
3°) On désire maintenant générer de manière aléatoire le score affiché sur le dé. Pour cela on vous propose d’utiliser la fonction ci-dessous.
unsigned char pseudoAleat(int Lim) {
unsigned char Result;
static unsigned int Y=1;
Y = (Y * 32719 + 3) % 32749;
Result = ((Y % Lim)+1);//+1 : eviter 0
return Result;
}
3-a) Calculer la première valeur de cette fonction si Lim=6.
3-b) Écrire le programme général qui génère les valeurs du dé de manière aléatoire dès l'appui du bouton poussoir (attente de 0,3s pour éviter les rebonds).
4°) Proposer un schéma pour réaliser deux dés en utilisant un seul PORT de sortie sur 8 bits. Écrire le programme correspondant.
1°) Seuls 2 et trois sont affichés bizarrement. On préférerai donc :
unsigned char tableau[7]={0x00,0x10,0x82,0x92,0xAA,0xBA,0xEE};
3-b)
#include <util/delay.h>
unsigned char pseudoAleat(int Lim) {
unsigned char Result;
static unsigned int Y=1;
Y = (Y * 32719 + 3) % 32749;
Result = ((Y % Lim)+1);//+1 : eviter 0
return Result;
}
int main(){
unsigned char tableau[7]={0x00,0x10,0x82,0x92,0xAA,0xBA,0xEE};
unsigned char i;
// setup()
DDRD = 0xFE; // PD7, PD6 , ...,PD1 en sortie
// loop()
while(1) {
while ((PIND & 0x01)==0x01)
_delay_ms(300);
i= pseudoAleat(6);
PORTD = tableau[i];
// _delay_ms(1000);
}// while(1)
return 0;
}
4°) L'astuce consiste à regrouper les leds qui s'allument ensembles (pour un dé) sur un même bit du PORT : il faut ainsi 4 bits par dé. Pour cela le bouton de lancer doit donc être relié à PB0.
Interfacer un clavier
modifierSur un PC, le clavier est complètement décodé. C'est-à-dire que lorsqu'une touche est appuyée, sa position sur le clavier est envoyée sur la liaison PS2. Le fait d'envoyer la position et non le code ASCII permet de gérer les claviers en divers langues.
Pour de petites applications, on utilise un clavier à 12 touches. Il est composé de simples contacts et le décodage est réalisé par le système informatique. Avec seulement 8 touches, un PORT de 8 bits en entrée suffit. Si le clavier possède plus de 8 touches, il faut:
- soit utiliser d'avantage d'entrées,
- soit multiplexer les entrées en deux étapes.
En utilisant 4 fils pour les lignes et 4 fils pour les colonnes, on peut différencier par croisement 16 touches. On utilise donc 8 fils reliés à 8 bits d'un PORT pour 16 touches. Pour nos 12 touches on peut câbler comme indiqué ci-dessus. Il s'agit ensuite de procéder en deux phases, une pour la détection de la colonne et une autre pour la détection de ligne.
Exercice 4
modifierQuestion 1 : détermination du numéro de colonne
modifier#define NOTAKEY 127
// colonne 1 à gauche
char lecture_colonne(){
char ch;
DDRB=0xF0; // 1111 0000
PORTB = 0x00; // B4, B5,B6 et B7 mis à 0 !!! surtout pas 0x0F =>pullup !!!
ch = PINB & 0x0E; // on ne garde que les bits intéressants B1, B2 et B3
switch (ch) {
case 14 : return 0;//aucune touche
case 6 : return 1;//a gauche
case 10 : return 2;// au milieu
case 12 : return 3;//a droite
// si autre cas, deux touches ou autre
default : return NOTAKEY;
}
}
Commenter en testant les bonnes valeurs du case.
Question 2 : détermination du numéro de ligne
modifierProgrammer les directions avec DDRB (PB7-PB4 en entrée et PB3-PB1 en sortie).
Quel est le code correspondant : sous-programme char lecture_ligne()
Question 3 : détermination du caractère
modifierÀ partir des deux informations précédentes transformer le numéro de colonne et le numéro de ligne en caractère correspondant sur le clavier : '1' ou '2' ou ... ou '0' ou '#'
Interfacer des éléments de puissance pour faire tourner des moteurs
modifierQuand le courant à sortir dépasse 15 mA (par bit), il faut trouver une solution amplifiée. C'est ce que nous allons examiner dans cette section.
Utilisation de transistors BJT
modifierPour commander des sorties puissantes il faut ajouter des transistors (BJT Bipolar Junction Transistor). Les sorties puissantes peuvent être :
- des relais
- des bobines
- des LEDs
- des moteurs
Exercice 5
modifierOn veut commander une LED qui nécessite 16 mA. Le transistor choisi a un b de 100.
1°) Calculer IB ?
2°) En déduire R1 (si l’on prend une marge de 30% ou si l’on prend 1 mA par défaut)
3°) En déduire RC pour un VCEsat=0,2 V (pour une alimentation Vcc=5 V) ?
4°) Une résistance RC de 1/4W suffit-elle ?
Interfacer des sorties puissantes avec des FET
modifierOn peut utiliser des transistors à effet de champ à la place des BJT. Nous examinons le cas des MOSFET. Un paramètre important à vérifier est la tension de grille nécessaire à la commutation. En effet pour les micro-contrôleur alimenté en 3,3 V cette tension peut s'avérer un peu forte pour des MOSFET de puissance.
Il existe des familles spécialement faites pour être commandées directement par des PORTs. Voir ZVN4206A (600 mA) et ZVN4306A (1,1A) de chez Zetex.
Avec isolation galvanique
modifierIl faut utiliser des opto-coupleurs. Ils permettent aussi une isolation galvanique ce qui est important si la tension d'alimentation est très différente de celle du micro-contrôleur. Cette isolation garantit qu'aucun courant de l'élément de puissance finira dans le micro-contrôleur, ce qui le détruirait.
Commander des bobines moteurs et relais avec BJT
modifierIl existe des transistors de puissance adaptés. Par exemple le transistor BD139 propose un gain b compris entre 25 et 250. On peut l’utiliser avec un courant IC=1,5 A (3A en pointe). Son faible gain nécessite un courant IB assez important, allant au-delà des possibilités des ports traditionnels (typiquement 10 mA). Par exemple pour commuter 1A, il faut un IB=40mA dans le pire des cas. Il faut donc un transistor supplémentaire.
Ce montage appelé Darlington existe en boîtier unique : par exemple le BCX38C peut commuter des courants jusqu'à 800 mA.
Exercice 6
modifierOn considère le montage Darlington ci-contre. Le transistor 2N2222 est bloqué, il circule 40 mA dans IB
1°) Si R2 est choisi à 330 Ohms, quelle puissance passe dans R2 ?
2°) Si le transistor 2N2222 est saturé (VCEsat=0,2 V) quelle puissance passe dans R2 ?
3°) Lorsque le BD139 est saturé, il circule Il circule IC=1A et l’on a VCEsat=0,70 V. Quelle puissance est dissipée dans le BD139 ?
Commander plusieurs moteurs avec un circuit unique
modifierIl existe des circuits capables de commander 7 moteurs comme le ULN2003 qui a à peu près les mêmes caractéristiques que le BCX83C (mais sept fois). Ils sont appelés Darlington driver IC. Le ULN2803 possède 16 broches et peut commander 8 moteurs avec la possibilité d’utiliser deux sorties identiques pour commander un seul moteur.
Le circuit ULN2003 est capable de délivrer 500 mA sous 50 V.
Exemple concret
modifierVoici l'électronique de commande des moteurs du robot mobile ASURO présenté dans un autre chapitre de ce projet. A noter que l’on utilise ici des transistors discrets et non pas un circuit de puissance intégré.
On remarquera une commande d'un moteur avec un pont en H qui permet de faire fonctionner le moteur dans les deux sens.
Un exercice sur ce schéma a été ajouté dans le chapitre AVR et robotique : ASURO de ce cours. Cet exercice nécessite cependant une bonne connaissance du timer 1 expliqué dans le chapitre ultérieur.