Suite : affichage des données sur LCD, programmation des "drivers" (atmega168 : "carte vidéo" série => LCD)
Histoire d'optimiser toujours et encore, aujourd'hui, j'ai travaillé sur l'affichage d'une aiguille et de sa valeur en texte à partir d'une donnée reçue par le port série du 168.
Pour la plus par des valeurs, une échelle de 256 pas suffit :
-
Vitesse : de 0 à 255Km/h par pas de 1km/h, même si on est limité à 130, une résolution de 1 suffit.
-
Niveau carburant : de 0 à 48 litres, 255 valeurs par pas de 0.2l (facteur = 5) donnent un affichage possible de 0 à 51l
-
Température eau moteur : de 0 à 120°, 255 valeurs par pas de 0.5° (facteur = 2) donnent un affichage possible de 0 à 127.5°
Coup de bol, si on part d'une valeur reçue sur 8 bits, avec un simple facteur entier (j'aime pas trop les opérations arithmétiques avec des floats quand il faut être rapide) et en plaçant la virgule au bon endroit (variable v), on obtient les valeurs suivantes :
facteur |
range |
pas |
v=0 |
v=1 |
v=2 |
v=3 |
1 |
0 à 255 |
1 |
0 à 255 +/- 1 |
0 à 25,5 +/- 0.1 |
0 à 2,55 +/- 0.01 |
0 à 0,255 +/- 0.001 |
2 |
0 à 510 |
2 |
0 à 510 +/- 2 |
0 à 51,0 +/- 0.2 |
0 à 5,10 +/- 0.02 |
0 à 0,510 +/- 0.002 |
3 |
0 à 765 |
3 |
0 à 765 +/- 3 |
0 à 76,5 +/- 0.3 |
0 à 7,65 +/- 0.03 |
0 à 0,765 +/- 0.003 |
4 |
0 à 1020 |
4 |
0 à 1020 +/- 4 |
0 à 102,0 +/- 0.4 |
0 à 10,20 +/- 0.04 |
0 à 1,020 +/- 0.004 |
5 |
0 à 1275 |
5 |
0 à 1275 +/- 5 |
0 à 127,5 +/- 0.5 |
0 à 12,75 +/- 0.05 |
0 à 1,275 +/- 0.005 |
6 |
0 à 1530 |
6 |
0 à 1530 +/- 6 |
0 à 153,0 +/- 0.6 |
0 à 15,30 +/- 0.06 |
0 à 1,530 +/- 0.006 |
7 |
0 à 1785 |
7 |
0 à 1785 +/- 7 |
0 à 178,5 +/- 0.7 |
0 à 17,85 +/- 0.07 |
0 à 1,785 +/- 0.007 |
8 |
0 à 2040 |
8 |
0 à 2040 +/- 8 |
0 à 204,0 +/- 0.8 |
0 à 20,40 +/- 0.08 |
0 à 2,040 +/- 0.008 |
9 |
0 à 2295 |
9 |
0 à 2295 +/- 9 |
0 à 229,5 +/- 0.9 |
0 à 22,95 +/- 0.09 |
0 à 2,295 +/- 0.009 |
[/td][/tr]
[/table]
une fois l'octet reçu précédé de son code d'affectation, je sais donc quel facteur lui est associé et où je dois mettre la virgule pour que l'affichage me donne la valeur finale. tout cela passe par une fonction
void affiche_valeur_4_digits(byte octet, byte facteur, byte virgule, byte x, byte y){ // affiche un nombre compris entre 0 et 9999 avec ou sans virgule sur 4 digits
word afficher = octet * facteur;
for (byte i = 4; i > 0; i--){
// extraction du digit i dans la variable "afficher"
dessine_digit(digit, x + 4 - i, y);
if ((i == virgule + 1) && (virgule > 0)) dessine_la_virgule_ici();
}
}
rien de plus simple en fait... Bon, la fonction ci-dessus est beaucoup plus hard en vrai, mais le principe est là.
On peut également continuer avec un facteur jusqu'à 256, ainsi, on couvre toutes les gammes de valeurs que l'on veut avec pas mal de précision, et tout ça en n'envoyant seulement un octet... Plus précis encore si on prend en compte un offset (la valeur mini en dessous de laquelle on ne tombera jamais)...
facteur |
range |
pas |
v=0 |
v=1 |
v=2 |
v=3 |
39 |
0 à 10200 |
39 |
0 à 10200 +/- 39 |
0 à 1020.0 +/- 3.9 |
0 à 102.00 +/- 0.39 |
0 à 10,200 +/- 0.039 |
Ca, c'est pour l'affichage du texte. Côté aiguille qui bouge, j'ai utilisé Excel pour calculer des tableaux de coordonnées relatives, afin de ne pas avoir à calculer les coordonnées du bout de l'aiguille. J'ai trouvé qu'avec un rayon de 40 pixels, on obtient 64 coordonnées consécutives qui ne se chevauchent pas (64 points distincts) faisant un arc de cercle de 90° pile. Ainsi, l'octet reçu de 256 valeurs, soit je le divise par 4 et ça me donne 64 angles sur 90° (soit mes 64 coordonnées), soit je le laisse telquel, et ça me fait un joli tour complet autour du centre. En plus, les sinus et cosinus se croisent, donc mes 64 coordonnées peuvent être réduites à deux tableaux de 32 octets. En regardant dans quel 1/8 du cercle va se trouver l'aiguille, on choisit l'un ou l'autre des deux tableaux pour ajouter la valeur à X1 ou y1 (centre de l'aiguille) et ainsi trouver l'autre bout de l'aiguille. Avantage, pour plusieurs aiguilles, c'est le même tableau qui sert...
Exemple pour l'aiguille de vitesse, qui doit tourner sur 324°pour 0 à 180km/h sur un rayon de 50 pixels : deux tableaux de 26 ordonnées me permettent de calculer mon aiguille :
volatile byte a0_x[26]={50, 50, 50, 50, 50, 49, 49, 49, 48, 48, 48, 47, 46 ,46, 45, 45, 44, 43, 42, 41, 40, 40, 39, 38, 36, 35};
volatile byte a0_y[26]={ 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21, 23, 24, 25, 27, 28, 29, 31, 32, 33, 34, 35};
// (x0, y0) est le centre de l'aiguille.
//
void vitesse_affiche(){
byte v_index;
if(vitesse != vitesse_old){ // ne change l'affichage que si besoin
v_index = (vitesse + 10) % 25; // calcule le modulo pour indexation des tableaux de coordonnées relatives
lcd_line(x0, y0, x00, y00, UNPUT); // effacer l'ancienne aiguille
lcd_line(x0 - 4, y0 - 4, x00, y00, UNPUT);
lcd_line(x0 + 4, y0 + 4, x00, y00, UNPUT);
lcd_line(x0 - 4, y0 + 4, x00, y00, UNPUT);
lcd_line(x0 + 4, y0 - 4, x00, y00, UNPUT);
if (vitesse < 15) { // cherche dans quel 8ième de cercle se trouve la nouvelle aiguille
x00 = x0 - a0_y[v_index]; // calcule le bout externe de l'aiguille
y00 = y0 + a0_x[v_index];
} else if (vitesse < 40) {
x00 = x0 - a0_x[25-v_index];
y00 = y0 + a0_y[25-v_index];
} else if (vitesse < 65) {
x00 = x0 - a0_x[v_index];
y00 = y0 - a0_y[v_index];
} else if (vitesse < 90) {
x00 = x0 - a0_y[25-v_index];
y00 = y0 - a0_x[25-v_index];
} else if (vitesse < 115) {
x00 = x0 + a0_y[v_index];
y00 = y0 - a0_x[v_index];
} else if (vitesse < 140) {
x00 = x0 + a0_x[25-v_index];
y00 = y0 - a0_y[25-v_index];
} else if (vitesse < 165) {
x00 = x0 + a0_x[v_index];
y00 = y0 + a0_y[v_index];
} else if (vitesse < 190) {
x00 = x0 + a0_y[25-v_index];
y00 = y0 + a0_x[25-v_index];
} else {
x00 = x0 - a0_y[v_index];
y00 = y0 + a0_x[v_index];
}
lcd_line(x0 - 4, y0 - 4, x00, y00, PUT); // dessin de l'aiguille en 5 segments
lcd_line(x0 + 4, y0 + 4, x00, y00, PUT);
lcd_line(x0 - 4, y0 + 4, x00, y00, PUT);
lcd_line(x0 + 4, y0 - 4, x00, y00, PUT);
lcd_line(x0, y0, x00, y00, PUT);
lcd_set_graph_xy(x0t, y0t);
lcd_byte_perso(1, 3, vitesse, 0); // affichage valeur numérique police 1, taille 3
vitesse_old = vitesse;
}
}
Le code ci-dessus marche super, je n'ai pas encore testé les aiguilles à rayon de 40px, mais il me tarde de le faire!