Skyduino:~#
Articles
arduino, programmation, test, tutoriel

[Test + Arduino] Afficheur 7 segments série (sparkfun)

Bonjour tout le monde !

Aujourd’hui je vous ai préparé un article au sujet d’un afficheur très pratique de chez sparkfun, commercialisé sous le nom de « Serial 7-Segment Display » (oui je triche c’est en anglais :)).

Le fils vert c’est moi qui l’ai ajouté.
J’ai malencontreusement bousillé la pastille en soudant le truc comme une brute (oui je sais honte à moi) …

Cet afficheur est un afficheur 7 segments tout ce qui a de plus classique, mais qui a plusieurs petites particularités :
– déjà il y a non pas un, mais 4 digits, avec séparateur heure / minute, points décimal, apostrophe (pour faire un °C ou °F par exemple),
– l’afficheur contient un ATmega328p, il est donc possible de mettre à jour le firmware avec un programme issu de l’ide arduino,
– de base l’afficheur se contrôle soit par le port série, soit par le bus SPI suivant un protocole bien précis,
– l’afficheur est d’une taille très « spéciale » (c’est plus petit que ce qu’on pourrait penser), 4cm x 2cm.

Quand j’ai acheté cet afficheur je voulais juste afficher des valeurs entières (sans décimal ou autre donc), puis une fois la documentation en main je me suis rendu compte du potentiel de ce petit afficheur !

En gros il est possible :
– d’afficher un nombre entier,
– d’afficher un nombre réel avec 1, 2, ou 3 nombres après la virgule,
– d’afficher une heure sous le format 00:00, ou tout autre valeur sous un format xx:yy,
– d’afficher des variables avec un format w.x.y.z.,
– d’afficher une température en °c ou °f (apostrophe + dernier digit servant à afficher la lettre C ou F (ou une autre lettre réalisable avec un afficheur 7 segments)).

Voici quelques exemples :

Nombres entiers :

Nombres réels :

(Je sais pas d’où vient cet arrondi de 133.7 vers 133.6, bizarre … (voir code plus bas))

Format horaire :

Variable avec point décimal :

Température :

Des digits « maison » :

Avant de me lancer dans le code j’ai regardé un peu comment fonctionnait cet afficheur.
Il se contrôle donc via un port série ou via un bus SPI, mais pour ma part je vais détailler son utilisation avec un port série uniquement.
Ce sera plus simple à comprendre pour tout le monde (les commandes en SPI soit identique).

Mais avant cela je voudrais faire une petite parenthèse sur le schéma de l’afficheur.
J’ai lu dans les commentaires de la page sparkfun de l’afficheur qu’il y avait divers problèmes, liés au software mais aussi au hardware.

J’ai donc regardé le schéma de plus prés, schéma que voici (extrait du pdf en provenance de sparkfun) :

Comme on peut le voir :
1 – il n’y a pas de résistances de limitation de courant sur les led,
2 – il n’y a pas de régulateur 5v (ou 3v3) intégré,
3 – il n’y as pas de quartz (l’ATmega utilise son oscillateur RC interne).

Pour le 1er point je suis un peu estomaqué pour un produit venant de sparkfun.
Je suis assez surpris qu’ils laissent toute la gestion des led au firmware dans l’ATmega, sans protection hardware (quelques résistances cms ça ne coute pas chère) !
Quelque chose me dit que l’afficheur ne résisterai pas bien longtemps si on mettait la luminosité au maximum, ou si l’on remplaçait le firmware d’origine par un firmware maison sans gestion de la luminosité, prudence donc !

Pour le 2eme point je comprends ce choix, mettre un régulateur demanderait de faire deux versions, une version 5v et une version 3v3.
Avec les différentes couleur de 7 segments disponible se serait ingérable.
Du coup il faudra faire très attention à l’alimentation de l’afficheur ! 5.5v MAXIMUM, sinon tout va cramer.

Pour le 3eme point je trouve cela un peu bête de ne pas avoir de « vrai » quartz.
Utiliser le pont RC interne comme signal d’horloge et faire du SPI / série dessus c’est très moyen comme solution (pour faire du Serial il faut une horloge avec moins de 2% de marge, le pont RC interne est à 10%. Autant dire que je ne tenterai pas d’aller au dessus de 9600 bauds).

Bref passons, l’afficheur se contrôle via une série de 8 commandes spéciales (en plus de CERTAIN codes ascii), commandes que voici (extraites du manuel) :

// Redémarre l'afficheur
#define AFF_RESET 0x76
 
// Modification de la luminosité (sauvegardé en EEPROM)
#define AFF_CTRL_LUM 0x7A // 0x7A 0x??
// 0x?? -> valeur entre 0 et 255, 0 = afficheur éteint, 255 = pleine puissance

// Modification de la vitesse du port série (sauvegardé en EEPROM)
#define AFF_CTRL_BAUDRATE 0x7F // 0x7F 0x??
// 0x00 -> 2400 bauds
// 0x01 -> 4800 bauds
// 0x02 -> 9600 bauds
// 0x03 -> 14400 bauds
// 0x04 -> 19200 bauds
// 0x05 -> 38400 bauds
// 0x06 -> 57600 bauds

// Permet de contrôler un point décimal
#define AFF_CRTL_DP 0x77 // 0x77 0x?? 
// 0x01 -> point décimal de gauche 1/4
// 0x02 -> point décimal de 2/4
// 0x04 -> point décimal de 3/4
// 0x08 -> point décimal de droite 4/4
// 0x16 -> double point horaire
// 0x32 -> apostrophe

// Contrôle des digits
#define AFF_CTRL_DIGITS_1 0x7B // 0x7B 0x?? 
#define AFF_CTRL_DIGITS_2 0x7C // 0x7C 0x?? 
#define AFF_CTRL_DIGITS_3 0x7D // 0x7D 0x?? 
#define AFF_CTRL_DIGITS_4 0x7E // 0x7E 0x?? 
// 0x?? -> valeur binaire correspondant aux segments allumés / éteints
// (MSB) ? a b c d e f g (LSB) (segments)

Petite image bonus tirée du manuel pour mieux comprendre l’agencement des points décimals et des segments :

Comme je le disais plus haut, en plus de ces commandes spéciales il est possible d’afficher une valeur en envoyant tout simplement le code ascii des 4 caractères qui la compose.

Trêve de bavardage ! Passons au cœur de la cuisine du sujet, le câblage, et le code !

Le câblage :

Tout d’abord il nous faudra pour ce test :
- 1 carte arduino,
- 1 afficheur 7seg série de sparkfun,
- quelques fils de câblage.

Le câblage en lui même :
Arduino -> Afficheur
RST -> RST
GND -> GND
5v -> VCC
TX -> RX
GND -> SCK

Le code de test :

Le code que j’ai réalisé pour ce test reprend les points importants du manuel et permet d’avoir un aperçu des divers fonctionnalités du firmware d’origine.
Comme toujours j’ai agrémenté le code de commentaires pour en faciliter sa compréhension 😉

/*
 * Exemple d'utilisation de l'afficheur série/spi 7 segments, 4 digits de sparkfun
 */

// Redémarre l'afficheur
#define AFF_RESET 0x76

// Modification de la luminosité (sauvegardé en EEPROM)
#define AFF_CTRL_LUM 0x7A // 0x7A 0x??
// 0x?? -> valeur entre 0 et 255, 0 = afficheur éteint, 255 = pleine puissance

// Modification de la vitesse du port série (sauvegardé en EEPROM)
#define AFF_CTRL_BAUDRATE 0x7F // 0x7F 0x??
// 0x00 -> 2400 bauds
// 0x01 -> 4800 bauds
// 0x02 -> 9600 bauds
// 0x03 -> 14400 bauds
// 0x04 -> 19200 bauds
// 0x05 -> 38400 bauds
// 0x06 -> 57600 bauds

// Permet de controler un point décimal
#define AFF_CRTL_DP 0x77 // 0x77 0x??
#define DP_1 0x01 // 0x01 -> point décimal de gauche 1/4
#define DP_2 0x02 // 0x02 -> point décimal de 2/4
#define DP_3 0x04 // 0x04 -> point décimal de 3/4
#define DP_4 0x08 // 0x08 -> point décimal de droite 4/4
#define DP_HORAIRE 0x10 // 0x10 -> double point horaire
#define DP_APOSTROPHE 0x20 // 0x20 -> apostrophe

// Contrôle des digits
#define AFF_CTRL_DIGITS_1 0x7B // 0x7B 0x?? 
#define AFF_CTRL_DIGITS_2 0x7C // 0x7C 0x?? 
#define AFF_CTRL_DIGITS_3 0x7D // 0x7D 0x?? 
#define AFF_CTRL_DIGITS_4 0x7E // 0x7E 0x?? 
// 0x?? -> valeur binaire correspondant aux segments allumé / éteint
// (MSB) ? a b c d e f g (LSB) (segments)

// Pour afficher des nombres / caractères il suffit d'envoyer les codes ascii des 4 caractères / nombres

// setup()
void setup() {
  // Initialisation du port série
  Serial.begin(9600);

  // Attend que l'afficheur soit OK
  delay(1000);

  // Reset de l'afficheur
  Serial.write(AFF_RESET);
}

// loop()
void loop() {

  // Démo affichage entier négatif
  affiche_entier(-42);
  delay(5000);

  // Démo affichage entier positif
  affiche_entier(1337);
  delay(5000);

  // Démo affichage réel négatif avec une décimale après la virgule
  affiche_reel(-42.7);
  delay(5000);

  // Démo affichage réel positif avec une décimale après la virgule
  affiche_reel(133.7);
  delay(5000);

  // Démo affichage heure
  affiche_heure(13, 37);
  delay(5000);

  // Démo affichage de 4 champs w.x.y.z
  affiche_champs('L', 'E', 'E', 'T');
  delay(5000);

  // Démo affichage température négative
  affiche_temperature(-42, 'C');
  delay(5000);

  // Démo affichage température positive
  affiche_temperature(42, 'C');
  delay(5000);

  // Démo K2000 avec les points décimaux
  byte x = 1;
  for(byte i = 0; i < 20; i++) {
    set_dp(x);
    x = x << 1;
    if(x == 0x10) x = 1;
    delay(100);
  }
  delay(5000);

  // Démo gestion manuelle des digits
  set_digit(1, 64); // -> '-'
  set_digit(2, 64);
  set_digit(3, 64);
  set_digit(4, 64);
  delay(5000);
  
  set_dp(0);
}

// ------------------------------------------- Fonction de haut niveau

// Affiche un nombre entier positif ou négatif
void affiche_entier(int nombre) {

  // Limite le nombre afin d'être affichable
  if(nombre > 9999) nombre = 9999;
  if(nombre < -999) nombre = -999;

  // Converti le nombre en chaine de caractères
  char tmp[5] = { 0 };
  sprintf(tmp, "%4d", nombre);

  // Affiche les 4 digits
  set_digits(tmp[0], tmp[1], tmp[2], tmp[3]);
}

// Affiche un nombre réel positif ou négatif avec 1 chiffre après la virgule
void affiche_reel(float nombre) {

  // Limite le nombre afin d'être affichable
  if(nombre > 999) nombre = 999;
  if(nombre < -99) nombre = -99;

  // Converti le nombre en chaine de caractères
  char tmpA[4] = { 0 }, tmpB[2] = { 0 };
  int num = (int)nombre;
  int dec = (int)((nombre - num) * 10);
  if(dec < 0) dec = -dec;

  sprintf(tmpA, "%3d", num);
  sprintf(tmpB, "%1d", dec);

  // Allume le point décimal de droite
  set_dp(DP_3);

  // Affiche les 4 digits
  set_digits(tmpA[0], tmpA[1], tmpA[2], tmpB[0]);
}

// Affiche une heure (ou autre) suivant le format xx:yy
void affiche_heure(byte heures, byte minutes) {

  // Limite le nombre afin d'être affichable
  // Dans le cas d'une utilisation avec autre chose qu'une heure
  if(heures > 99) heures = 99;
  if(minutes > 99) minutes = 99;

  // Converti l'heure en chaine de caractères
  char tmpA[3] = { 0 }, tmpB[3] = { 0 };
  sprintf(tmpA, "%02d", heures);
  sprintf(tmpB, "%02d", minutes);
  
  // Allume les double points horaire
  set_dp(DP_HORAIRE);

  // Affiche les 4 digits
  set_digits(tmpA[0], tmpA[1], tmpB[0], tmpB[1]);
}

// Affiche 4 valeurs séparées par un point décimal
void affiche_champs(char d1, char d2, char d3, char d4) {

  // Allume les 4 points décimals
  set_dp(DP_1 | DP_2 | DP_3 | DP_4);

  // Affiche les 4 digits
  set_digits(d1, d2, d3, d4);
}

// Affiche une température positive ou négative avec °C ou °F
void affiche_temperature(int temp, char unite) {

  // Limite le nombre afin d'être affichable
  if(temp > 999) temp = 999;
  if(temp < -99) temp = -99;

  // Converti le nombre en chaine de caractères
  char tmp[4] = { 0 };
  sprintf(tmp, "%3d", temp);
  
  // Allume l'apostrophe
  set_dp(DP_APOSTROPHE);

  // Affiche les 4 digits
  set_digits(tmp[0], tmp[1], tmp[2], unite);
}


// ------------------------------------------- Fonction de bas niveau

// Permet d'actualiser les 4 digits de l'afficheur
void set_digits(char d1, char d2, char d3, char d4) {
  Serial.write(d1);
  Serial.write(d2);
  Serial.write(d3);
  Serial.write(d4);
}

// Permet de changer la luminosité
void set_luminosity(byte lum) {
  Serial.write(AFF_CTRL_LUM);
  Serial.write(lum);
}

// Permet de changer le vitesse du port série
void set_baudrate(int baud) {
  Serial.write(AFF_CTRL_LUM);
  switch(baud) {
  case 2400:
    Serial.write((uint8_t)0x00);
    break;
  case 4800:
    Serial.write((uint8_t)0x01);
    break;
  case 9600:
    Serial.write((uint8_t)0x02);
    break;
  case 14400:
    Serial.write((uint8_t)0x03);
    break;
  case 19200:
    Serial.write((uint8_t)0x04);
    break;
  case 38400:
    Serial.write((uint8_t)0x05);
    break;
  case 57600:
    Serial.write((uint8_t)0x06);
    break;
  }
} 

// Permet de modifier un digit en particulier
void set_digit(byte digit, byte value) {
  switch(digit) {
  case 1:
    Serial.write(AFF_CTRL_DIGITS_1);
    break;
  case 2:
    Serial.write(AFF_CTRL_DIGITS_2);
    break;
  case 3:
    Serial.write(AFF_CTRL_DIGITS_3);
    break;
  case 4:
    Serial.write(AFF_CTRL_DIGITS_4);
    break;
  }
  Serial.write(value);
}

// Permet de modifier les états des différents points décimaux
void set_dp(byte value) {
  Serial.write(AFF_CRTL_DP);
  Serial.write(value);
}

Pour le résultat il suffit de regarder les images d’exemple un peu plus haut, elles sont directement tirées du code 😉

Bon bidouillage à tous ! 🙂

Publicités

Discussion

6 réflexions sur “[Test + Arduino] Afficheur 7 segments série (sparkfun)

  1. Juste modifié un peu affiche_heure par set_digits(heures/10,heures%10,minutes/10,minutes%10) pour avoir un affichage cohérent pour les heures du style 01:05 et pas 1: 5…

    Merci pour votre tutorial. Y a plus qu’a maintenant.

    Publié par Etienne | 13 août 2012, 15 h 17 min
    • Pour paginer avec des zéro au lieu d’avec des espaces :
      sprintf(tmpA, "%2d", heures);
      sprintf(tmpB, "%2d", minutes);

      ->

      sprintf(tmpA, "%02d", heures);
      sprintf(tmpB, "%02d", minutes);

      Question de gout, moi je préfère avoir des espaces 😉

      Publié par skywodd | 13 août 2012, 15 h 50 min
  2. super tuto! merci bcp

    Publié par Pierre Rasamoela | 25 janvier 2014, 7 h 46 min
  3. j’ai un problème avec ce type d’afficheur !!! s’il vous plait si vous pouvez m’aider je vous remercie d’avance:

    lors de mes premiers essais l’afficheur marche très bien j’ai même essayé l’exemple proposé dans ce tuto, mais après avoir essayé de modifier quelque fonction pour l’adapter à mon cas d’utilisation, l’afficheur ne répond plus ! il affiche que ‘0000’ et je n’arrive pas à le modifier j’ai l’impression qu’il y a un problème de réinitialiser et je ne sais pas comment le faire :(, merci de me répondre

    Publié par MAKHLOUF | 18 octobre 2014, 21 h 00 min
    • Je suis sensé trouvé la cause du problème avec ma boule de cristal ?
      Tu as modifié quelles fonctions et comment ?

      Le plus simple pour avoir quelque chose qui marche c’est de ne pas modifier les fonctions d’origines et de faire des fonctions par dessus pour ton application.

      Publié par Skywodd | 20 octobre 2014, 14 h 57 min

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

Skyduino devient Carnet du Maker

Le site Carnet du Maker remplace désormais le blog Skyduino pour tout ce qui touche à l'Arduino, l'informatique et au DIY.