Bonjour,
Devant gérer une fête de nouvel an avec une soixantaine de personnes, je devais faire le décompte 10, 9, 8...1, 2024, mais de façon originale. Merci Arduino qui passait par là.
Le but était donc de cacher un peu le décompte pour que les gens ne s'aperçoivent que le décompte état commencé le plus tard possible. Ce qui a été réussi, beaucoup m'on dit qu'ils avait compris à 5 seulement. Dix, neuf, huit, sept, six ont été dit haut et fort sans qu'ils le remarquent. Pourtant c'était à minuit moins quelques. C'est un jeu qui a commencé exactement à 23h48mn50s.
La vidéo sur place n'a pas été faite, j'en ai fait une pour que vous puissiez comprendre après coup. Elle est légèrement accélérée:
http://arduino.dansetrad.fr/Decompte/Decompte.mp4
Il a fallu faire cela vite fait à la dernière semaine.
J'avais récupéré l'électronique d'un afficheur de lycée, genre celui qui indique la liste des profs absents. On suppose qu'il marchait, mais il y a eu un problème d'informatique et plus moyen de communiquer. Le fabricant avait disparu. Voici ce que j'ai récupéré:
La carte mère est à 68HC11, mais inutilisable pour moi (si quelqu'un la veut?) d'autant plus que je n'ai ni le schéma ni le programmateur d'EEprom.
Le 5V et le GND des afficheurs est facile grâce aux connecteurs d'alimentation. Les afficheurs se montent en série, et d'origine il y avait plusieurs lignes en parallèle. V est une évidence à cause des 3 alims 5V/20A.
Il y a des petits afficheurs de 4 digits et des grand de 8 digits qui sont presque des doubles des petits. Sur les petits il y a 7 transistors (7 lignes), sur les grands 7 aussi.
Les lecture des nom des circuits intégrés était faisable, j'en ai déduis un schéma très probable:
Pour piloter le tout avec ce que j'avais sous la main, j'ai utilisé une nano et un clavier 4x4, j'avais besoin d'au moins quelques boutons pour la remise à l'heure. Comme la dérive de la nano est d'une seconde toute les 4 heures et que c'est pour une soirée, j'utilise l'horloge millis() C'est rare quand j'utilise millis(), profitons en! Un son a été rajouté avec tone() pour donner le départ et la fin d'une recherche.
Comme il y a pleins de boutons, chaque chiffre de l'heure peut être incrémenté ou décrémenter, deux servent à régler la luminosité, et deux pour régler le niveau sonore (un qui fait un son, l'autre qui passe en mode normal.
Le schéma de branchement de la Nano est le suivant:
/* Câblage:
GND ────── 0V
PB4 = D8 ───── Strobe
PB5 Sck = D13 ──── Clk
PB3 Mosi = D11 ──── Din
PB1 ~1 = D9 ───── OE
PC2 = A2 ───── Mux 2
PC1 = A1 ───── Mux 1
PC0 = A0 ───── Mux 0
┌───────┐ ││
PB2 = D10 ────┬──┤ 4,7kΩ ├───┤├──────── vers sono
│ └───────┘ ││100nF
┌─┴─┐
│ │
│1kΩ│
│ │
└─┬─┘
│
GND
*/
// 4 5 6 7
// │ │ │ │
// ├─\ ├─\ ├─\ ├─\ .
// │ └──│─┴──│─┴──│─┴──▷├─┐
// ├─\ ├─\ ├─\ ├─\ ├─ 3
// │ └──│─┴──│─┴──│─┴──┤◁─┘
// ├─\ ├─\ ├─\ ├─\ .
// │ └──│─┴──│─┴──│─┴──▷├─┐
// └─\ └─\ └─\ └─\ ├─ 2
// └────┴────┴────┴──┤◁─┘
//
// Correspond à la matrice carrée triple:
// │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 2 │ X │ / │ -10s │ +10s │ -1s │ +1s │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 3 │ / │ X │ -10h │ +10h │ -1h │ +1h │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 4 │ -10mn │ faib │ X │ / │ / │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 5 │ +10mn │ fort │ / │ X │ / │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 6 │ -1mn │ /Son │ / │ / │ X │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 7 │ +1mn │ Son │ / │ / │ / │ X │
// ──┴───────┴──────┴──────┴──────┴─────┴─────┘
Il y a des diodes dans la matrice de boutons pour n'utiliser que 6 entrées, je ne savais pas si la gestion des boutons se ferait par scan ou par interruptions, et dans ce dernier cas il vaut mieux mettre tout le monde sur le même port.
Le programme était le suivant:
#include <avr/pgmspace.h> // pour la fonte de caractères qui est en mémoire programme
#include "font.h"
/* Câblage:
GND ────── 0V
PB4 = D8 ───── Strobe
PB5 Sck = D13 ──── Clk
PB3 Mosi = D11 ──── Din
PB1 ~1 = D9 ───── OE
PC2 = A2 ───── Mux 2
PC1 = A1 ───── Mux 1
PC0 = A0 ───── Mux 0
┌───────┐ ││
PB2 = D10 ────┬──┤ 4,7kΩ ├───┤├──────── vers sono
│ └───────┘ ││100nF
┌─┴─┐
│ │
│1kΩ│
│ │
└─┬─┘
│
GND
*/
#define NOMBRE_AFFICHEURS 2 // Chaque afficheur à 4 digits
#define OUTPUT_ENABLE PORTB |= 0b00000010 // PB1, D9
#define OUTPUT_DISABLE PORTB &= 0b11111101
#define STROBE_ENABLE PORTB |= 0b00000001 //PB0, D8
#define STROBE_DISABLE PORTB &= 0b11111110
#define CLK_VALIDE PORTB |= 0b00100000 //PB5, D13
#define CLK_REPOS PORTB &= 0b11011111
#define DIN_1 PORTB |= 0b00001000 //PB3, D11
#define DIN_0 PORTB &= 0b11110111
#define LIGNE PORTC // Ligne de l'afficheur (0 à 6)
// Variables
volatile uint32_t afficher[NOMBRE_AFFICHEURS][7]; // Ce qui va être affiché. Dialogue entre Main et la fonction d'interruption
boolean allume = true; // Si false l'afficheur ne s'allume pas
word lumiere = 16; // Luminosité de l'afficheur 0..2000 (0=éteint, 2000=maxi)
void affiche(String phrase)
/* Prend la phrase et met les bonx pixels dans la variable afficher.
La phrase est centrée
Dure environ 0,3ms par afficheur */
{
static uint32_t prepareAfficheur[7]; // Permet de préparerl'affichage
char num=phrase.length(); // Nombre de caratères
byte espace=(NOMBRE_AFFICHEURS*4-num)>>1; // Nombre d'espaces à ajouter avant d'écrire
byte decalage = espace;
for (byte unAfficheur=0; unAfficheur<NOMBRE_AFFICHEURS; unAfficheur++) // Un afficheur c'est 4 matrices 5x7, mais 24 pixels à transférer (3x8)
{
for (byte uneLigne=0; uneLigne<7; uneLigne++) prepareAfficheur[uneLigne] = 0xFFFFFFFF; // 7 lignes de 24 bits mis dans ldes uint32_t. Par défaut tout éteint
for (uint32_t caractere=0; caractere<4; caractere++) // Pour lire un caractère, trouver ses bits et les ranger dans les différentes lignes
{
if (espace>0) espace--; // Ne rien faire si c'est les espaces du départ, mais on a un espace à mettre en moins
else // C'est un caractère e la chaîne (qui peut d'ailleurs être un espace)
{
uint32_t base;
if (num-- <= 0) base = 0; // fin de phrase, on donne l'adresse de l'espace
else base = (phrase[caractere+4*unAfficheur-decalage]-' ') * 7; // Offset du premier octet de définition
for (uint32_t ligne=0; ligne<7; ligne++) // Pour les 7 lignes de la définition d'un caractère
{
uint32_t valeur = pgm_read_byte_near(font + base + ligne); // Lecture de la matrice de définition du caractère
valeur <<= (caractere * 5 + 4); // Que l'on positionne dans les 24 bits à faire tranférer
prepareAfficheur[ligne] &= ~valeur; // On met donc des 0 pour chaque pixel allumé
}
}
}
for (byte uneLigne=0; uneLigne<7; uneLigne++) afficher[unAfficheur][uneLigne] = prepareAfficheur[uneLigne]; // Transfert de ce qui a été préparé
}
}
void coucou(void) // Bruitage d'accueil (pour inviter à chercher des mots)
{
allume = false;
OUTPUT_DISABLE;
tone(10, 523); // Do
delay(200);
tone(10, 784); // Sol
delay(200);
tone(10, 659, 400); // Mi
allume = true;
}
void byebye(void) // Bruitage pour dire c'est fini
{
allume = false;
OUTPUT_DISABLE;
tone(10, 262); // Do
delay(200);
tone(10, 247); // Si
delay(200);
tone(10, 220); // La
delay(200);
tone(10, 196); // Sol
delay(200);
tone(10, 175, 400); // Fa
allume = true;
}
void setup()
{
Serial.begin(115200); // Débuggage
// Broches utilisées
DDRC = 0b00000111; // Adresse de la ligne, autres bits non utilisés
DDRB = 0b00101111; // Broches de contrôle
pinMode(2,INPUT_PULLUP); // Pavé numérique 8x8
pinMode(3,INPUT_PULLUP);
pinMode(4,INPUT_PULLUP);
pinMode(5,INPUT_PULLUP);
pinMode(6,INPUT_PULLUP);
pinMode(7,INPUT_PULLUP);
// Timer 2: 490Hz pour être synchrone avec le PWM naturel du timer 1 si besoin
// Avec 7 lignes, le rafraichissement est à 70Hz
TIMSK2 = 1; // Interruptions en route
}
ISR(TIMER2_OVF_vect)
// On n'affiche qu'une seule ligne 490 fois par seconde. Pour afficher les caractères
// en entier c'est la succession des 7 appels qu le fera.
// Pour afficher la suivante, il faut la renvoyer
// dans le registre à décalage et faire le transfert. Les données sont préparées dans
// la variable "afficher"
// J'aurais pu passer par le SPI, mais j'ai eu la paresse de regarder comment il faut
// le configurer. Mais les broches le permettent.
// Cette fonction dure environ 0,1ms pour 2 afficheurs
{
static byte ligne; // Numéro de la ligne 0..6
static uint32_t envoi; // les 24 valeurs de l'envoi
// Incrémenter la ligne du dernier appel
if (++ligne == 7) ligne = 0;
// Tranférer des données dans le registre à décalage
// Pour un seul afficheur, on transfert un unsigned long qui est préparé
for (byte unAfficheur=0; unAfficheur<NOMBRE_AFFICHEURS; unAfficheur++) // Pour plusieurs afficheurs
{
envoi = afficher[unAfficheur][ligne]; // On récupère le long à envoyer
for (byte colonne=0; colonne<24; colonne++) // 24 pixels à envoyer, 20 aurait suffit si on n'avait qu'un seul afficheur
{
if ((envoi & 1) == 1) DIN_1; else DIN_0; // Envoi d'un bit
CLK_VALIDE; // Envoi du bit, la validation se fait sur le front montant
envoi = envoi >> 1; // Décalage pour préparer le bit suivant. Mis ici pour rallonger l'impulsion d'horloge
CLK_REPOS; // Reposd e l'hologe. Front inactif
}
}
OUTPUT_DISABLE; // Eteindre l'afficheur pour éviter d'envoyer la donnée sur la ligne précédente
LIGNE = ligne; // Passer à la ligne suivante
STROBE_ENABLE; STROBE_DISABLE; // Valider les données transmises
if (allume) OUTPUT_ENABLE; // Rallumer l'afficheur
// Intensité variable sans le PWM
// Si on allume au maxi, c'est environ 2ms (490Hz). Allumer 10µs c'est 1/400
if (lumiere < 1500)
{
delayMicroseconds(lumiere);
OUTPUT_DISABLE;
}
}
struct element { // Evénement élémentaire
unsigned long duree; // En secondes
String mot; // Ce qu'il faut afficher
byte musique; // 0:pas de musique, 1:coucou, 2:byebye
};
String chrono="00-00-00"; // Affichage de l'heure
String affichageEnCours; // Le mot affiché
long temps, // Temps corrigé en seconde
tempsAfficheur,
correction=17*3600L+0*60+0, // Heure à l'allumage, correction de la dérive. Ici départ à 17h
prochain; // Heure du prochain événement
byte indiceDepart = 0; // Index dans la suite des événements
word memoireLumiere; // Memorisation de lumière pendant le jeu
const element departs[] = { // Suite des événements
{23*3600L+43*60+50,"",0}, // Temps mort du départ
{300,"",1}, // Bip 5mn avant
{60,"RAY",1}, // -> démarrage du jeu 23h48:50, explications 23h48
{10," ",2},
{60,"CHA",1},
{3," ",2},
{60,"FAN",1},
{3," ",2},
{60,"CUI",1},
{3," ",2},
{60,"LOU",1},
{3," ",2},
{55,"DIS",1},
{3," ",2},
{50,"NEU",1},
{3," ",2},
{45,"UIT",1},
{3," ",2},
{40,"SAIT",1},
{3," ",2},
{35,"SIS",1},
{3," ",2},
{30,"CINQ",1},
{2," ",2},
{25,"QUATRE",1},
{2," ",2},
{20,"TROIS",1},
{2," ",2},
{15,"DEUX",1},
{1," ",2},
{10,"UN",1},
{1," ",2},
{10,"2024",1},
{0,"",0}};
void change(byte abscisse, byte ordonnee, long valeur)
// Change le valeur de correction (met à l'heure) pour un bouton
// Cette fonction scanne une touche du keypad et agit en conséquence
//
// Câblage
// 4 5 6 7
// │ │ │ │
// ├─\ ├─\ ├─\ ├─\ .
// │ └──│─┴──│─┴──│─┴──▷├─┐
// ├─\ ├─\ ├─\ ├─\ ├─ 3
// │ └──│─┴──│─┴──│─┴──┤◁─┘
// ├─\ ├─\ ├─\ ├─\ .
// │ └──│─┴──│─┴──│─┴──▷├─┐
// └─\ └─\ └─\ └─\ ├─ 2
// └────┴────┴────┴──┤◁─┘
//
// Correspond à la matrice carrée triple:
// │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 2 │ X │ / │ -10s │ +10s │ -1s │ +1s │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 3 │ / │ X │ -10h │ +10h │ -1h │ +1h │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 4 │ -10mn │ faib │ X │ / │ / │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 5 │ +10mn │ fort │ / │ X │ / │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 6 │ -1mn │ /Son │ / │ / │ X │ / │
// ──┼───────┼──────┼──────┼──────┼─────┼─────┤
// 7 │ +1mn │ Son │ / │ / │ / │ X │
// ──┴───────┴──────┴──────┴──────┴─────┴─────┘
{
pinMode(abscisse,OUTPUT); digitalWrite(abscisse, LOW);
if (digitalRead(ordonnee)==LOW) // Bouton appuyé
{
if (abscisse != 3) correction += valeur;
else
{
if ((ordonnee == 4) && (lumiere > 1)) lumiere /= 2; // Diminution de l'éclairage exponentiel
if ((ordonnee == 5) && (lumiere < 1500)) lumiere *= 2; // Augmentation de l'éclairage
}
delay(20); // Antirebond
while (digitalRead(ordonnee)==LOW) // On attend le relâchement
delay(20);
}
pinMode(abscisse,INPUT_PULLUP);
}
void loop()
{
// Calcul de l'heure pour le format d'affichage
tempsAfficheur = temps = (millis()/1000)+correction; // En secondes
while (tempsAfficheur >= 86400L) tempsAfficheur -= 86400L;
while (tempsAfficheur < 0) tempsAfficheur += 86400L;
chrono[7] = (tempsAfficheur % 10) + '0';
tempsAfficheur /= 10; // En 10s
chrono[6] = (tempsAfficheur % 6) + '0';
tempsAfficheur /= 6; // En mn
chrono[4] = (tempsAfficheur % 10) + '0';
tempsAfficheur /= 10; // En 10mn
chrono[3] = (tempsAfficheur % 6) + '0';
tempsAfficheur /= 6; // En h
chrono[1] = (tempsAfficheur % 10) + '0';
tempsAfficheur /= 10; // En 10h
chrono[0] = tempsAfficheur + '0';
// Lecture du pavé numérique
change(4, 3, -36000L);
change(6, 3, -3600);
change(2, 4, -600);
change(2, 6, -60);
change(4, 2, -10);
change(6, 2, -1);
change(7, 2, 1);
change(5, 2, 10);
change(2, 7, 60);
change(2, 5, 600);
change(7, 3, 3600);
change(5, 3, 36000L);
change(3, 5, 0);
change(3, 4, 0);
pinMode(3,OUTPUT); digitalWrite(3, LOW);
if (digitalRead(7)==LOW)
{
allume = false;
OUTPUT_DISABLE;
tone(10, 220);
}
if (digitalRead(6)==LOW)
{
noTone(10);
allume = true;
}
pinMode(3,INPUT_PULLUP);
//Déroulement du jeu
if (indiceDepart < 0xff) // On na pas fini
if (prochain <= temps) // On va travailler sur l'événement prochain
{
affichageEnCours = departs[indiceDepart].mot;
if (departs[indiceDepart].musique == 1) coucou();
else if (departs[indiceDepart].musique == 2) byebye();
prochain += departs[indiceDepart].duree;
if ((departs[indiceDepart].duree) == 0)
{ // Fin du jeu
indiceDepart = 0xFE;
lumiere = memoireLumiere;
}
if (affichageEnCours == "RAY")
{ // Début du jeu, passage en lumère maxi
memoireLumiere = lumiere;
lumiere = 2000;
}
indiceDepart++; // Prêt à lire l'événement suivant
}
// Affichage
if (affichageEnCours == "") affiche(chrono); else affiche(affichageEnCours);
}
La fonte de caractère est:
const byte font[125*7] PROGMEM = {
B00000, // espace
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00100, // !
B00100,
B00100,
B00100,
B00100,
B00000,
B00100,
B01010, // "
B01010,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // #
B01010,
B11111,
B01010,
B11111,
B01010,
B00000,
B00100, // $
B11110,
B00001,
B01110,
B10000,
B01111,
B00100,
B10011, // %
B10011,
B01000,
B00100,
B00010,
B11001,
B11001,
B00110, // &
B01001,
B01001,
B00110,
B00101,
B01001,
B10110,
B00100, // '
B00100,
B00000,
B00000,
B00000,
B00000,
B00000,
B01000, // (
B00100,
B00100,
B00100,
B00100,
B00100,
B01000,
B00010, // )
B00100,
B00100,
B00100,
B00100,
B00100,
B00010,
B00000, // *
B10101,
B01110,
B11111,
B01110,
B10101,
B00000,
B00000, // +
B00100,
B00100,
B11111,
B00100,
B00100,
B00000,
B00000, // ,
B00000,
B00000,
B00000,
B00000,
B00100,
B00010,
B00000, // -
B00000,
B00000,
B01110,
B00000,
B00000,
B00000,
B00000, // .
B00000,
B00000,
B00000,
B00000,
B00000,
B00100,
B10000, // /
B01000,
B01000,
B00100,
B00010,
B00010,
B00001,
B00110, // 0
B01001,
B01001,
B01001,
B01001,
B01001,
B00110,
B00100, // 1
B00110,
B00100,
B00100,
B00100,
B00100,
B01110,
B00110, // 2
B01001,
B01000,
B00100,
B00010,
B00001,
B01111,
B00110, // 3
B01001,
B01000,
B00110,
B01000,
B01001,
B00110,
B01001, // 4
B01001,
B01001,
B01111,
B01000,
B01000,
B01000,
B01111, // 5
B00001,
B00001,
B00111,
B01000,
B01001,
B00110,
B00110, // 6
B01001,
B00001,
B00111,
B01001,
B01001,
B00110,
B01111, // 7
B01000,
B00100,
B00100,
B00010,
B00010,
B00010,
B00110, // 8
B01001,
B01001,
B00110,
B01001,
B01001,
B00110,
B00110, // 9
B01001,
B01001,
B01110,
B01000,
B01001,
B00110,
B00000, // :
B00000,
B00000,
B00100,
B00000,
B00000,
B00100,
B00000, // ;
B00000,
B00000,
B00100,
B00000,
B00100,
B00010,
B10000, // <
B01000,
B00100,
B00010,
B00100,
B01000,
B10000,
B00000, // =
B00000,
B00000,
B11111,
B00000,
B11111,
B00000,
B00010, // >
B00100,
B01000,
B10000,
B01000,
B00100,
B00010,
B01110, // ?
B10001,
B10000,
B01000,
B00100,
B00000,
B00100,
B01110, // @
B10001,
B11101,
B10101,
B11101,
B00001,
B11110,
B01110, // A
B10001,
B10001,
B11111,
B10001,
B10001,
B10001,
B01111, // B
B10001,
B10001,
B01111,
B10001,
B10001,
B01111,
B01110, // C
B10001,
B00001,
B00001,
B00001,
B10001,
B01110,
B01111, // D
B10001,
B10001,
B10001,
B10001,
B10001,
B01111,
B11111, // E
B00001,
B00001,
B01111,
B00001,
B00001,
B11111,
B11111, // F
B00001,
B00001,
B01111,
B00001,
B00001,
B00001,
B01110, // G
B10001,
B00001,
B11001,
B10001,
B10001,
B01110,
B10001, // H
B10001,
B10001,
B11111,
B10001,
B10001,
B10001,
B01110, // I
B00100,
B00100,
B00100,
B00100,
B00100,
B01110,
B11110, // J
B10000,
B10000,
B10000,
B10000,
B10001,
B01110,
B10001, // K
B01001,
B00101,
B00011,
B00101,
B01001,
B10001,
B00001, // L
B00001,
B00001,
B00001,
B00001,
B00001,
B11111,
B10001, // M
B11011,
B10101,
B10001,
B10001,
B10001,
B10001,
B10001, // N
B10001,
B10011,
B10101,
B11001,
B10001,
B10001,
B01110, // O
B10001,
B10001,
B10001,
B10001,
B10001,
B01110,
B01111, // P
B10001,
B10001,
B01111,
B00001,
B00001,
B00001,
B01110, // Q
B10001,
B10001,
B10001,
B10001,
B01001,
B10110,
B01111, // R
B10001,
B10001,
B01111,
B10001,
B10001,
B10001,
B01110, // S
B10001,
B00001,
B01110,
B10000,
B10001,
B01110,
B11111, // T
B00100,
B00100,
B00100,
B00100,
B00100,
B00100,
B10001, // U
B10001,
B10001,
B10001,
B10001,
B10001,
B01110,
B10001, // V
B10001,
B10001,
B01010,
B01010,
B00100,
B00100,
B10001, // W
B10001,
B10001,
B10101,
B10101,
B11011,
B10001,
B10001, // X
B10001,
B01010,
B00100,
B01010,
B10001,
B10001,
B10001, // B
B10001,
B01010,
B00100,
B00100,
B00100,
B00100,
B11111, // Z
B10000,
B01000,
B00100,
B00010,
B00001,
B11111,
B01110, // [
B00010,
B00010,
B00010,
B00010,
B00010,
B01110,
B00001, // barre oblique inverse
B00010,
B00010,
B00100,
B01000,
B01000,
B10000,
B01110, // ]
B01000,
B01000,
B01000,
B01000,
B01000,
B01110,
B00100, // ^
B01010,
B10001,
B00000,
B00000,
B00000,
B00000,
B00000, // _
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B00010, // '
B00100,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // a
B00000,
B01110,
B10000,
B11110,
B10001,
B11110,
B00001, // b
B00001,
B01111,
B10001,
B10001,
B10001,
B01111,
B00000, // c
B00000,
B01110,
B10001,
B00001,
B10001,
B01110,
B10000, // d
B10000,
B11110,
B10001,
B10001,
B10001,
B11110,
B00000, // e
B00000,
B01110,
B10001,
B01111,
B00001,
B11110,
B01100, // f
B10010,
B00010,
B00111,
B00010,
B00010,
B00010,
B00000, // g
B01110,
B10001,
B10001,
B11110,
B10000,
B01110,
B00001, // h
B00001,
B01111,
B10001,
B10001,
B10001,
B10001,
B00100, // i
B00000,
B00100,
B00100,
B00100,
B00100,
B00100,
B01000, // j
B00000,
B01000,
B01000,
B01000,
B01001,
B00110,
B00001, // k
B00001,
B10001,
B01001,
B00111,
B01001,
B10001,
B00100, // l
B00100,
B00100,
B00100,
B00100,
B00100,
B01000,
B00000, // m
B00000,
B01111,
B10101,
B10101,
B10101,
B10101,
B00000, // n
B00000,
B01111,
B10001,
B10001,
B10001,
B10001,
B00000, // o
B00000,
B01110,
B10001,
B10001,
B10001,
B01110,
B00000, // p
B00000,
B01111,
B10001,
B01111,
B00001,
B00001,
B00000, // q
B00000,
B11110,
B10001,
B11110,
B10000,
B10000,
B00000, // r
B00000,
B11101,
B00011,
B00001,
B00001,
B00001,
B00000, // s
B00000,
B11110,
B00001,
B01110,
B10000,
B01111,
B00010, // t
B00010,
B00111,
B00010,
B00010,
B10010,
B01100,
B00000, // u
B00000,
B10001,
B10001,
B10001,
B10001,
B11110,
B00000, // v
B00000,
B10001,
B10001,
B01010,
B01010,
B00100,
B00000, // w
B00000,
B10101,
B10101,
B10101,
B10101,
B01010,
B00000, // x
B00000,
B10001,
B01010,
B00100,
B01010,
B10001,
B00000, // B
B00000,
B10001,
B10001,
B11110,
B10000,
B01110,
B00000, // z
B00000,
B11111,
B01000,
B00100,
B00010,
B11111,
B11000, // {
B00100,
B00100,
B00010,
B00100,
B00100,
B11000,
B00100, // |
B00100,
B00100,
B00100,
B00100,
B00100,
B00100,
B00011, // }
B00100,
B00100,
B01000,
B00100,
B00100,
B00011,
B00000, // ~
B00000,
B00010,
B10101,
B01000,
B00000,
B00000,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00010, // à
B00100,
B01110,
B10000,
B11110,
B10001,
B11110,
B01000, // á
B00100,
B01110,
B10000,
B11110,
B10001,
B11110,
B00100, // â
B01010,
B01110,
B10000,
B11110,
B10001,
B11110,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000, // ç
B11110,
B00001,
B00001,
B11110,
B01000,
B00110,
B00010, // è
B00100,
B01110,
B10001,
B01111,
B00001,
B11110,
B01000, // é
B00100,
B01110,
B10001,
B01111,
B00001,
B11110,
B00100, // ê
B01010,
B01110,
B10001,
B01111,
B00001,
B11110,
B10001, // ë
B00000,
B01110,
B10001,
B01111,
B00001,
B11110,
B01110, // €
B10001,
B00111,
B00001,
B00111,
B10001,
B01110,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00100, // î
B01010,
B00000,
B00100,
B00100,
B00100,
B00100,
B10001, // ï
B00000,
B00100,
B00100,
B00100,
B00100,
B00100,
B00100, // °
B01010,
B00100,
B00000,
B00000,
B00000,
B00000,
B00100, // ±
B00100,
B11111,
B00100,
B00100,
B00000,
B11111,
B00010, // ò
B00100,
B01110,
B10001,
B10001,
B10001,
B01110,
B01000, // ó
B00100,
B01110,
B10001,
B10001,
B10001,
B01110,
B00100, // ô
B01010,
B01110,
B10001,
B10001,
B10001,
B01110,
B00000, // µ
B00000,
B10001,
B10001,
B01111,
B00001,
B00001,
B10001, // ö
B00000,
B01110,
B10001,
B10001,
B10001,
B01110,
B00000, // ÷
B00100,
B00000,
B11111,
B00000,
B00100,
B00000,
B00000, // XXXXX
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00010, // ù
B00100,
B10001,
B10001,
B10001,
B10001,
B11110,
B01000, // ú
B00100,
B10001,
B10001,
B10001,
B10001,
B11110,
B00100, // û
B01010,
B10001,
B10001,
B10001,
B10001,
B11110,
B10001, // ü
B00000,
B10001,
B10001,
B10001,
B10001,
B11110
};
Comme il a fallu faire vite, c'est écrit à l'arrache, sans économies. Il devrait être possible d'utiliser efficacement le SPI, mais j'ai eu la flegme de regarder les registres. L'écriture par la fonction affiche() centre le texte, et un afficheur pour moi c'est 4 digits. Un digit c'est 5 colonnes, 4 digits, c'est 20 bits à passer, un registre à décalage, c'est 8 bits, il en faut 3 et 4 bits inutiles sont donc à décaler.
Conclusion: vous n'aurez sans doute pas le même afficheur, mais je vous assure que l'idée de l'animation est bonne. Personne quasiment ne compte ses points, cela n'a d'ailleurs pas d'intérêt.
Prendre un autre afficheur, un autre programme et une autre carte est encouragé, il n'y a pas de droits d'auteur. Il vous reste un peu moins d'un an pour le faire.