Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Commentez, partagez et proposez des Tutos en langage C !
Afficheur 7 segments (Digits)
Jérémy
Administrateur du site
Administrateur du site
Messages : 2163
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#1 Message par Jérémy » dim. 27 sept. 2015 22:16

Bonjour à tous,


Je vous propose un tutoriel sur le fonctionnement des afficheurs 7 segments "Digit" avec MikroC.



Les pré-requis :
  • Le Modulo : %.
  • La fonction : switch.
  • Fonction avec paramètres d'entrée et de sortie.
Plaque easyPIC7.jpg

Configuration :

- PIC18F46K22
- IDE : MikroC Pro for PIC Version 6.6.3
- Compilateur : Mikro prog suite fo PIC V 2.32
- Plaque Easy PIC V7



Un afficheur 7 segments appelé également "digit" est un composant permettant l'affichage de chiffres et de lettres en combinant et en allumant ces différents segments.
Chaque segment ( qui sont des leds) doit être connecté à une broche de notre PIC. Suivant l'afficheur 7 segments utilisé, anode ou cathode commune il faudra un "état haut" ou un "état bas" pour allumer celui-ci.

Image




Le Schéma :



Voici le schéma de la partie "DIGIT" de la carte EasyPic7. Chaque segments des digits est relié au PORTD de 0 à 7 . "0" correspondant au segment "a" et 7 à "dp" pour "décimal point".
Les transistors sont reliés au PORT A ( de RA0 à RA3) et active ou non les digits correspondants, le premier Digit(à droite) est branché sur RA0.

Nous allons voir comment se servir d'un seul digit pour commencer !!!








Image

Le but :
Nous allons créer un compteur, comptant de 0 à 9. Il devra afficher sa valeur sur un DIGIT( RA0). Aucune précision n'est souhaité et une pause servira de temporisation.
Une fonction permettra de convertir le chiffre de notre compteur, en une valeur définissant les segments à allumés.

par exemple pour affichés "1" : il faudra affiché les deux segments verticaux à droite .
ces deux segments correspondent aux segments "b" et "c". Ce qui fais 0b00000110 = 0x06



Programme pour un seul "digit" :

Code : Tout sélectionner

/*##################################################################################
##############################     Variable / Constante    #########################
##################################################################################*/

unsigned int   compteur, num ;  // Déclaration des variables

/*##################################################################################
###########################    CONVERTIR LE CHIFFRE    #############################
##################################################################################*/
unsigned short conversion(unsigned short num)   //  Fonction avec paramètres d'entrée et de sortie
 {                                    // suivant le chiffre du compteur on renvoie la valeur pour allumer tel ou tel segments sur le PORTD

                                      // Utilisation de la commande "switch"
      switch (num) {                  // "Switch" compare la valeur contenu dans "num" aux valeurs "case" ci dessous
                                      // Si une valeur est trouvée, "Switch" renvoie la valeur correspondante et sort
                                      // Une seule valeur est prise en compte

      case 0 : return 0x3F;           // Affiche un "0" avec l'allumage de six segments 3F = 00111111  du PORTD
      case 1 : return 0x06;           //                     |
      case 2 : return 0x5B;           //                     |
      case 3 : return 0x4F;           //                     |
      case 4 : return 0x66;           //                     |
      case 5 : return 0x6D;           //                     |
      case 6 : return 0x7D;           //                     |
      case 7 : return 0x07;           //                     |
      case 8 : return 0x7F;           //                     |
      case 9 : return 0x6F;           // Affiche un "9" par l'allumage des segments correspondants
    }
 }

/*##################################################################################
############################   PROGRAMME PRINCIPAL    ##############################
##################################################################################*/
void main() {

  ANSELA = 0;                    // Configure le PORTA en Digital
  ANSELD = 0;                    // Configure le PORTD en Digital

  TRISA = 0;                     // Configure le PORTA en SORTIE
  LATA  = 0;                     // affecte 0 aux broches du PORTA
  TRISD = 0;                     // Configure le PORTD en SORTIE
  LATD  = 0;                     // affecte 0 aux broches du PORTD

  LATA.B0 = 1;                  // Mise à l'état haut de RA0 pour activer le premier afficheur.

  compteur = 0;                 // Initialise notre compteur à 0.

 //##########################    BOUCLE INFINIE    ##################################
  do {
   

   if 
(compteur >= 10) compteur = 0 ;   // Si le compteur est supérieur ou égale a 10 alors on le remet à 0
   LATD  =  conversion(compteur) ;      // on affecte la valeur convertie pour affichage sur le PORT D
   compteur = compteur++;               // On incrémente notre compteur.
   delay_ms(1000);                      // On marque une pause de 1 seconde.

  } while(1);                           // On reboucle



Remarques :
Le problème avec les digits c'est qu'ils sont gourmands en connexions, 8 en général, 7 pour les segments et 1 pour le point. Donc si on veut afficher des nombres avec plus de un chiffre, ça devient assez problématique. Pour éviter de monopoliser autant de broches , on va utiliser le multiplexage .

le multiplexage consiste à allumer successivement les afficheurs les uns après les autres, très rapidement . On ne verra pas de clignotement grâce a la persistance rétinienne.

Le déroulement se fera ainsi :
  1. activation du premier digit -> Affichage d'un chiffre -> désactivation du premier digit
  2. activation du deuxième digit -> Affichage d'un chiffre -> désactivation du deuxième digit
  3. activation du troisième digit -> Affichage d'un chiffre -> désactivation du troisième digit
  4. activation du quatrième digit -> Affichage d'un chiffre -> désactivation du quatrième digit
  5. et on reboucle.


Programme pour 4 afficheurs 7 segments :

Voici le programme, non optimisé, pour bien vous faire comprendre le principe. Ici un afficheur sera actif toutes 15ms pendant 5 ms. On ne voit aucun clignotement !.
Bien évidemment suivant votre programme principal, d'autres solutions plus optimisées sont largement conseillées. Ici on ne fait que compter et afficher, c'est rarement le cas dans les projets !

Notez la fonction modulo, qui nous sert à extraire les chiffres correspondant aux différentes unités .


Code : Tout sélectionner

/*##################################################################################
##############################     Variable / Constante    #########################
##################################################################################*/

unsigned int   compteur, num,millier, centaine, dizaine, unite;  // Déclaration des variables

/*##################################################################################
###########################    CONVERTIR LE CHIFFRE    #############################
##################################################################################*/
unsigned short conversion(unsigned short num)   //  Fonction avec parametres d'entrée et de sortie
 {                                    // suivant le chiffre du compteur on renvoie la valeur pour allumer tel ou tel segments sur le PORTD

                                      // Utilisation de la commande "switch"
      switch (num) {                  // "Switch" compare la valeur contenu dans "num" au valeur "case" ci dessous
                                      // Si une valeur est trouvée, "Switch" renvoie la valeur toucorrespondante et sort
                                      // Une seule valeur est prise en compte

      case 0 : return 0x3F;           // Affiche un "0" avec l'allumage de six segments 3F = 00111111  du PORTD
      case 1 : return 0x06;           //                     |
      case 2 : return 0x5B;           //                     |
      case 3 : return 0x4F;           //                     |
      case 4 : return 0x66;           //                     |
      case 5 : return 0x6D;           //                     |
      case 6 : return 0x7D;           //                     |
      case 7 : return 0x07;           //                     |
      case 8 : return 0x7F;           //                     |
      case 9 : return 0x6F;           // Affiche un "9" par l'allumage des segments correspondants
    }
 }

/*##################################################################################
############################   PROGRAMME PRINCIPAL    ##############################
##################################################################################*/
void main() {

  ANSELA = 0;                    // Configure le PORTA en Digital
  ANSELD = 0;                    // Configure le PORTD en Digital

  TRISA = 0;                     // Configure le PORTA en SORTIE
  LATA  = 0;                     // affecte 0 aux broches du PORTA
  TRISD = 0;                     // Configure le PORTD en SORTIE
  LATD  = 0;                     // affecte 0 aux broches du PORTD

  compteur = 0;                 // Initialise notre compteur à 0.

 //##########################    BOUCLE INFINIE    ##################################
  do {
    millier = compteur/1000 %10 ;     // Calcul de la valeur des milliers . On divise le compteur par 1000 on prend le modulo
    LATD  = conversion(millier);      // On convertit la valeur calculée en segments pour affichage.
    LATA  = 8;                        // On active le 4iéme digit ( 0b00001000) en mettant le bit 3 à 1
    delay_ms (5);                     // On marque une pause pour afficher le chiffre

    centaine = compteur/100 %10;     // calcul de la valeur des centaines . On divise le compteur par 100 on prend le modulo
    LATD  = conversion(centaine);    // On convertit la valeur calculée en segments pour affichage.
    LATA  = 4;                       // On active le 3iéme digit ( 0b00000100) en mettant le bit 2 à 1
    delay_ms (5);                    // On marque une pause pour afficher le chiffre

    dizaine = compteur/10 %10;      // calcul de la valeur des dizaines . On divise le compteur par 10  on prend le modulo
    LATD  = conversion(dizaine);    // On convertit la valeur calculée en segments pour affichage.
    LATA  = 2;                      // On active le 2iéme digit ( 0b00000010) en mettant le bit 1 à 1
    delay_ms (5);                   // On marque une pause pour afficher le chiffre

    unite = compteur %10;           // calcul de la valeur des unités . On prend le modulo
    LATD  = conversion(unite);      // On convertit la valeur calculée en segments pour affichage.
    LATA  = 1;                      // On active le 1er digit ( 0b00000001) en mettant le bit 0 à 1
    delay_ms (5) ;                 // On marque une pause pour afficher le chiffre

    compteur = compteur++ ;        // On incrémente notre compteur

  } while(1);                           // On reboucle
}
 


idea ! Conseils :

- Conseil de Paulfjujo : Sur les PIC 18F, l'affection d'une valeur sur un PORT se fait avec le mot LATx plutôt que PORTx.


- Ici nous utilisons des delay_ms, pour temporiser l'affichage, sinon cela y aurai bien trop vite pour nos yeux et on verrait tous les segments s'allumés en même temps. N'oubliez pas que pendant un delay_ms, votre µC ne peut rien faire.
La bonne méthode serait de passer par un timer afin de libérer notre µC pendant ces pauses. voici un exemple de ce qui pourrait être fait

► Afficher le programme



Vidéo :

http://www.dailymotion.com/video/x37y6p2

Attention!! Comme d'habitude, pour les experts si vous voyez des erreurs ou avez des astuces , vous pouvez poster à la suite, je mettrais le Tuto à jour .
Pour les moins Experts qui veulent approfondir ou poser des questions , n’hésitez surtout pas et postez aussi à la suite!.
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Afficheur 7 segments (Digits)
Jérémy
Administrateur du site
Administrateur du site
Messages : 2163
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#2 Message par Jérémy » jeu. 28 juil. 2016 17:23

MAJ + programme "évolué" pour gérer 4 digits
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Afficheur 7 segments (Digits)
sylvain54
Avatar de l’utilisateur
Amateur
Amateur
Messages : 178
Âge : 46
Enregistré en : août 2015
Localisation : Dans l'est de la France

#3 Message par sylvain54 » jeu. 28 juil. 2016 22:20

Nickel tout ça :bravo:

Afficheur 7 segments (Digits)
tarek_07
Membre
Membre
Messages : 1
Enregistré en : septembre 2016

#4 Message par tarek_07 » ven. 16 sept. 2016 18:36

Mercie :bravo:

Afficheur 7 segments (Digits)
venom
Avatar de l’utilisateur
Passioné
Passioné
Messages : 425
Âge : 33
Enregistré en : avril 2016
Localisation : . <------ ici
Contact :

#5 Message par venom » ven. 16 sept. 2016 22:11

A pic !

Merci beaucoup Jérémy pour ce tuto très propre. 8-) :bravo: Merci !






@++
En fait tout est une question de BIT ? :-D

Afficheur 7 segments (Digits)
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 1089
Âge : 68
Enregistré en : juillet 2015
Localisation : 01800
Contact :

#6 Message par paulfjujo » sam. 17 sept. 2016 14:58

bonjour,



+1 Belle presentation ..

juste un petit detail..
dans ton init tu utilises bien LATD=0

par contre dans le programme, il faudrait, pour garder une bonne habitude avec les 18F ,
remplacer les affectations comme
PORTD = conversion(compteur) ;
par
LATD= conversion(compteur) ;

meme si cela fonctionne dans ce cas là.

Afficheur 7 segments (Digits)
Jérémy
Administrateur du site
Administrateur du site
Messages : 2163
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#7 Message par Jérémy » sam. 17 sept. 2016 15:33

Correction effectuée !

Merci Paul !
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Afficheur 7 segments (Digits)
Omar
Membre
Membre
Messages : 2
Enregistré en : novembre 2016

#8 Message par Omar » jeu. 8 déc. 2016 04:54

salut Jérémy

pour quoi tu n'utilise pas un tableau au lieu la fonction de conversion

exemple
unsigned short conversion(unsigned short num) // Fonction avec paramètres d'entrée et de sortie
{ // suivant le chiffre du compteur on renvoie la valeur pour allumer tel ou tel segments sur le PORTD

// Utilisation de la commande "switch"
switch (num) { // "Switch" compare la valeur contenu dans "num" aux valeurs "case" ci dessous
// Si une valeur est trouvée, "Switch" renvoie la valeur correspondante et sort
// Une seule valeur est prise en compte

case 0 : return 0x3F; // Affiche un "0" avec l'allumage de six segments 3F = 00111111 du PORTD
case 1 : return 0x06; // |
case 2 : return 0x5B; // |
case 3 : return 0x4F; // |
case 4 : return 0x66; // |
case 5 : return 0x6D; // |
case 6 : return 0x7D; // |
case 7 : return 0x07; // |
case 8 : return 0x7F; // |
case 9 : return 0x6F; // Affiche un "9" par l'allumage des segments correspondants
}
}

par
const unsigned char conversion[] = {0x3f,0x06,0x5b......}

et

LATD = conversion(compteur) ; // on affecte la valeur convertie pour affichage sur le PORT D

par

LATD = conversion[compteur] ; // on affecte la valeur convertie pour affichage sur le PORT D


Afficheur 7 segments (Digits)
Jérémy
Administrateur du site
Administrateur du site
Messages : 2163
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#9 Message par Jérémy » jeu. 8 déc. 2016 07:30

Bonjour Omar,

Merci de l’intérêt porté à ce Tuto c'est une très bonne suggestion ! c'est une autre façon de faire qui mérite d'être vue. Je vais voir pour mettre à jour le tuto !

D’après toi quelle serait les avantages d'utiliser un tableau plutôt qu'une fonction ? afin d'argumenter mon tuto ?

Bonne journée
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Afficheur 7 segments (Digits)
Claudius
Avatar de l’utilisateur
Amateur
Amateur
Messages : 119
Enregistré en : septembre 2015

#10 Message par Claudius » dim. 8 janv. 2017 20:48

Bonsoir et Bonne Année à tous,

L'utilisation d'un tableau est une excellente idée car l'accès à la valeur est pratiquement en temps constant alors qu'avec un switch / case, les données sont accédées en un temps fonction de sa place dans le case (du moins si le compilateur ne les réorganise pas). En effet un switch / case est transcrit par les compilateurs (sauf exception et à vérifier par désassemblage du code généré) par une suite de if/ else if / ... / else if / else

Maintenant, une autre astuce est d'écrire en assembleur ledit tableau comme suit pour un pic16 (je n'ai pas vérifié avec un pic18):

Code : Tout sélectionner

conversion
   addwf      PCL,F
   retlw      0x3F      ;  Retourne un "0" avec l'allumage de six segments 3F = 00111111 du PORTD
   retlw      0x06      ; |
   retlw      0x5B      ; |
   retlw      0x4F      ; |
   retlw      0x66      ; |
   retlw      0x6D      ; |
   retlw      0x7D      ; |
   retlw      0x07      ; |
   retlw      0x7F      ; |
   retlw      0x6F      ; Retourne un "9" avec l'allumage des segments correspondants

Avec cette dernière implémentation, le temps d'accès est constant quelle que soit la place de la valeur à retourner (attention à la taille de cette subroutine qui doit être définie un et un seul bank. et ne pas chevaucher 2 bank différents)...

Cf. pour tout savoir: Implementing a Table Read ;-)


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité