[Projet] Un tableau de bord numérisé

Comme il n'est pas terminé, je ne le mets pas dans "réalisations et projets finis"...

Bonjour à tous,

Depuis plusieurs années, je traine dans ma tête un projet pour ma vieille auto (R11 1.4L 1987) :

un tableau de bord électronisé pour remplacer celui d'origine.

L'idée première était de remplacer la jauge à essence (qui prend pas mal de place) par un compte-tour. On trouve dans les R19, R21, et même d'autres R11 des TDB avec compte-tour, même gabarit. Puis de fil en aiguille, j'ai fait évoluer les choses, en pensant à un écran LCD, puis aujourd'hui, deux LCD graphiques en conservant les connecteurs d'origine si un jour je veux remettre un tableau de bord d'origine (on ne peut jamais se fier à l'électronique dans une voiture, c'est bien connu).

Petit préliminaire...

Depuis plus d'un an, ma R11 est équipée d'un UNO qui récupère le signal du capteur PMH, en déduit la vitesse de rotation du moteur, et calcul la vitesse de la voiture en 5ème (connaissant les rapports de boîte, périmètre des roues, il suffit de multiplier la vitesse du moteur par un simple facteur pour trouver la vitesse théorique). Ce UNO gère également un servo-moteur qui tire sur le mécanisme d'accélérateur (via une simple ficelle dans une gaine de frein de vélo) et propose un mode "régulateur de vitesse". Ca marche plutôt bien, on peut réguler à 70, 90, 110 et 130. C'est même assez précis, puisqu'en régulant à 90, la vitesse varie de 85 à 92Km/h, et le régulateur se coupe de lui-même dès qu'il détecte la position "pied-levé" du servo moteur (généralement aux alentours de 94Km/h, qui reste en dessous de la limite des radars automatiques :smiley: ), et dès qu'on touche la pédale de frein ou d'embrayage, il se coupe aussi. 5 boutons et un LCD 16x2 en guise d'IHM :

Une petite interface électronique qui se place à côté du moteur (mise en forme signaux PMH, alimentation servomoteur...)

Le servomoteur modifié (ajout d'un engrenage et déport du potentiomètre pour plus de puissance) :

Le système en lui-même :

Bref, j'ai l'intension de combiner le régulateur et les écrans LCD autour d'un MEGA2560.

Alors j'ai désossé un tableau de bord. découpe du plastique et fabrication d'une plaque de support des LCD (du CI double face, c'est super facile à travailler, et j'en ai plusieurs centaines de Kg...)

Les deux LCD "presque" à leurs places, ils ne sont pas encore fixés :

Puis, pour reprogrammer facilement les "serial back-pack" de sparkfun qui étaient complètement buggés d'origine, j'ai fait un shield maison pour arduino/ISP :

Et un autre shield pour relier l'ATMEGA168 du LCD aux RX/TX/RESET/alim d'une carte UNO dépourvue du DIP 328 :

Pour l'instant, j'en suis à la programmation des LCD. Distar (celui fabrique les LCD) n'a pas trop gazé, puisqu'il a forcé le driver T6963C en petite police de 5x7 sur une grille de 8x8. Le T6963C possède une police de 7x8 en interne, mais du coup inaccessible.

Les LCD possèdent une RAM assez importante que l'on peut découper à sa guise en "pages". On définit donc une page graphique (un octet = 8 pixels) et une page texte (1 octet = 1 caractère). J'ai calculé qu'on peut obtenir 22 pages graphiques et autant de pages texte. On peut ainsi écrire dans une page, alors que le LCD en affiche une autre. Je ne détaille pas plus le fonctionnement des LCD, ça ferait plutôt l'objet d'un topic que j'avais déjà créé à ce sujet.

Donc, dans l'idée, je programme le 168 du LCD pour qu'il dessine l'interface graphique voulue, et quand il reçoit une valeur par le port série, il l'affiche sous forme de texte ou de graphique. Côté MEGA2560, c'est super simple, car il me suffira d'envoyer par exemple les octets 0x15 puis 0x45 (0x15 pour "afficher vitesse" et 0x45 la valeur (69)) par port série, et le 168 se débrouille par la suite pour "bouger" l'aiguille sur l'écran et afficher "69 Km/h" à un endroit précis. Bref, je dispose d'une accélération matérielle assez puissante. j'accède aux LCD avec un port série pour chaque, c'est tout.

Le côté ARDUINO :

Le MEGA2560 va mesurer divers signaux et les transformer en valeurs à afficher sur les LCD. La liste non exhaustive :

  • vitesse véhicule
  • rotation moteur
  • niveau réservoir essence
  • consommation, autonomie
  • kilométrage total et journalier
  • avance à l'allumage
  • température moteur
  • niveau / pression huile
  • lambda échappement (taux CO / CO2)
  • divers voyants du tableau de bord
  • messages d'alerte de fonctionnement

Mais aussi remplir certaines fonctions...

  • remplacer le câble d'accélérateur par un potar et un servomoteur
  • Régulation / limitation de vitesse
  • enregistrement de données de parcours
  • monitoring de fonctionnement du moteur
  • interfaçage avec un PC sur USB pour diagnostiques, relevés...
  • ...

A suivre!

1 Like

J'étale un peu sur plusieurs posts pour plus de clarté...

Un peu d'électronique, le choix des capteurs, solutions techniques :

Pour le calcul de la vitesse moteur, j'avais fait un topic pour tenter de trouver une solution de précision. En effet, le signal qui sort du capteur n'est pas très utilisable, puisqu'il donne un signal carré de 44 impulsions par tour moteur, mais il manque deux "dents" à chaque demi tour de moteur. Ce "trou" dans le signal permet au calculateur (AEI) d'allumage de connaître la position des pistons et donc de générer l'étincelle aux bougies au bon moment en fonction de la vitesse de rotation et dépression dans l'admission. Donc je vais utiliser un ATMEGA328 qui va "extraire" deux données du signal du capteur : une impulsion correspondant au PMH des pistons et régénérer les "trous" du signal pour avoir un signal carré parfait pour compter la vitesse de rotation du moteur. voir le topic correspondant : Interface à base de pic pour gestion d'impulsions - #20 by jfs - Français - Arduino Forum

Pour l'instant, le 328 me génère l'impulsion PMH ainsi qu'un signal carré de 64 impulsions par tour moteur (c'est tombé comme ça, les mesures n'en seront que plus précises...)

Calcul de la vitesse du véhicule :

D'origine, le compteur km est relié mécaniquement à la sortie de la boîte de vitesse par un câble qui tourne dans une gaine. J'avais deux solutions :

soit trouver un câble tout fait dans une casse. C'est le même câble, mais avec un boîtié dessus appelé "générateur d'impulsion" qui donne 1 impulsion tous les 20cm parcourus par la voiture. Dans l'idée, ce serait pas mal, mais malheureusement, selon le type de boîte de vitesse (il en existe plus de 200 qui ont été montées sur super5, R9, R11, R15... jusqu'à la R25, Clio, Twingo...), le câble de sortie de boîte ne tourne pas à la même vitesse, et les générateurs d'impulsions n'ont pas été conçus pour ma boîte, donc je n'aurai pas 1 impulsion par 20cm, mais un truc un peu plus batard (genre 18,55555555cm, 21.3333333cm...).

Reste la solution 2 : construire moi-même ce générateur d'impulsion. Pour celà, j'ai dépouillé un vieux compteur et adapté un petit engrenage qui fait tourner un moteur récupéré sur une imprimante HP.

ce n'est pas le moteur qui m'intéresse, mais le disque encodeur qu'il possède. Si ce moteur est bien connu sur le net comme pièce détachée, je n'ai pas trouvé le nombre de "crans" du disque. Il y a un capteur fourche en quadrature dessus, mais le sens de rotation m'importe peu, car en marche arrière, ça représente aussi des Km pour le moteur, donc autant les compter comme "parcourus". Alors j'ai fait un compteur avec un arduino qui m'affiche la valeur de sortie sur 8 leds (un octet à déchiffrer, mais avec l'expérience, j'arrive à traduire à la volée un octet de leds en valeur hexa...). Bref, pour un tour de câble compteur, j'ai une moyenne de 80 impulsions (j'ai fait une dizaine de relevés, sur un, deux et trois tours en entrée, chaque relevé me donnait la même chose à +/-1 : 335 crans sur le disque). en calculant rapidement, ça me donne une impulsion toutes les 2.0609xxxcm parcourus. pas très précis en fait... si je néglige le 0.06cm, ça me fait une erreur de 3%, soit 300Km sur 10000, ou encore 100Km/h au lieu de 103, pas bon.

A voir, car je connais tous les rapports de toutes les boîtes renault et les caractéristiques des compteurs associés, donc la solution 1 sera finalement peut-être plus précise, car là, je connais exactement le nombre de crans du générateur d'impulsion renault!

La mesure de la consommation :

Il suffit de récupérer sur une twingo ou clio ou R19/21/25 un débitmètre. C'est un petit boîtier qui se place à l'arrivée d'essence du carburateur, et donne une impulsion tous les 80µl qui passent. La conso ne peut pas être précise sur une seule de ces impulsions, même si je peux trouver le déplacement de la voiture à 20cm près, car l'essence qui passe par le débitmètre arrive dans une cuve tampon du carburateur, donc le débit se fait par oscillations (la pompe à essence "pousse" l'essence à chaque fois que le moteur a fait 2 tours, et le pointeau de régulation de remplissage de cuve donne une hystérésis sur le débit) donc une seule impulsion ne sera pas représentative du débit réel. Mais avec un petit calcul, à 100Km/h et une conso de 6l/100 (soit 10ml par seconde), le débitmètre me fournirait une impulsion toutes les 8ms. cela calculé sur 1 seconde (125 impulsions du débitmètre), quitte à moyenner sur 16 secondes (16 mesures), le calcul sera plus précis.

Un peu de programmation :

Pour ce qui est de la programmation des LCD, j'ai dû créer des tables de caractères pour pouvoir afficher les valeurs en un peu plus gros que les caractères de 5mm d'origine. J'ai fait deux polices, l'une reprenant la classique LCD, et une autre qui ressemble plus à du 7 segments. Comme je n'ai pas trop de mémoire, je n'ai créé que des chiffres. un chiffre représente quand même 9 octets (deux polices de 10 caractères = 180octets en ram), par exemple, un 2 codé en police classique :

caractere_2[9] = {0x1C, 0x3E, 0x63, 0x03, 0x06, 0x18, 0x60, 0x7F, 0x3F}

Lorsque je me suis bien pris la tête à coder mes caractères, j'avais dans l'idée d'afficher en double les lignes de 1 à 6 du tableau pour diminuer la taille en mémoire, afin de sortir un caractère de 7x14 pixels avec seulement 9 octets. le résultat prévu était :

   XXX    1C
  XXXXX   3E
 XX   XX  63
 XX   XX
      XX  03
      XX
     XX   06
     XX
   XX     18
   XX
 XX       60
 XX
 XXXXXXX  7F
  XXXXXX  3F

Sauf que j'avais oublié de doubler les lignes du milieu... ça m'a affiché ça :

   XXX    1C
  XXXXX   3E
 XX   XX  63
      XX  03
     XX   06
   XX     18
 XX       60
 XXXXXXX  7F
  XXXXXX  3F

Petite erreur, mais intéressante finalement. Je me suis aperçu que je pouvais garder ça, donc j'ai défini deux tailles : 0 : simple en 7x9 (l'erreur), et 1 : 7x14 (l'idée d'origine) en doublant les lignes du milieu. Mais j'ai fini par élargir mes caractères en transformant mon octet "ligne" en un word, qui double chaque bits de l'octet, ce qui m'a permis d'obtenir deux tailles supplémentaires, taille 2 (14x9) :

      XXXXXX      1C
    XXXXXXXXXX    3E
  XXXX      XXXX  63
            XXXX  03
          XXXX    06
      XXXX        18
  XXXX            60
  XXXXXXXXXXXXXX  7F
    XXXXXXXXXXXX  3F

et taille 3 (14x14)

      XXXXXX      1C
    XXXXXXXXXX    3E
  XXXX      XXXX  63
  XXXX      XXXX  
            XXXX  03
            XXXX  
          XXXX    06
          XXXX    
      XXXX        18
      XXXX        
  XXXX            60
  XXXX            
  XXXXXXXXXXXXXX  7F
    XXXXXXXXXXXX  3F

Côté écran, ça donne ça :



Avec dans l'ordre des lignes :

  • police interne du LCD 5x7
  • police perso 0, taille 0
  • police perso 1, taille 0
  • police perso 0, taille 1
  • police perso 1, taille 1
  • police perso 0, taille 2
  • police perso 1, taille 2
  • police perso 0, taille 3
  • police perso 1, taille 3

Il faut que je règle le contraste, c'est un peu faiblard...

Pour la rapidité d'affichage, le remplissage de l'écran ci-dessus est invisible. Pour ceux qui me connaissent, ils savent déjà que je n'utilise aucun digitalWrite() ou pinMode() pour envoyer les données du 168 au T6963C, ni aucun delay() dans les impulsions, le T6963 est donné pour des tempos de 100ns, mes signaux font minimum 2 cycles FOSC, donc 123ns, je suis pile-poil dans les temps!

Le rétroéclairage est géré par une PWM du 168, donc par logiciel. Le mec qui avait développé le code d'origine du 168 chez sparkfun avait utilisé le timer2 qui générait une interruption toutes les 0.5ms, et à chaque interruption, il comptait pour savoir où il en était. S'il avait atteint la valeur d'éclairage souhaitée, faisait un bit_set / bit_clear sur la pin de sortie. une belle PWM en soft, sûr, mais qui devait bouffer un temps pas possible dans le code. Il n'avait même pas vu qu'il avait câblé les leds du rétroéclairage sur la pin OC1B, et qu'il suffisait de faire tourner le timer1 en PWM pour se décharger de toute perte de temps. Tout comme il avait défini un buffer de réception série de 512 octets (donc indexé par une variable de 16 bits et occupation du quart de la RAM), alors qu'un buffer de 256 octets était suffisant et tellement plus pratique à gérer : un index sur 8 bits revient tout seul à zéro après 255, même pas besoin de faire un index = index % 256 ou encore un if (index > 255) index = 0... autre bug rigolo : selon l'inclinaison d'un ligne à tracer, il manquait des pixels. Il y a aussi une fonction qui était dans la doc, mais pas implémentée dans le code, quand on l'appelle par port série, le LCD l'affichait sous forme de caractères insensés.

Bref, je ne sais pas comment ils recrutent leurs développeurs chez sparkfun, mais il vaut mieux se méfier de leurs produits...

Super_Cinci:
Bref, pour un tour de câble compteur, j'ai une moyenne de 80 impulsions (j'ai fait une dizaine de relevés, sur un, deux et trois tours en entrée, chaque relevé me donnait la même chose à +/-1 : 335 crans sur le disque). en calculant rapidement, ça me donne une impulsion toutes les 2.0609xxxcm parcourus. pas très précis en fait... si je néglige le 0.06cm, ça me fait une erreur de 3%, soit 300Km sur 10000, ou encore 100Km/h au lieu de 103, pas bon.

Bonjour Super_cinci
tu a aussi l'astuce d'utiliser les deux canaux A et B et de compter tous les flancs (montants et descendants) comme les canaux sont déphasés de 90° ça te multiplie par 4 le nombre de tops vu par tour.

Artouste:
Bonjour Super_cinci
tu a aussi l'astuce d'utiliser les deux canaux A et B et de compter tous les flancs (montants et descendants) comme les canaux sont déphasés de 90° ça te multiplie par 4 le nombre de tops vu par tour.

Il serait encore plus simple de coller une petite électronique avec un XOR entre les deux signaux A et B pour multiplier par 4 la précision en comptant tous les fronts (et ne pas bouffer plus de ressources de l'arduino, je vais déjà devoir souder des fils sur 8 pins non routées : les entrées de timers, les INT...), mais si tu regardes les photos de mon bricolage, tu vois que j'ai mis un réducteur entre le câble et le disque (ça divise la rotation du câble par 4.2 (10/42)). pour plus de précision, il me suffit de mettre le disque directement sur le câble, voire même d'inverser le réducteur... Mais il faut voire ensuite les capacités de comptage, car les 16 bits pourraient vite déborder... si j'ai 330 impulsions par tour de roue (pas de réducteur), ça me ferait dans les 200 000 impulsions pour 1Km (une imp correspondrait à 5mm, pas besoin d'autant de précision). Les 20cm du générateur d'impulsion Renault me suffiraient bien (puis côté mécanique, c'est étudié pour les vibrations etc etc...).

Puis le câble sur sa longueur (il fait 1m) peut "vibrer" et faire tourner le disque à l’envers de temps en temps, ne serait-ce qu'une seule impulsion générée à l'envers tous les deux tours de câble serait catastrophique pour ma précision...

Je vais aller chercher un générateur en casse pour tester (en notant le numéro de série de la boîte de vitesse sur laquelle il était, je saurai facilement trouver le bon calcul (combien de cm / impulsion).

Ca c'est du Tuning !

Tu penses pouvoir encore pouvoir passer le contrôle technique avec çà ?

N'oublie pas le TimeCounter :

barbudor:
Ca c'est du Tuning !

Tu penses pouvoir encore pouvoir passer le contrôle technique avec çà ?

N'oublie pas le TimeCounter :

bonjour barbudor
je crois que les Delorean ont eu une carrière bien plus éphémère que les R11 :grin:

Y'en a encore quelques unes qui roulent
Avec un peu d'imagination, on peu trouver une similitude avec la R11 (quoi que, plutot avec une Fuego...) XD

Salut,

Un sacré projet que tu nous présente dit donc :astonished:

L'écran LCD enfin le "backpack" pour être précis est complétement buggé, même sparkfun le reconnait ...
Il existe un firmware alternatif pas trop mal sur github (faut aller voir sur la page du produit), tu devrais leur envoyer un lien vers ton firmware ça aiderai beaucoup de personnes :wink:

Encore bravo pour le travail accomplit, je suis sûr qu'il ya de longue heures derrière tout ça :grin:

Mécaniquement, la fuego est une bombe! super solide, surdimensionnée... mais tellement moche... Par contre, elle se rapproche très bien de la delorean... J'ai déjà une horloge à LCD (d'origine...), mais pour le fun, j'ai un emplacement au dessus du cendrillon qui pourrait accueillir ce genre de gadget, bien que je comptais l'utiliser pour ranger un clavier 4x4... Mais le cendrier ne me sert à rien, donc ça fait un emplacement supplémentaire (chiche?)

skywodd:
Salut,

Un sacré projet que tu nous présente dit donc :astonished:

L'écran LCD enfin le "backpack" pour être précis est complétement buggé, même sparkfun le reconnait ...
Il existe un firmware alternatif pas trop mal sur github (faut aller voir sur la page du produit), tu devrais leur envoyer un lien vers ton firmware ça aiderai beaucoup de personnes :wink:

Encore bravo pour le travail accomplit, je suis sûr qu'il ya de longue heures derrière tout ça :grin:

Ca va pas être facile de partager mon code, car il faut passer par arduino, donc booloader (mais un bidouilleur peut le récupérer "pour pièces", certaines routines peuvent simplifier la vie). Y'a aussi qu'il n'y a pas beaucoup de commentaires, et un code sans commentaires, c'est pas facile à (ré)utiliser. J'attendrai d'avoir implémenté la gestion du port série (le port est démarré, mais il n'y a pas de code pour lire les entrées)

Pour les heures, la première idée est arrivée vers 2005, a évolué en pensant aux pics fin 2008, et me chatouille un peu tous les jours depuis que j'ai découvert Arduino, mai 2011... Je ne compte plus le nombre de feuilles que j'ai noircies à force de bouts de code et de schémas temporaires, un peu chaque jour, surtout le matin pendant le café-clop, c'est là que mon cerveau me pond tout ce qu'il a inventé pendant la nuit...

Aujourd'hui, je mets tout ça au propre, et à chaque solution technique trouvée, un peu de code s'ajoute à la future version finale (pour l'instant, le code du MEGA ne contient que la gestion de l'accélérateur avec sauvegardes en EEPROM de quelques variables).

Il y a surtout que j'ai 4 ATMEGA à programmer (2 LCD, 1 gestion signaux moteur et 1 maître calculateur...)

Super_Cinci:
Mécaniquement, la fuego est une bombe! super solide, surdimensionnée... mais tellement moche... Par contre, elle se rapproche très bien de la delorean...

[HUM]
La derniere fuego que j'ai vu en réel c'etait rue Pierre Demours Paris 17, il y a déjà maintenant quelques années, 8)
je ne sais pas ce qu'elle est devenue après.

http://video.google.com/videoplay?docid=2349599298801115250

C'est pas un poil dangereux le régulateur de vitesse ? je pense surtout en cas de défaillance électronique .... Enfin moi j'aurais pas confiance ^^

chicotore:
C'est pas un poil dangereux le régulateur de vitesse ? je pense surtout en cas de défaillance électronique .... Enfin moi j'aurais pas confiance ^^

Ca fait plus d'un an que je roule avec la version 1.0 (le UNO qui est déjà dessus), et jamais de soucis, que du bonheur.

Avec toute l'énergie qu'on perd à tout le temps faire attention à pas trop appuyer, maintenant, quand je roule 1 ou 2 heures en régulé, je sens bien l'agréable différence... et encore, la version que j'ai faite est assez limitée, il faudrait pouvoir réguler à la vitesse qu'on veut, car à 110, on se retrouve vite derrière quelqu'un qui roule à 109, et pour le dépasser, il faut désactiver le régulateur... Dans le prochain, on appuiera sur un bouton et ça régulera à la vitesse où on est. Ensuite, un bouton + et - pour ajuster au km/h près... Côté sécu, désactivation automatique dès qu'on touche une pédale (frein, embrayage, accélérateur, bouton d'arrêt d'urgence...) ou dès qu'on dépasse de 5km/h.

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!

Super_Cinci:
Exemple pour l'aiguille de vitesse, qui doit tourner sur 324°pour 0 à 180km/h ...

Je vois qu'il n'y'a pas que le tableau de bord qui est "tuné" dans cette voiture XD

Le code ci-dessus marche super, je n'ai pas encore testé les aiguilles à rayon de 40px, mais il me tarde de le faire!

Je vois que tu efface la ligne précédente avant de tracer la nouvelle.
Tu n'as pas de possibilité de travailler en double buffer ?

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};
...
v_index = (vitesse + 10) % 25;

2 remarques ici. Tu t'en rendras certainement compte tout seul mais comme les vacances sont terminées, je suis vénère d'être rentré alors j'ai envie de faire ch... tout le monde pour des trucs totalement puérils ]:smiley: (comme sur l'autoroute où je roule a 120 sur la voie de gauche quand y'a des grosses BMW derrière moi :grin:)

  • volatile est un mauvais choix ici. volatile s'utilise pour des variables qui peuvent être modifiées en dehors du court normal du programme, par exemple une variable globale utilisée entre une routine d'interruption et le corps du programme, pour éviter que le compilateur optimise l'accès en ne lisant qu'une fois la variable. Dans ton cas, les valeurs sont figées et donc c'est plutôt le mot clefs "const" que tu devrais utiliser.
  • l'index étant calculé %25, les valeurs possible sont de 0 à 24. Donc la taille du tableau devrait être a0_xy[25] (index de 0 à 24) au lieu de a0_xy[26] (index de 0 à 25) puis que l'index [25] ne sera jamais utilisé.

Tu peux aussi éviter le %25 qui implique une division entière ce qui coûte pas mal d'instructions (essaye de mesurer son exécution)
Puisque tu fais déjà une série de tests par rapport à 15, 40, .... dans chaque test tu peux calculer index comme une simple addition ou soustraction.

  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);

Les tracés multiples décalés de +/- 4 pixels c'est pour faire plus épais ?

A quand la vidéo ?

J'aime bien barbudor, car il soulève souvent des questions rigolotes ou utiles.

barbudor:

Super_Cinci:
Exemple pour l'aiguille de vitesse, qui doit tourner sur 324°pour 0 à 180km/h ...

Je vois qu'il n'y'a pas que le tableau de bord qui est "tuné" dans cette voiture XD

Alors pas du tout, j'ai repris le format du compteur d'origine, en calculant l'angle de l'aiguille sur 40 et 90km/h. J'ai pris l'habitude d'avoir l'aiguille à la verticale pour 90Km/h... le compteur d'origine est marqué jusqu'à 180, ce n'est pas pour rien, car j'ai déjà emmené l'aiguille jusque là (sur circuit, hein, parce que sur route, c'est pas vraiment autorisé :grin: ). On prend vite des habitudes et repères visuels, donc je garde le 90 à la verticale et le 0 à 20° en bas...

barbudor:

Le code ci-dessus marche super, je n'ai pas encore testé les aiguilles à rayon de 40px, mais il me tarde de le faire!

Je vois que tu efface la ligne précédente avant de tracer la nouvelle.
Tu n'as pas de possibilité de travailler en double buffer ?

Qu'entends tu par là? je vois pas trop de quoi tu parles... je me suis posé la question d'utiliser les 22 pages graphiques dispo dans le LCD lui-même, mais il faut de toute façon effacer les vieilles lignes un jour où l'autre...

barbudor:

  • volatile est un mauvais choix (...). Dans ton cas, les valeurs sont figées et donc c'est plutôt le mot clefs "const" que tu devrais utiliser.

Je n'ai pas osé définir un tableau de constantes, ne sachant pas comment le compilateur allait réagir. Si tu me dis que c'est mieux, alors je vais y penser. Le code actuel fait 6500 octets sur les 14300 dispos, donc si les tableaux de constantes vont dans la flash, ça m'intéresse! (il y a aussi les tables de caractères en const...) Je crois que les simples variables déclarées en const sont traduites à la compilation, non?

barbudor:

  • l'index étant calculé %25, les valeurs possible sont de 0 à 24. Donc la taille du tableau devrait être a0_xy[25] (index de 0 à 24) au lieu de a0_xy[26] (index de 0 à 25) puis que l'index [25] ne sera jamais utilisé.

Oui, et c'est une erreur de ma part. il faut que je recalcule ma série de coordonnées pour tomber sur pile 25 points. Mais de visu sur un sweep, l'aiguille ne semble pas sauter de point. je peux me contenter de virer les index N°25 pour gagner deux octets... :smiley:

barbudor:
Tu peux aussi éviter le %25 qui implique une division entière ce qui coûte pas mal d'instructions (essaye de mesurer son exécution)
Puisque tu fais déjà une série de tests par rapport à 15, 40, .... dans chaque test tu peux calculer index comme une simple addition ou soustraction.

ça, c'est pas con, merci!

barbudor:

  lcd_line(x0 - 4, y0 - 4, x00, y00, PUT);  // dessin de l'aiguille en 5 segments

Les tracés multiples décalés de +/- 4 pixels c'est pour faire plus épais ?

Oui, je n'ai pas trouvé comment dessiner une aiguille pleine qui tourne sans perdre de temps. Ca donne un rendu rigolo, on a l'impression que l'aiguille est en 3D et qu'elle tourne sur elle-même... (à défaut...) Pour les petites aiguilles (de 40px), j'ai mis +/-4 aussi, mais je vais descendre à +/-3 voire +/-2, mais ce n'est aussi qu'un détail.

barbudor:
A quand la vidéo?

Malheureusement, je n'ai plus de quoi filmer, et mon apn me sort des .MOV à 5Mo/s, et je n'arrive pas à les réencoder en avi ou mpeg (saloperie de format propriétaire tiens!) Mais dès que je peux, je m'y mets!

une photo en attendant?


les valeurs collées pour la photo : vitesse = 124, jauge haut (carburant 36.4L) = 173 et jauge bas (température eau 89.5°) = 179. les valeurs des petites jauges sont affichées au dessus ou en dessous de l'aiguille selon sa position, on voit même que je n'efface pas la virgule quand le texte passe de l'autre côté, mais ce n'est qu'un détail...

il y a un faux contact dans le potar de contraste (qui fait 2mm de diamètre...), faudra que je le change.

Côté animation, j'ai mis dans le loop() un sweep genre :

for (vitesse = 0; vitesse <= 180; vitesse--){
  vitesse_affiche();
  galva_value[0] = vitesse;
  galva_affiche(0);
  galva_value[1] = vitesse;
  galva_affiche(1);
  delay(125);
}

C'est vraiment fluide, et on n'est pas loin des 8 changements par seconde, donc mes codes doivent être assez rapide (je mesurerai à l'oscillo pour avoir une idée précise!)

La Renault 11 la plus moderne qui soit :grin:

Super_Cinci:
Je n'ai pas osé définir un tableau de constantes, ne sachant pas comment le compilateur allait réagir. Si tu me dis que c'est mieux, alors je vais y penser. Le code actuel fait 6500 octets sur les 14300 dispos, donc si les tableaux de constantes vont dans la flash, ça m'intéresse! (il y a aussi les tables de caractères en const...) Je crois que les simples variables déclarées en const sont traduites à la compilation, non?

Sur AVR avec avr-gcc le mot clé const n'entraîne pas le stockage des variables en flash. ça indique juste que tes valeurs sont constantes, en quelque sorte en lecture seule. Par contre il est effectivement possible de stocker les constantes en flash avec la directive PROGMEM : avr-libc: Data in Program Space

++

SesechXP:
La Renault 11 la plus moderne qui soit :grin:

Je ne fais que réinventer ce qui existe déjà : http://aebergon.perso.neuf.fr/Renault/page_Renault_11_Electronic_85.htm La Ronze-tronic, pour info, elle coûtait l'équivalent de 10 000€, aujourd'hui, la moindre voiture en haut de série, c'est 25 à 30000. Je doute qu'en 30 ans, l'inflation ait pris 150%... Mais ces vieilles caisses qui roulent encore (comme la mienne qui n'a "que" 25 ans) montrent qu'elles sont bien plus endurantes que celles d'aujourd'hui et ne coûtent rien en entretien si on sait un peu bricoler.

Il faut que je regarde comment ça marche, le progmem, mais j'ai peur que ça ralentisse beaucoup le code...

Super_Cinci:
J'aime bien barbudor, car il soulève souvent des questions rigolotes ou utiles.

Le code ci-dessus marche super, je n'ai pas encore testé les aiguilles à rayon de 40px, mais il me tarde de le faire!

Je vois que tu efface la ligne précédente avant de tracer la nouvelle.
Tu n'as pas de possibilité de travailler en double buffer ?

Qu'entends tu par là? je vois pas trop de quoi tu parles... je me suis posé la question d'utiliser les 22 pages graphiques dispo dans le LCD lui-même, mais il faut de toute façon effacer les vieilles lignes un jour où l'autre...

C'est exactement ca le principe.
En double (ou triple) buffer, on dessine dans une page mémoire qui n'est pas affichée puis on commute l'affichage brusquement sur la nouvelle page.
L'avantage c'est que tu ne vois pas le dessin se faire progressivement. Si par exemple dessiner tout ton panneau prend 300 ms, en simple buffer, l'utilisateur va voir le contenu se construire petit a petit ce qui ne donne pas forcément un super rendu dynamique.

Comme tu le notes, il y toujours le problème d'effacement. Mais dans beaucoup de cas, les systèmes d'affichages a plusieurs pages permettent souvent de faire des copies internes rapides entre des pages. Si cette fonction existe, tu peux avoir une des pages qui est dessinée qu'une seul fois au démarrage et qui contient le fond (par exemple, une bitmap dessinée sur PC et stockée sur une carte SD.
Au moment de faire un nouveau dessin, tu demande a l'écran de copier de manière interne l'image du fond sur une page libre non affichée, tu dessines par dessus tes nouveaux éléments, puis tu commutes instantanément l'affichage.

Je ne connais pas ton afficheur donc je ne sais pas si cette méthode est utilisable.

Je n'ai pas osé définir un tableau de constantes, ne sachant pas comment le compilateur allait réagir. Si tu me dis que c'est mieux, alors je vais y penser. Le code actuel fait 6500 octets sur les 14300 dispos, donc si les tableaux de constantes vont dans la flash, ça m'intéresse! (il y a aussi les tables de caractères en const...) Je crois que les simples variables déclarées en const sont traduites à la compilation, non?

Comme répondu par SesechXP, utiliser const ne va pas placer les données en Flash mais volatile empêche certaines optimisations.
Je ne dis pas que ca va transcender la vitesse de ton code mais c'est déjà mieux.
Pour placer les données en Flash, voir : PROGMEM - Arduino Reference puis poser plus de questions si nécessaire.
Note que cela va gagner un peu de RAM mais perdre du temps car la lecture d'une table en flash ne se fait pas de manière transparente.

C'est vraiment fluide, et on n'est pas loin des 8 changements par seconde, donc mes codes doivent être assez rapide (je mesurerai à l'oscillo pour avoir une idée précise!)

Good!

SesechXP:
La Renault 11 la plus moderne qui soit :grin:

Super_Cinci:
Je n'ai pas osé définir un tableau de constantes, ne sachant pas comment le compilateur allait réagir. Si tu me dis que c'est mieux, alors je vais y penser. Le code actuel fait 6500 octets sur les 14300 dispos, donc si les tableaux de constantes vont dans la flash, ça m'intéresse! (il y a aussi les tables de caractères en const...) Je crois que les simples variables déclarées en const sont traduites à la compilation, non?

Sur AVR avec avr-gcc le mot clé const n'entraîne pas le stockage des variables en flash. ça indique juste que tes valeurs sont constantes, en quelque sorte en lecture seule. Par contre il est effectivement possible de stocker les constantes en flash avec la directive PROGMEM : avr-libc: Data in Program Space

Dans les dernières version (nightly) de avr-gcc le fait de mettre une variables en const la stocke en flash.
Mais dans les version stable et/ou obsoléte qui sont fourni avec l'installateur arduino il faut utiliser PROGMEM pour déplacer une variable en flash.

"volatile" force le compilateur à ne pas optimiser la variable, c'est utile (et même obligatoire) dans le cas d'une variable globale partageait entre une fonction standard et une interruption.
"static" sur une variable globale informe le compilateur qu'il peut optimiser l'accès à cette variable en la rendant accesible uniquement dans le fichier .c/.cpp en cours.
"static" sur une variable locale la rend persistante (elle garde sa valeur au prochain appel de la fonction)
"static" sur une fonction la rend optimisable par le compilateur, en la rendant accessible uniquement dans le fichier .c/.cpp en cours.