SE3 2025/2026 EC2

De wiki-se.plil.fr
Aller à la navigation Aller à la recherche

Objectifs

Réaliser le programme du devoir surveillé concernant la programmation en C sur microcontrôleur AVR :

  • vous disposez de la fonction init_minuteur du cours ;
  • vous devez déjà écrire une version améliorée de la fonction shift_set donnée en cours/TP :
    • la version améliorée doit s'appeller affiche_chiffre,
    • cette fonction se charge de l'initialisation des registres à décalage du bouclier multifonction au premier appel,
    • à chaque appel, affiche_chiffre n'affiche qu'un seul chiffre hexadécimal sur l'afficheur 7 segments,
    • le premier paramètre de la fonction donne la position où afficher le chiffre (les nombres valides vont de 0 à 3),
    • le second paramètre donne le code ASCII du chiffre à afficher (les valeurs valides vont des caractères 0 à 9, et des caractères A à F) ;
  • vous écrirez ensuite un programme affichant les nombres de 0 à 9999 (en base 10), un par seconde, puis cyclant en revenant à 0 :
    • il vous est imposé d'utiliser une variable globale char nombre[4]; qui contiendra les valeurs ASCII des nombres qui seront affichés sur le 7 segments,
    • écrivez d'abord la fonction principale main, initialisant ce qui est nécessaire, puis affichant à tour de rôle (et à l'infini) chaque chiffre sur le 7 segments,
    • donnez ensuite le code de l'ISR, incrémentant les valeurs contenues dans nombre (attention ce sont des valeurs ASCII, pour rappel les valeurs sont contiguës de 0 à 9, et de A à F).

Matériel nécessaire

  • Arduino Uno avec câble USB ;
  • bouclier multi-fonctions.
PhotoProjet1.jpg
EC2.jpg
EC2.jpg

Documents Rendus

Objectifs

Le but de ce devoir surveillé est de réaliser un programme en langage C sur microcontrôleur AVR permettant de piloter un afficheur 7 segments à l’aide d’un registre à décalage.

Les objectifs sont les suivants :

  • Utiliser la fonction init_minuteur fournie dans le cours pour configurer un timer.
  • Écrire une version améliorée de la fonction shift_set appelée affiche_chiffre :
    • la fonction initialise les registres à décalage lors du premier appel
    • elle affiche un seul chiffre à la fois sur l’afficheur 7 segments
    • le premier paramètre indique la position (de 0 à 3)
    • le second paramètre correspond au code ASCII du caractère à afficher (de '0' à '9' et de 'A' à 'F')
  • Mettre en place un programme affichant les nombres de 0 à 9999 :
    • incrémentation chaque seconde
    • retour à 0000 après 9999
  • Utiliser une variable globale char nombre[4] contenant les valeurs ASCII des chiffres
  • Écrire une routine d’interruption (ISR) pour gérer l’incrémentation
  • Mettre en œuvre le multiplexage pour afficher les 4 chiffres


Pour cette première étape , je me suis concentré sur la communication avec le 74HC595 du Multi-function Shield. J'ai repris la base de la fonction shift_set vue en TP pour créer une fonction plus robuste nommée affiche_chiffre.

1- Principe de Fonctionnement

Le système utilise un registre à décalage pour envoyer les données à l'afficheur. Trois signaux sont utilisés :

  • SER (serial)
  • CLK (clock)
  • LTC (Latch)

Les données ne sont pas envoyées en parallèle, mais bit pas bit (communication série).

2- Description du programme

  • Le programme configue les broches utilisées comme sorties :
- PB0 pour les données (SER)
- PD7 pour l'horloge (CLK)
- PD4 pour la validation (LTC)
  • Un tableau nommé digits contien les codes binaires nécessaires pour afficher les chiffre et les lettres sur l'afficheur 7 segments.
  • La fontion affiche_chiffre permet d'afficher un caractère à une position
- si le caractère est entre '0' et '9' on utilise directement l'index correspond.
- si le caractère est entre 'A' et 'F' on utilise la formule (ascii - 'A' + 10 )
- Cela permet de convertir la lettre en index dans le tableau .
  • LA position de l'afficheur est sélectionnée à l'aide d'un masque binaire .
  • Les données (motif +position) sont envoyées au regitre à décalage bit par bit et du bit de poinds fort au bit de poinds faible .
  • une fois tous les bits envoyés , le signale LTC est activé pour afficher les données sur l'afficheur .
  • Dans la fontion main une boucle infinie affiche en continu la lettre 'C' à la position 2 avec un petit délai de 5ms .

3- Code source

#include <avr/io.h>
#include <util/delay.h>

#define SFTSER_PIN PB0
#define SFTCLK_PIN PD7
#define SFTLTC_PIN PD4

static const unsigned char digits[]={
  0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void affiche_chiffre(int position, char ascii){
  static int initialisation = 0;
  if (!initialisation){
    DDRB |= (1<<SFTSER_PIN);
    DDRD |= (1<<SFTCLK_PIN) | (1<<SFTLTC_PIN) ;
    initialisation = 1;
  }
  // calcul de motif 
  unsigned char motif = 0xFF;
  if(ascii >= '0' && ascii <= '9'){
    motif = digits[ascii - '0'];
  }else if (ascii >= 'A' && ascii <= 'F'){
    motif = digits[ascii - 'A' + 10];
  }

  unsigned char pos_mask = (1<<position);
  unsigned char tab[2]={motif, pos_mask};

  PORTD &= ~(1<< SFTLTC_PIN); //Latch Low 

  for(int i= 0; i<2 ; i++){
    unsigned char b = tab[i];
    for (int j=7; j>=0;j--){
      PORTD &= ~(1<<SFTCLK_PIN); // clock Low

      if (b & (1<<j)) {
        PORTB |= (1<<SFTSER_PIN);
      }else{
        PORTB &= ~(1<<SFTSER_PIN);
      }
      PORTD |=(1<<SFTCLK_PIN); // Clock High
    }
  }
  PORTD |=(1<<SFTLTC_PIN); // Latch High

}
int main(void){
  while(1){ 
// test / afficher sur la deuxième position
    affiche_chiffre(2, 'C');
    _delay_ms(5);
  }
  return 0; 
}


4- Gestion du temps

Pour optimiser le comptage, un timer est utilisé.

  • La fonction init_minuteur est fournie dans le cours.
  • Le timer est configuré en mode CTC
  • un diviseur est utilisé pour ajuster la vitesse
  • Une interruption est générée à intervalle régulier.

Dans ce programme:

  • Diviseur = 1024
  • Période = 1000ms

Une Interruption toutes les 1 seconde

5- Interruption (ISR)

L’interruption TIMER1_COMPA_vect permet d’incrémenter le nombre affiché.

  • Le deriner chiffre est incrémenté
  • si le chiffre dépasse '9'
  • il revient à '0'
  • le chiffre suivant est incrémenté (retenue)
  • Si 9999 est atteint :
 * retour à 0000

6- Multiplexage

L'affichage des 4 chiffres est réalisé par multiplexage :

  • Les chiffres sont affichés un par un très vite
  • Une boucle affiche successivement chaque position :
    • affiche_chiffre(i,nombre[i])
  • un délai de 2ms est utilisé pour éviter le clignotement rapide

7- Code source

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>


#define SFTSER_PIN PB0
#define SFTCLK_PIN PD7
#define SFTLTC_PIN PD4
#define CTC1   WGM12 

//Variable globale 
char nombre[4]={'0', '0','0','0'};

static const unsigned char digits[]={
  0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void affiche_chiffre(int position, char ascii){
  static int initialisation = 0;
  if (!initialisation){
    DDRB |= (1<<SFTSER_PIN);
    DDRD |= (1<<SFTCLK_PIN) | (1<<SFTLTC_PIN) ;
    initialisation = 1;
  }
  
  unsigned char motif = 0xFF;
  if(ascii >= '0' && ascii <= '9'){
    motif = digits[ascii - '0'];
  }else if (ascii >= 'A' && ascii <= 'F'){
    motif = digits[ascii - 'A' + 10];
  }

  unsigned char pos_mask = (1<<position);
  unsigned char tab[2]={motif, pos_mask};

  PORTD &= ~(1<< SFTLTC_PIN);

  for(int i= 0; i<2 ; i++){
    unsigned char b = tab[i];
    for (int j=7; j>=0;j--){
      PORTD &= ~(1<<SFTCLK_PIN);

      if (b & (1<<j)) {
        PORTB |= (1<<SFTSER_PIN);
      }else{
        PORTB &= ~(1<<SFTSER_PIN);
      }
      PORTD |=(1<<SFTCLK_PIN);
    }
  }
  PORTD |=(1<<SFTLTC_PIN);

}

void init_minuteur(int diviseur,long periode){
TCCR1A=0;               
TCCR1B=(1<<CTC1);       
switch(diviseur){
  case    8: TCCR1B |= (1<<CS11); break;
  case   64: TCCR1B |= (1<<CS11 | 1<<CS10); break;
  case  256: TCCR1B |= (1<<CS12); break;
  case 1024: TCCR1B |= (1<<CS12 | 1<<CS10); break;
 }
OCR1A=F_CPU/1000*periode/diviseur;  // Calcul du pas
TCNT1=0;                
TIMSK1=(1<<OCIE1A);    
}
 // ISR
ISR(TIMER1_COMPA_vect){  
  // on part du dernier chiffre 
  nombre[3]++;

  for (int i=3; i>=0; i--){
    if (nombre[i]>'9'){
      nombre[i]='0';
      if(i>0){
        nombre[i-1]++;
      }else{
        // si on dépasse 9999, on revient à 0000
        nombre[0]='0';
      }
    }
  }
}


int main(void){

  init_minuteur(1024,1000); //1s
  sei();

  while(1){

    //Multiplexage: affichage des 4 digits 
    for (int i=0; i<4; i++){
      affiche_chiffre(i,nombre[i]);
      _delay_ms(2);// temps court pour éviter le clignotement 

    }
  }
}

8- Résultats et tests

  • Le compteur s’incrémente correctement chaque seconde
  • Les chiffres s’affichent correctement sur les 4 positions
  • Le passage de 9999 à 0000 fonctionne correctement
  • L’affichage est stable grâce au multiplexage


9- Conclusion

Ce travail a permis de comprendre :

  • le fonctionnement du registre à décalage 74HC595
  • la communication série (bit à bit)
  • l’utilisation des timers et des interruptions
  • la technique du multiplexage

Le programme réalise un compteur fiable de 0000 à 9999 avec affichage dynamique.

Ressources et Documentation

  • Documentation du composant 74HC595
  • Cours et TP sur les registres à décalage
  • Documentation AVR (ports et registres)