SE3 2025/2026 EC3
Aller à la navigation
Aller à la recherche
Objectifs
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
Travail réalisé
1. Youssef_servo.c
#ifndef F_CPU
#define F_CPU 16000000UL // On définit la vitesse de l'horloge
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define LATCH PD4 // Signal de validation
#define CLOCK PD7 // Signal d'horloge
#define DATA PB0 // Fil de données
volatile uint16_t angle = 90;
const uint8_t segments[] = {~0x3F,~0x06,~0x5B,~0x4F,~0x66,~0x6D,~0x7D,~0x07,~0x7F,~0x6F};
//Le symbole '~' inverse les bits car l'afficheur s'allume avec du 0V
void envoyer(uint8_t val) {
for (uint8_t i = 0; i < 8; i++) {
// On vérifie chaque bit de l'octet du plus grand au plus petit
if (val & (1 << (7 - i))){
PORTB |= (1 << DATA); // On envoie un 1 (5V)
} else {
PORTB &= ~(1 << DATA); // On envoie un 0 (0V)
}
// On actionne l'horloge manuellement pour faire avancer le bit
PORTD |= (1 << CLOCK);
PORTD &= ~(1 << CLOCK);
}
}
ISR(TIMER2_COMPA_vect) {
// static permet de garder en mémoire quel digit (0, 1 ou 2) on doit allumer
static uint8_t digit = 0;
// On extrait le bon chiffre du nombre total Centaines, Dizaines et Unités
uint8_t val = (digit == 0) ? (angle/100) : (digit == 1) ? (angle/10)%10 : (angle%10);
PORTD &= ~(1 << LATCH); // On bloque l'affichage le temps de préparer les données
envoyer(segments[val]); // chiffre
envoyer(1 << digit); // digit
PORTD |= (1 << LATCH); // On déverrouille pour afficher le résultat final
// On prépare le tour suivant
digit = (digit + 1) % 3;
}
int main(void) {
// On définit les pins comme des sorties (DDR = 1)
DDRD |= (1<<LATCH) | (1<<CLOCK) | (1<<PD6) | (1<<PD3);
DDRB |= (1<<DATA);
// On force le buzzer au silence
PORTD |= (1<<PD3);
// On active les résistances internes
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
// On règle une alerte toutes les 1 milliseconde pour changer de chiffre
TCCR2A = (1<<WGM21); // Mode CTC
TIMSK2 |= (1<<OCIE2A); // On active l'alerte
OCR2A = 249; // Cible
TCCR2B = (1<<CS22);
sei(); // On autorise les alertes à fonctionner
uint8_t pos = 23;
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
// Calcul pour transformer la valeur technique en un chiffre lisible (0-180)
angle = (uint32_t)(pos - 8) * 180 / 30;
_delay_ms(100); // Délai pour le réglage du servo soit pas rapide
}
}