« SE3 2025/2026 EC3 » : différence entre les versions
| Ligne 56 : | Ligne 56 : | ||
Étant donné que le microcontrôleur fonctionne à 16 MHz, j’ai appliqué un prescaler de 1024 via les bits CS02 et CS00 (page 87). Le calcul de la fréquence obtenue est le suivant : | Étant donné que le microcontrôleur fonctionne à 16 MHz, j’ai appliqué un prescaler de 1024 via les bits CS02 et CS00 (page 87). Le calcul de la fréquence obtenue est le suivant : | ||
<math>f = \frac{16\,000\,000}{1024 \times 256} | <math>f = \frac{16\,000\,000}{1024 \times 256} = 61 \text{ Hz}</math> | ||
La fréquence obtenue est donc d’environ 61 Hz, ce qui est compatible avec les exigences d’un servo-moteur standard. | La fréquence obtenue est donc d’environ 61 Hz, ce qui est compatible avec les exigences d’un servo-moteur standard. | ||
Version du 3 mars 2026 à 20:13
Objectifs
Réaliser le programme du devoir surveillé concernant la programmation en C sur microcontrôleur AVR : Réaliser le programme "capteurs et actionneurs" du cours/TP concernant la programmation en C sur microcontrôleur AVR :
- contrôlez un servo-moteur en utilisant le minuteur 0 ;
- l’utilisateur utilise deux boutons pour changer l’angle ;
- affichez l’angle de rotation sur les 7-segments :
- 3 afficheurs doivent être utilisés ;
- utilisez la persistence rétinienne ;
- utilisez les interruptions générées par un second minuteur.
Matériel nécessaire
- Arduino Uno avec câble USB ;
- bouclier multi-fonctions ;
- servo-moteur.
Historique
- 02/03/2026:Branchement du matériel (Arduino,Shield et servo-moteur) et code pour faire bouger le moteur avec les deux boutons.
Travail réalisé
Jour 1 : Moteur et Boutons
Pour cette première étape, j’ai choisi d’avancer progressivement. L’objectif était simplement de lire les boutons S1 et S2 afin de commander la rotation du servo-moteur dans les deux sens.
Configuration des boutons
En consultant la datasheet ATmega328P,la section 13.2.1 (page 59),
- Lorsqu’une broche est configurée en entrée DDR = 0 et que l’on écrit un 1 dans le registre PORT correspondant, la résistance pull-up interne est activée. Cela maintient la broche à 5V au repos.
on a donc :
- Bouton non appuyé : niveau 1
- Bouton appuyé : niveau 0
C’est pour cette raison que, dans la boucle principale, je teste un état logique bas 0 pour détecter un appui.
Désactivation du buzzer du shield
Au démarrage, le buzzer du shield émettait un signal sonore en continu. Après vérification, celui-ci est piloté par un transistor PNP Q1. Pour le désactiver, il faut imposer un niveau logique haut (5V) sur la broche de commande. D’après la table 13-1 (page 60), cela se fait en configurant la broche en sortie DDR = 1 et en forçant le bit correspondant du registre PORT à 1. J’ai donc configuré la broche PD3 en sortie et fixé son état à 1 dès l’initialisation du programme.
Génération du signal PWM pour le servo
Le servo-moteur nécessite un signal PWM d’environ 60 Hz.
J’ai utilisé le Timer 0 en mode Fast PWM (Mode 3), en activant les bits WGM01 et WGM00, conformément à la table 14-8 (page 86).
- Dans ce mode, le compteur évolue de 0 à 255.
- Pour que le signal soit transmis sur la broche PD6 (OC0A), j’ai activé le bit COM0A1 (table 14-3, page 84). "If one or both of the COM0A1:0 bits are set, the OC0A output overrides the normal port functionality of the I/O pin it is connected to."
Étant donné que le microcontrôleur fonctionne à 16 MHz, j’ai appliqué un prescaler de 1024 via les bits CS02 et CS00 (page 87). Le calcul de la fréquence obtenue est le suivant :
La fréquence obtenue est donc d’environ 61 Hz, ce qui est compatible avec les exigences d’un servo-moteur standard.
Justification des valeurs matérielles pour le servo Hitec HS-422
Le moteur utilisé pour ce projet est un servo Hitec HS-422. En étudiant ses spécifications techniques officielles, le constructeur définit la plage de fonctionnement suivante :
- Le point central (neutre) est fixé à 1500 µs (1,5 ms).
- La plage d'impulsion garantie (Pulse Width) s'étend de 900 µs (0,9 ms) à 2100 µs (2,1 ms).
Calcul des valeurs du registre OCR0A : Notre horloge Arduino fonctionne à 16 MHz. Avec un prescaler de 1024, la durée d'une seule incrémentation (un "tic") du Timer 0 est de :
Pour trouver la valeur technique à envoyer au registre, on divise le temps d'impulsion du constructeur par la durée de notre tic :
- Point central (1,5 ms) :
. En arrondissant, on obtient notre position de démarrage 23.
- Butée minimale constructeur (0,9 ms) :
. La limite officielle basse est de 14.
- Butée maximale constructeur (2,1 ms) :
. La limite officielle haute est de 33.
Dans le code final, les limites ont été étendues de 8 à 38, correspondant environ à 0,5 ms et 2,4 ms pour exploiter le maximum la mécanique du servo.
Code du Jour 1
#ifndef F_CPU
#define F_CPU 16000000UL // On définit la vitesse de l'horloge
#endif
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
// On définit les pins comme des sorties (DDR = 1)
DDRD |= (1<<PD6) | (1<<PD3);
// On force le buzzer au silence
PORTD |= (1<<PD3);
// On active les résistances internes pour les boutons
PORTC |= (1<<PC1) | (1<<PC2);
// On crée un signal PWM rapide pour piloter le servo sur la pin D6
TCCR0A = (1<<COM0A1) | (1<<WGM01) | (1<<WGM00);
TCCR0B = (1<<CS02) | (1<<CS00); // On ralentit le chrono pour avoir du 61Hz
uint8_t pos = 23; // Valeur de démarrage (moteur à l'arrêt)
while (1) {
// Lecture des boutons
if (!(PINC & (1<<PC1)) && pos > 8) pos--; // Bouton S1 diminue
if (!(PINC & (1<<PC2)) && pos < 38) pos++; // Bouton S2 augmente
OCR0A = pos; // On envoie l'ordre de vitesse au moteur
_delay_ms(100); // Délai pour que le réglage du servo ne soit pas trop rapide
}
}
Jour 2 : Affichage et Timer 2
Aujourd'hui, j'ai travaillé sur l'afficheur 7-segments du shield. C'est plus dur que le moteur parce qu'il faut gérer plusieurs chiffres en même temps avec peu de fils.
1. Comment on parle à l'afficheur
Le shield utilise deux puces (74HC595) pour contrôler les segments. On utilise seulement 3 broches :
- DATA (PB0) : pour envoyer les infos bit par bit.
- CLOCK (PD7) : pour donner le rythme.
- LATCH (PD4) : pour dire à l'écran d'afficher ce qu'on a envoyé.
Comme il faut envoyer du courant vers l'afficheur, j'ai mis ces broches en Sortie dans le registre DDR (Table 13-1, page 60).
2. L'affichage (Multiplexage)
On ne peut pas allumer les 3 chiffres en même temps normalement. On utilise la persistance rétinienne : on allume chaque chiffre l'un après l'autre très vite. L'œil ne voit pas le clignotement et on a l'impression que tout est allumé.
3. Pourquoi le Timer 2 et le mode CTC ?
Pour que l'affichage soit propre, j'utilise le Timer 2 pour faire une interruption toutes les 1 ms.
Pourquoi le Timer 2 ?
- J'ai laissé le Timer 0 car il gère déjà le moteur.
- Je n'ai pas pris le Timer 1 car c'est un timer 16 bits très puissant. L'affichage est une tâche simple.
Pourquoi le mode CTC ?
J'ai choisi le mode CTC (Clear Timer on Compare Match) au lieu du mode normal.
En mode normal, le timer compte jusqu'à 255 et on ne peut pas régler la durée précisément.
En mode CTC, le timer se remet à zéro pile quand il atteint la cible qu'on lui donne dans le registre OCR2A.
Pour avoir 1 ms, j'ai mis 249 dans OCR2A. Comme le compteur commence à 0, ça fait exactement 250 étapes. Avec le prescaler de 64, ça nous donne un rafraîchissement parfait.
// Timer 2 pour l'affichage (toutes les 1ms)
TCCR2A = (1 << WGM21); // Mode CTC
TCCR2B = (1 << CS22); // Prescaler 64
OCR2A = 249; // 1ms
TIMSK2 |= (1 << OCIE2A); // Active l'interruption
Document utilisés
- https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
- https://forum.arduino.cc/t/multifunction-shield/1007847/3
- https://ww1.microchip.com/downloads/en/DeviceDoc/AVR-InstructionSet-Manual-DS40002198.pdf
- https://cdn.sparkfun.com/assets/1/1/f/a/3/HCS_HS-422_Specsheet_v2.2__102623.pdf