Aller au contenu

Voltmètre 0 à 25 Vdc fait-maison, à base de microcontrôleur ATmega328P + écran lcd Nokia 5110 (projet éducatif)

Voltmètre ATmega328P écran LCD type Nokia 5110, projet électronique avec schéma et réalisation DIY, avec mesure de 0 à 25 volts VDC

Que diriez-vous de réaliser un voltmètre numérique, pour mesurer des tensions de 0 à 25 volts, en courant continu ? Et l’ensemble, piloté par un microcontrôleur ATmega328P (celui équipant les cartes Arduino Uno et Nano), avec affichage LCD compatible Nokia 5110. Ça vous dit ? Alors en avant !

Prérequis :
– savoir graver un bootloader sur un ATmega328P vierge (acheté neuf, donc)
– savoir téléverser un programme sur un ATmega328P via un convertisseur USB/TTL de type FTDI
– savoir piloter un module-écran Nokia 5110 via le bus SPI
– savoir écrire manuellement sur le bus SPI via la librairie SPI.h (native, sous Arduino IDE)

Niveau : intermédiaire

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

Comme d’habitude, les réalisations présentées ici le sont à but didactique (pour apprendre, donc). L’accent est donc mis sur le côté ludique, plutôt qu’autre chose (esthétique, optimisation, sécurisation, …). En clair : il s’agit là de vous montrer une façon de faire parmi tant d’autres, afin que vous puissiez vous en inspirer ! En espérant que tout ceci puisse vous servir, comme toujours 🙂

Aperçu et caractéristiques de ce projet de Voltmètre Numérique

Ce projet se présente sous la forme d’une carte électronique, alimentée par une pile 9V (format 6LR61), dotée de 2 borniers pour fiches bananes (sur lesquelles viendront se brancher des sondes de mesures de multimètre numérique, tout ce qu’il y a de plus « classique »).

En image, voici le « projet en action », si je puis dire (ici, pour la mesure de la tension d’une batterie au plomb 12V, par exemple) :

Mesure tension batterie au plomb 12V avec montage projet de voltmètre sans arduino, muni d'un microcontrôleur ATmega328P et afficheur LCD

Au niveau des caractéristiques de ce voltmètre, voici ce qu’on peut dire : cet appareil pourra lire toute tension continue (fixe) comprise entre 0 et 25 volts (ce qui exclut toute tension négative, ou variante dans le temps ou en amplitude).

L’affichage se met à jour 5 fois par seconde environ, et dispose d’un rétro-éclairage activable/désactivable manuellement.

Du reste, voici les éléments remarquables, sur le circuit imprimé de ce montage électronique :

Détail voltmètre numérique fait maison 25 volts de mesure en courant continu, doté d'un écran d'affichage LCD rétroéclairé, avec plans et schémas

Après cette vue d’ensemble, entrons un peu plus dans le détail, à présent 😉

Mais pourquoi ce voltmètre électronique fait-maison, au fait ?

Comme évoqué en intro, ce projet est surtout éducatif (pour apprendre l’électronique, donc). D’ailleurs, voici « tout » ce que nous allons voir, au travers ce voltmètre électronique fait-maison :

  • comment câbler/utiliser un microcontrôleur ATmega328P (le µC présent sur les cartes Arduino Uno et Nano, pour rappel) ; à noter que ce microcontrôleur devra avoir un bootloader gravé en lui (si ce n’est pas le cas, il vous suffit par exemple de suivre le tuto que j’avais fait à ce sujet, sur comment graver un bootloader sur une puce AT mega 328P)
  • comment téléverser un programme dans la mémoire flash de ce microcontrôleur, en se servant de l’IDE Arduino (même si nous n’utilisons pas de carte arduino ici !) ; à noter que nous utiliserons un convertisseur USB/TTL de type FTDI modèle FT232RL, ou équivalent, pour ce faire
  • comment piloter un écran compatible Nokia 5110 via le bus SPI, manuellement
  • comment envoyer des images personnalisées (entête, gros chiffres, …) sur cet écran LCD, à partir d’un fichier entête externe (.h) rattaché au programme principal arduino (.ino)
  • comment effectuer une conversion de tension dynamique 5V → 3,3V, au niveau des signaux transitant entre les sorties du microcontrôleur ATmega328P (+5V) et les entrées du module LCD compatible Nokia 5110 (+3V3), à l’aide du circuit intégré 74HC4050 (hexa-buffer)
  • comment effectuer des moyennes de mesures analogiques, dans le code arduino, pour plus de stabilité au niveau des mesures de ce voltmètre fait maison
  • et enfin, comment faire des calculs inverses au niveau d’un pont diviseur de tension, pour retrouver la tension mesurée 0-25Vdc en entrée de pont, en fonction de la tension présente en sortie de pont, présentée au niveau de l’entrée ADC 0-5Vdc du microcontrôleur

Comme vous l’aurez compris, il ne s’agissait pas là de faire un montage des plus simple ou épuré qui soit, mais bien un montage ludique, permettant d’apprendre l’électronique, par la pratique ! D’où … tout ce qui suit 😉

Cela étant étendu, voyons à présent le schéma électronique ce projet !

Schéma électronique

Tout d’abord, voici le schéma électronique de ce voltmètre 0-25 volts CC :

Schéma voltmètre ATmega328P sans carte arduino, affichage sur écran Nokia 5110 compatible, avec connecteur de programmation FTDI

Comme vous pouvez le constater, l’ensemble est divisé en 8 blocs, bien distincts :

  • l’alimentation en bas à gauche, permettant de fournir du +5V (grâce à U4) et du +3,3V (grâce à U5) à l’ensemble de notre montage, et ce, à partir d’une pile 9V
  • un microcontrôleur ATmega328P (U1) en haut au centre, véritable cœur de notre montage ; il dispose :
    • d’un oscillateur à quartz externe à 16 MHz (composants X1, C1, et C2)
    • d’un condensateur de stabilisation (C6) sur Aref (préconisation fabricant, pour améliorer les lectures analogiques faites par l’ADC, interne au µC)
    • d’une alimentation en +5V (préférée à une alimentation en +3,3V, afin d’avoir une meilleure précision sur les mesures de tension 0 à 25 volts de ce voltmètre)
  • un circuit de reset manuel en haut à gauche, composé d’une simple résistance pull-up (R1) et d’un bouton poussoir de mise à la masse manuel (BP1)
  • un bornier (CN1) pour le branchement d’un module FTDI type FT232RL ou équivalent ; il s’agit d’un convertisseur USB/TTL permettant la programmation de notre ATmega328P, avec :
    • un croisement des lignes RX/TX, entre le connecteur FTDI et le microcontrôleur (ce qui est typique dans le cas d’une communication UART, pour rappel)
    • un condensateur (C3) monté en série sur la ligne DTR, afin de n’émettre qu’une impulsion sur la ligne de RESET, juste avant la programmation
  • une led (LED1) au milieu du schéma, avec sa résistance de limitation de courant (R2), le tout connecté sur une broche particulière du microcontrôleur (permettant ainsi de s’assurer que le programme du µC « tourne » bien !)
  • un circuit de conversion de tension unidirectionnel 5V → 3,3V reposant sur la puce 74HC4050 (U2) en haut à droite ; ce circuit intégré (xx4050) est en fait simplement un ensemble de « 6 portes OUI » (un hexa-buffer au final, donc), qui délivre le même niveau en sortie, que celui présent en entrée (niveau haut → niveau haut, niveau bas → niveau bas) … mais avec une adaptation de tension au passage, si on l’alimente avec une tension différente de celle des signaux (ce qui est le cas ici !)
  • un afficheur LCD compatible Nokia 5110 (U3) en bas à droite, avec un interrupteur (SW2) permettant d’activer ou non le rétroéclairage de l’écran
  • et un pont diviseur de tension au centre à droite, matérialisé par les résistances R3 et R4, permettant d’abaisser la tension à mesurer (division par 5, ici), nous donnant ainsi du +5 volts sur l’entrée A0, lorsque la tension à mesurer V+ atteint +25 volts (ce qui est la limite de notre voltmètre, pour le coup)

Du reste, on retrouve quelques condensateurs de filtrage (C4, C-U1, C5, C-U2, C-U3), permettant de stabiliser la tension, en plusieurs points du montage.

Liste des composants utilisés dans ce projet

Dans le cadre de ce projet de voltmètre électronique à base d’ATmega328, voici les composants mis en œuvre :

QtéDésignationLien achat
2Résistance de 10 kΩ (1/4 watt, 1% de tolérance)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Résistance de 30 kΩ (1/4 watt, 1% de tolérance)(idem)
1Résistance de 7,5 kΩ (1/4 watt, 1% de tolérance)(idem)
1Condensateur de 47 µF (16 volts, minimum)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Condensateur de 10 µF (10 volts, minimum)(idem)
5Condensateur de 100 nFCaddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Condensateur céramique de 22 pFCaddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Quartz de 16 MHz (modèle HC-49S)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Diode 1N4001 (ou équivalent)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Bouton poussoir 12 x 12 x 7,3 à 4 broches (reset µC)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Interrupteur à glissière type SS12D10 (rétroéclairage lcd)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Interrupteur à poussoir 8.5 autobloquant, à 6 broches (on/off montage)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Support de pile 9V à souder, sur circuit imprimé (modèle « With Pin », pour qu’il soit soudable sur PCB)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Pile 9V format 6LR61Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Régulateur de tension 7805, en boîtier TO220Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Régulateur de tension AMS1117-3V3, pour montage en surfaceCaddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Led Ø5 mm de couleur verte (témoin de « bon fonctionnement programme »)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Microcontrôleur ATmega328P, version DIP 28 brochesCaddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Support de circuit intégré DIP à 28 broches, format étroit (« narrow »)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Circuit intégré 74HC4050, version DIP 16 brochesCaddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Support de circuit intégré DIP à 16 broches (à contacts tulipes, de préférence)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Borne à souder pour fiche banane (une rouge, et l’autre noire)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Module d’affichage compatible Nokia 5110Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Rangée de 8 headers mâles, au pas de 2,54mm (à souder sur afficheur Nokia 5110, si non équipé de base)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
2Rangée de 8 header femelle, au pas de 2,54mm (à souder sur le circuit imprimé de notre montage, pour supporter le lcd Nokia 5110)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Rangée de 6 header femelle, au pas de 2,54mm (pour pouvoir y connecter la carte FTDI dessus, pour la programmation)(idem)
1Ensemble d’entretoises nylon de taille M3 (pour surélever le circuit imprimé PCB, au besoin)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Ensemble d’entretoises nylon de taille M2 (pour fixer le support de pile 9V)Caddie plein 24x24, icone passion électronique fr, achat de matériels d'élec, idéal débutant et amateurs d'électronique
1Circuit imprimé PCB (voir le fichier Gerber au format ZIP, tout en bas de cet article, si vous souhaitez reproduire ce circuit imprimé à l’identique)

Et pour la programmation, à proprement parler :

Voilà pour la partie matérielle ! À présent, voyons la partie logicielle 😉

Un mot sur l’écran Nokia 5110 utilisé ici

Avant de vous présenter le code de programmation en lui-même, il y a juste un mot que j’aimerai vous dire, au sujet de l’afficheur LCD de ce voltmètre.

En fait, l’affichage de la tension mesurée par ce voltmètre se fera sur un écran LCD graphique, compatible Nokia 5110 (je vous mets le lien du tuto que j’avais fait dessus, si besoin). Celui-ci dispose d’une surface d’affichage de 84 pixels de large sur 48 pixels de haut (en mode « paysage »).

Voici d’ailleurs ce que notre voltmètre affichera sur l’écran LCD, une fois en service (avec « 88.88 » remplacé par la tension mesurée, bien évidemment !) :

Écran d'affichage voltmètre DIY 0-25Vdc faisant 84x48 pixels, avec détail de chaque bit sur l'afficheur, au niveau des chiffres et images lcd

Pour bien comprendre ce qui suit, et comment j’ai construit le programme arduino faisant tourner ce voltmètre, dites-vous que tous les éléments affichés sont des images. Ainsi :

  • la bannière du haut (indiquant « voltmètre ») est une image
  • les chiffres (allant de 0 à 9) sont des images
  • le point séparateur de chiffres est une image
  • et la mention « Vdc », tout en bas, est une image

Ainsi, nous ne ferons appel à aucune librairie spécifique, ce qui vous montrera une autre façon d’utiliser un écran Nokia 5110 (sans bibliothèque aucune, que ce soit pour envoyer ces images, tout comme assurer la communication entre notre microcontrôleur et cet écran).

Par contre, il y a un point technique à voir ensemble, et qui à trait au stockage de l’état des pixels dans la mémoire interne de l’écran LCD (car oui, il y a un stockage intermédiaire/tampon, où sont renseignés l’état de tous les pixels). Concrètement, cette mémoire RAM tampon fait 504 octets (soit 4032 bits), qui correspondent bien aux 4032 pixels à afficher (84 x 48 pixels de taille d’écran nous donnant bien 4032 pixels).

Comme la mémoire est organisée en octets adressables, et non « bit à bit », vous comprendrez sûrement qu’il ne va pas être facile de cibler un pixel en particulier, à l’écran. En effet, si nous devons par exemple modifier l’état d’un pixel aux coordonnées X/Y, il faudra tout d’abord déterminer dans quel octet se trouve ce pixel, avant de modifier le bit concerné.

Vous êtes perdu ? Alors passons à quelque chose de moins abstrait, et plus visuel ! Voici l’écran d’affichage du Nokia 5110, et le « calque » de sa représentation mémoire à l’écran (le « 1er » octet étant représenté dans le rectangle rouge, en haut à gauche) :

Répartition lignes et colonnes écran Nokia 5110 lcd, stockage 8 bits interne sur six lignes de huit pixels, mapping RAM pour affichage voltmètre diy

En fait, on peut dire que l’adressage des colonnes correspond bien, mais que l’adressage des lignes se fait sous forme d’octets, et non « bit à bit » (6 lignes pour 48 pixels).

Si je vous parle de tout cela, ce n’est pas pour vous ennuyer ! C’est simplement pour vous expliquer pourquoi les images seront renseignées sous forme d’octets (paquets de 8 bits, représentant 8 pixels), au niveau du fichier « images.h » accompagnant le programme principal arduino. Au passage, voici comment seront encodées chaque image visuellement (entête, chiffres, point/séparateur de chiffres, ou mention Vdc), pixel par pixel :

Images et chiffres créés PSE et personnalisés pour afficheur LCD Nokia 5110, projet de voltmètre numérique fait maison, avec schémas

Ce qui nous donne par exemple le code suivant, pour le chiffre 9 (un 0 = pixel éteint ; un 1 = pixel allumé) :

const byte IMAGE_CHIFFRE_9[] PROGMEM = {
  0b00010000, 0b00000000, 0b00000000,   // 1ère colonne de pixels de ce chiffre (octet du bas, du milieu, puis du haut => 3 x 8 bits = 24 pixels de haut)
  0b00110000, 0b00000000, 0b00000000,   // 2ème colonne de pixels de ce chiffre
  0b00110000, 0b00000111, 0b10000000,   // 3ème colonne de pixels de ce chiffre
  0b00110000, 0b00001111, 0b11111000,   // 4ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b01111100,   // 5ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 6ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 7ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 8ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 9ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 10ème colonne de pixels de ce chiffre
  0b00110000, 0b00011000, 0b00001100,   // 11ème colonne de pixels de ce chiffre
  0b00111110, 0b00011000, 0b00001100,   // 12ème colonne de pixels de ce chiffre
  0b00011111, 0b11111000, 0b00001100,   // 13ème colonne de pixels de ce chiffre
  0b00000001, 0b11101111, 0b10001100,   // 14ème colonne de pixels de ce chiffre
  0b00000000, 0b00000111, 0b11111100,   // 15ème colonne de pixels de ce chiffre
  0b00000000, 0b00000000, 0b01111000    // 16ème colonne de pixels de ce chiffre
};

Si vous arrivez à bien comprendre comment sont encodés chaque élément, alors le programme qui suit vous semblera bien plus simple à comprendre ! Sinon, ce n’est pas grave, dans l’immédiat 😉

Nota : j’ai dessiné tous ces éléments/chiffres à la main, avant de les encoder dans un fichier image (comme le code du chiffre 9, présenté ci-dessus). Cela a été un peu long et fastidieux, je dois bien l’avouer, mais une fois fait … c’est fait ! En fait, si j’ai procédé ainsi, c’est avant tout pour vous montrer une façon de faire, visant à occuper le moins de place mémoire possible, dans l’ATmega328P ; ce qui laissera un maximum de place pour le programme principal, ensuite, dans le microcontrôleur !

Code programme (sous Arduino IDE)

Bien que nous n’utilisons pas de carte Arduino ici, nous pouvons tout de même utiliser l’IDE Arduino pour écrire du code, et programmer notre ATmega328P comme s’il s’agissait d’une carte arduino. En fait, ceci est possible à partir du moment où on utilise un ATmega328P disposant d’un bootloader, et qu’un convertisseur USB/TTL (FTDI, par exemple) permet le transfert de données entre les deux.

Ici, je vous préconise de graver un bootloader de type « optiboot », ce qui vous permettra de « faire croire » à l’IDE Arduino que votre ATmega328P est en fait une carte Arduino Uno. Si vous ne savez pas comment vous y prendre pour réaliser cela, je vous renvois tout simplement vers le tuto détaillant la gravure d’un bootloader sur un ATmega 328P que j’avais fait, il y a peu ; car c’est indispensable ici, pour suivre cet article !

Du reste, voici le programme principal, permettant de donner vie à ce multimètre ATmega328P fait-maison :

/*
   ______               _                  _///_ _           _                   _
  /   _  \             (_)                |  ___| |         | |                 (_)
  |  [_|  |__  ___  ___ _  ___  _ __      | |__ | | ___  ___| |_ _ __ ___  _ __  _  ___  _   _  ___
  |   ___/ _ \| __|| __| |/ _ \| '_ \_____|  __|| |/ _ \/  _|  _| '__/   \| '_ \| |/   \| | | |/ _ \
  |  |  | ( ) |__ ||__ | | ( ) | | | |____| |__ | |  __/| (_| |_| | | (_) | | | | | (_) | |_| |  __/
  \__|   \__,_|___||___|_|\___/|_| [_|    \____/|_|\___|\____\__\_|  \___/|_| |_|_|\__  |\__,_|\___|
                                                                                      | |
                                                                                      \_|
  Fichier :       prgATmega328P-Voltmetre25VdcATMEGA328P.ino
  
  Description :   Programme permettant de réaliser un voltmètre à base d'ATmega328P,
                  avec affichage sur écran compatible Nokia 5510
                  
  Remarques :     - l'ATmega328P mis en oeuvre devra comporter un bootloader, de type "optiboot" (comme un Arduino Uno, en fait)
                    (lien vers article PSE à venir)
                  - là on va piloter l'ATmega328 comme s'il s'agissait d'un Arduino Uno, c'est pourquoi les entrées/sorties seront notées A0..A5 et D0..D13
                                    
  Auteur :        Jérôme TOMSKI (https://passionelectronique.fr/)
  Créé le :       30.12.2023

*/

// Inclusion des images qui seront affichées à l'écran (chiffres, bloc entête, et mention Vdc)
#include "images.h"

// Inclusion de la librairie SPI (native, sous Arduino IDE, donc pas besoin de l'importer/installer)
#include <SPI.h>

// Définition des broches de raccordement ATmega328P → convertisseur de tension 5V/3,3V → écran Nokia
// Nota : là on se sert des alias d'entrées/sorties Dxx, comme si nous étions sur un Arduino Uno
#define sortieD3_ATmega328P_vers_brocheLIGHT_ecranNokia       3              // Physiquement, la sortie D3 correspond à la broche 5 de l'ATmega328P
#define sortieD13_SCK_ATmega328P_vers_brocheCLK_ecranNokia    13             // Physiquement, la sortie D13 correspond à la broche 19 de l'ATmega328P
#define sortieD11_MOSI_ATmega328P_vers_brocheDIN_ecranNokia   11             // Physiquement, la sortie D11 correspond à la broche 17 de l'ATmega328P
#define sortieD6_ATmega328P_vers_brocheDC_ecranNokia          6              // Physiquement, la sortie D6 correspond à la broche 12 de l'ATmega328P
#define sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia      10             // Physiquement, la sortie D10 correspond à la broche 16 de l'ATmega328P
#define sortieD8_ATmega328P_vers_brocheRST_ecranNokia         8              // Physiquement, la sortie D8 correspond à la broche 14 de l'ATmega328P

// Définitions des autres broches utilisées sur l'ATmega328P
#define sortieD7_ATmega328P_vers_LED_temoin_sur_pcb           7              // Physiquement, la sortie D7 correspond à la broche 13 de l'ATmega328P
#define entreeA0_ATmega328P_lecture_tension                   A0             // Physiquement, la sortie A0 correspond à la broche 23 de l'ATmega328P


// Autres paramètres de ce programme
#define nbreDeLecturesAfaireSurA0       100
#define valeurResistanceR3DansMontage   30000.0     // La résistance R3 de notre montage fait 30 kohms
#define valeurResistanceR4DansMontage   7500.0      // La résistance R4 de notre montage fait 7,5 kohms


// ========================
// Initialisation programme
// ========================
void setup() {
  
  // Initialisation de la liaison série (PC <-> ATmega328P, au travers du FTDI), pour le débuggage, si besoin
  Serial.begin(9600);
  Serial.println(F("================="));
  Serial.println(F("Voltmètre 0-25Vdc"));
  Serial.println(F("================="));
  Serial.println("");

  // Définition des sorties de l'ATmega328P
  pinMode(sortieD3_ATmega328P_vers_brocheLIGHT_ecranNokia, OUTPUT);
  pinMode(sortieD13_SCK_ATmega328P_vers_brocheCLK_ecranNokia, OUTPUT);
  pinMode(sortieD11_MOSI_ATmega328P_vers_brocheDIN_ecranNokia, OUTPUT);
  pinMode(sortieD6_ATmega328P_vers_brocheDC_ecranNokia, OUTPUT);
  pinMode(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, OUTPUT);
  pinMode(sortieD8_ATmega328P_vers_brocheRST_ecranNokia, OUTPUT);
  pinMode(sortieD7_ATmega328P_vers_LED_temoin_sur_pcb, OUTPUT);

  // Définition des entrées de l'ATmega328P (inutile dans l'absolu, car les ports d'E/S sont configurés en "entrée", par défaut ; mais bon, là c'est juste pour la "bonne forme" !)
  pinMode(entreeA0_ATmega328P_lecture_tension, INPUT);

  // Mise à l'état par défaut de certaines des broches de sortie de l'ATmega328P
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, LOW);      // Ligne CE du Nokia5110 = LOW, pour désactiver le module
  digitalWrite(sortieD8_ATmega328P_vers_brocheRST_ecranNokia, HIGH);        // Ligne RST du Nokia5110 = HIGH, pour désactiver le reset
  digitalWrite(sortieD3_ATmega328P_vers_brocheLIGHT_ecranNokia, LOW);       // Ligne LIGHT du Nokia5110 = LOW, pour allumer le rétroéclairage
  digitalWrite(sortieD7_ATmega328P_vers_LED_temoin_sur_pcb, HIGH);          // Allumage de la LED "témoin de bon fonctionnement" du montage (indique que le programme a bien démarré)
  
  // Initialisation du bus SPI
  SPI.begin();                            // Initialise la librairie SPI
  SPI.setClockDivider(SPI_CLOCK_DIV4);    // On divise l'horloge 16 MHz du µC par 4, pour fonctionner à 4 MHz (ce qui est la vitesse maxi, pour l'écran nokia 5110)

  // Reset du module Nokia 5110 (via ligne RST, active à l'état bas)
  digitalWrite(sortieD8_ATmega328P_vers_brocheRST_ecranNokia, LOW);
  delay(100);
  digitalWrite(sortieD8_ATmega328P_vers_brocheRST_ecranNokia, HIGH);
  delay(100);
  
  // Initialisation de l'écran Nokia 5110
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, LOW);    // Sélection de l'écran (ligne "slave select" SPI de l'ATmega328P → ligne CE de l'écran)
  envoiUneCommandeAuNokia5510(0b00100001);    // [Function set] => PD(power-down)=0, V(vertical-adressing)=0, et H=1 (H à 1 permet d'avoir accès aux commandes "étendues" de l'écran LCD)
  envoiUneCommandeAuNokia5510(0b10111000);    // [Set LCD Vop] => bits 6 à 0 donnent une valeur en 0 et 127  ; ici, 56 (x011 1000) de "contraste" est sélectionné
  envoiUneCommandeAuNokia5510(0b00010100);    // [Bias system] => bits 2, 1, et 0 donnent une valeur en 0 et 7  ; ici, 4 (xxxx x100) de "bias" est sélectionné
  envoiUneCommandeAuNokia5510(0b00100000);    // [Function set] => PD(power-down)=0, V(vertical-adressing)=0, et H=0 (retour aux commandes "normales" de l'écran LCD)
  envoiUneCommandeAuNokia5510(0b00001100);    // [Display control] => D=1, 0, E=0 (DE=10 signifie un fonctionnement en "Normal mode")
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, HIGH);   // Déselection de l'afficheur LCD

  // Petite pause, avant de passer à la suite
  delay(100);

  // Mise en place des "élements fixes, sur l'écran LCD"
  effaceLecran();
  affichageBanniereEnHaut();
  affichagePointAuMilieu();
  affichageMentionVdcEnBas();

  // Nouvelle petite pause, avant de passer à la boucle LOOP
  delay(100);

}


// =================
// Boucle principale
// =================
void loop() {

  // ****************************************************************************************************************************************
  // Effectue plusieurs lectures de l'entrée A0, puis en fait la moyenne (pour avoir une valeur qui varie lentement, notamment à l'affichage)
  // ****************************************************************************************************************************************
  // Nota : A0 retourne une valeur entre 0 et 1023, puisque l'ADC de l'ATmega328P sur ces entrées analogiques fait 10 bits
  long sommeDesValeursLues = 0;
  for(int i=0; i<nbreDeLecturesAfaireSurA0; i++) {
    sommeDesValeursLues = sommeDesValeursLues + (long)analogRead(entreeA0_ATmega328P_lecture_tension);
  }
  int moyenneValeurA0 = sommeDesValeursLues / nbreDeLecturesAfaireSurA0;


  // *******************************************************************************************************************************
  // Calcul la tension mesurée, en fonction de la valeur moyenne lue sur A0, et du pont diviseur résistif présent dans notre montage
  // *******************************************************************************************************************************
  float tensionMoyenneSurA0 = (float)moyenneValeurA0 * 5.0 / 1023.0;
          // 5 correspond aux +5V de référence de l'ATmega328P (son alim), et 1023 à la résolution de lecture des entrées analogiques (10 bits)
  float tensionMesureeSurMontage = tensionMoyenneSurA0 * (valeurResistanceR3DansMontage + valeurResistanceR4DansMontage) / valeurResistanceR4DansMontage;
          // Nota : il s'agit en fait de la formule du pont diviseur de tension, mais inversée (pour trouver la valeur d'entrée, en fonction de la sortie)

  // Pour débug, si nécessaire :
  // Serial.print("tensionMoyenneSurA0 = "); Serial.print(tensionMoyenneSurA0); Serial.println(" volts");
  // Serial.print("tensionMesureeSurMontage = "); Serial.print(tensionMesureeSurMontage); Serial.println(" volts");
  
  // ****************************************************************************
  // Affichage de la tension d'entrée calculée, sur l'écran compatible Nokia 5110
  // ****************************************************************************
  // Décomposition du nombre, deux chiffres avant et après la virgule (on multiplira par 100 et enlèvera ce qui est après la virgule, pour simplifier les choses)
  byte quatreChiffresAafficher[4];
  sprintf(quatreChiffresAafficher, "%04d", (int)(tensionMesureeSurMontage * 100));
  
  affichageChiffreAunePositionDonnee(1, quatreChiffresAafficher[0]-48);     // -48, parce que le caractère ASCII du chiffre 0 vaut "48" (donc il faut décaler d'autant ici)
  affichageChiffreAunePositionDonnee(2, quatreChiffresAafficher[1]-48);
  affichageChiffreAunePositionDonnee(3, quatreChiffresAafficher[2]-48);
  affichageChiffreAunePositionDonnee(4, quatreChiffresAafficher[3]-48);
  

  // *********************************************************************************************************
  // Puis rebouclage, après une petite pause (pour ne pas faire varier l'affichage trop rapidement non plus !)
  // *********************************************************************************************************
  delay(200);
  
}




// ======================================
// Fonction : envoiUneCommandeAuNokia5510
// ======================================
// Permet d'envoyer un ordre (instruction) à l'afficheur LCD, pour qu'il l'exécute (par exemple : positionner curseur à tel ou tel endroit, régler contraste, ...)
void envoiUneCommandeAuNokia5510(byte commande) {
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, LOW);  // Activation de l'écran LCD (en mettant sa ligne CE à l'état bas)
  digitalWrite(sortieD6_ATmega328P_vers_brocheDC_ecranNokia, LOW);      // Passage en mode "commande" de l'écran LCD (ligne DC à 0)
  SPI.transfer(commande);                                               // Envoi des 8 bits de commande
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, HIGH); // Désélection de l'écran Nokia 5110, en ramenant sa ligne /SS à l'état haut
}


// =====================================
// Fonction : envoiDesDonneesAuNokia5510
// =====================================
// Permet d'envoyer des données à l'afficheur LCD (les pixels à afficher à l'écran, en fait)
void envoiDesDonneesAuNokia5510(byte donnees) { // Send data to display
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, LOW);  // Activation de l'écran LCD (en mettant sa ligne CE à l'état bas)
  digitalWrite(sortieD6_ATmega328P_vers_brocheDC_ecranNokia, HIGH);     // Passage en mode "données" de l'écran LCD (ligne DC à 1)
  SPI.transfer(donnees);                                                // Envoi des 8 bits de commande
  digitalWrite(sortieD10_SS_ATmega328P_vers_brocheCE_ecranNokia, HIGH); // Désélection de l'écran Nokia 5110, en ramenant sa ligne /SS à l'état haut
}


// ==============================
// Fonction : positionneLeCurseur
// ==============================
// Permet de positionner le curseur à la position souhaité
// (en sachant qu'on va de 1 en 1 sur l'axe X, et de 8 en 8 sur l'axe Y)
void positionneLeCurseur(byte Xpos, byte Ypos) {

  // Avec
  //   - Xpos : valeur entre 0 et 83, sur l'axe horizontal (on va de 1 en 1 pixel sur l'axe X)
  //   - Ypos : valeur entre 0 et 5, sur l'axe vertical (on va de 8 en 8 pixels sur l'axe Y)
  //
  //               REMARQUE IMPORTANTE:
  //                   L'axe Y de l'écran fait 48 pixels de haut (ce qui occupe donc 48 bits d'espace mémoire, au sein de l'écran).
  //                   Par contre, l'écran Nokia 5110 gère sa mémoire sous forme "d'octets" et non de "bits", sur l'axe Y. Ainsi,
  //                   ces 48 bits seront répartis sur 6 octets, ce qui nous donne bien 6x8 = 48 pixels. Cela explique pourquoi ici
  //                   la position_Y va de 0 à 5 (octets) dans ce cas, et non de 0 à 47 (bits).
    
  envoiUneCommandeAuNokia5510(0b10000000 + Xpos);                       // Saut à la position horizontale "Xpos" (exprimée en "pixels", pour ainsi dire)
  envoiUneCommandeAuNokia5510(0b01000000 + Ypos);                       // Saut à la position verticale "Ypos" (exprimée en "numéro de ligne de 8 pixels", en quelque sorte)

}


// =======================
// Fonction : effaceLecran
// =======================
// Permet d'effacer tous les pixels de l'écran (indispensable au démarrage, car l'écran Nokia 5110 peut afficher des pixels "allumés" par ci, par là !)
void effaceLecran() {

  // On se place "en haut/à gauche" de l'écran
  byte colonneX = 0;      // De 0 à 83, représentant nos 84 pixels de large, sur l'écran
  byte ligneY = 0;        // De 0 à 5, représentant nos 6 lignes de 8 pixels de haut, sur l'écran
  positionneLeCurseur(colonneX, ligneY);

  // Puis on efface les 504 octets de mémoire de l'afficheur LCD
  // Nota : l'écran faisant 84 pixels de large, sur 6 paquets de 8 pixels de haut, cela nous donne bien 84x6 soit 504 octets !
  for(int i=0; i < 504; i++) {
    envoiDesDonneesAuNokia5510(0x00);                                   // Mise à 0 préalable de tous les pixels de l'écran
  }

}


// ==================================
// Fonction : affichageBanniereEnHaut
// ==================================
void affichageBanniereEnHaut() {

  // On se place "en haut/à gauche" de l'écran
  byte colonneX = 0;      // De 0 à 83, représentant nos 84 pixels de large, sur l'écran
  byte ligneY = 0;        // De 0 à 5, représentant nos 6 lignes de 8 pixels de haut, sur l'écran
  positionneLeCurseur(colonneX, ligneY);

  // *********************************
  // Envoi de l'image "bannière haute"
  // *********************************
  // Nota : cette image fait :
  //   - 84 pixels de large (envoyés 1 par 1)
  //   - 16 pixels de haut (envoyés 8 par 8, donc répartis sur 2 x 8 bits, d'où les 2 envois séparés ci-dessous)
  for(byte offset=0; offset<84; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(IMAGE_ENTETE + (2*offset+1)));     // 8 bits "supérieurs" de notre image, sur 84 pixels de large
  }
  for(byte offset=0; offset<84; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(IMAGE_ENTETE + (2*offset)));       // 8 bits "inférieurs" de notre image, sur 84 pixels de large
  }

}


// =================================
// Fonction : affichagePointAuMilieu
// =================================
void affichagePointAuMilieu() {

  // On se positionne à l'écran
  byte colonneX = 41;      // De 0 à 83, représentant nos 84 pixels de large, sur l'écran
  byte ligneY = 4;        // De 0 à 5, représentant nos 6 lignes de 8 pixels de haut, sur l'écran
  positionneLeCurseur(colonneX, ligneY);

  // *******************************
  // Envoi de l'image "point milieu"
  // *******************************
  // Nota : cette image fait :
  //   - 2 pixels de large (envoyés 1 par 1)
  //   - 8 pixels de haut (envoyés 8 par 8, donc répartis sur 1 x 8 bits, d'où un seul envoi ci-dessous)
  for(byte offset=0; offset<2; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(IMAGE_POINT_SEPARATEUR + offset));
  }

}


// ===================================
// Fonction : affichageMentionVdcEnBas
// ===================================
void affichageMentionVdcEnBas() {

  // On se positionne à l'écran
  byte colonneX = 67;      // De 0 à 83, représentant nos 84 pixels de large, sur l'écran
  byte ligneY = 5;        // De 0 à 5, représentant nos 6 lignes de 8 pixels de haut, sur l'écran
  positionneLeCurseur(colonneX, ligneY);

  // *******************************
  // Envoi de l'image "mention Vdc"
  // *******************************
  // Nota : cette image fait :
  //   - 15 pixels de large (envoyés 1 par 1)
  //   - 8 pixels de haut (envoyés 8 par 8, donc répartis sur 1 x 8 bits, d'où un seul envoi ci-dessous)
  for(byte offset=0; offset<15; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(IMAGE_MENTION_VDC + offset));
  }

}

// =============================================
// Fonction : affichageChiffreAunePositionDonnee
// =============================================
void affichageChiffreAunePositionDonnee(byte position1a4, byte valeurAafficher) {

  // Déclaration des variables de positionnement
  byte colonneX;          // De 0 à 83, représentant nos 84 pixels de large, sur l'écran
  byte ligneY;            // De 0 à 5, représentant nos 6 lignes de 8 pixels de haut, sur l'écran

  // Détermination de la position sur l'axe horizontal (colonneX)
  switch(position1a4) {
    case 1:
      colonneX = 5;       // Le 1er chiffre commence à la 6ème colonne (index #5)
      break;
    case 2:
      colonneX = 23;      // Le 2ème chiffre commence à la 24ème colonne (index #23)
      break;
    case 3:
      colonneX = 45;      // Le 3ème chiffre commence à la 46ème colonne (index #45)
      break;
    case 4:
      colonneX = 63;      // Le 4ème chiffre commence à la 64ème colonne (index #63)
      break;
    default:
      break;
  }

  // Détermination du chiffre à envoyer
  byte* pointeurVersChiffreAenvoyer;
  switch(valeurAafficher) {
    case 0:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_0;
      break;
    case 1:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_1;
      break;
    case 2:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_2;
      break;
    case 3:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_3;
      break;
    case 4:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_4;
      break;
    case 5:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_5;
      break;
    case 6:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_6;
      break;
    case 7:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_7;
      break;
    case 8:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_8;
      break;
    case 9:
      pointeurVersChiffreAenvoyer = IMAGE_CHIFFRE_9;
      break;
    default:
      break;
  }

  // ****************************************************************************************************************************************
  // Nota : chaque chiffre fait 16 pixels de large, sur 24 pixels de haut (soit 24 bits, soit 3 octets, d'où les 3 envois séparés ci-dessous)
  // ****************************************************************************************************************************************

  // Envoi du haut de l'image (les "3èmes octets" du chiffre), sur la ligne 2 de l'écran (sur l'axe vertical, j'entends)
  ligneY = 2;
  positionneLeCurseur(colonneX, ligneY);
  for(byte offset=0; offset<16; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(pointeurVersChiffreAenvoyer + (3*offset+2)));
  }
  
  // Envoi du milieu de l'image (les "2èmes octets" du chiffre), sur la ligne 3 de l'écran (sur l'axe vertical, j'entends)
  ligneY = 3;
  positionneLeCurseur(colonneX, ligneY);
  for(byte offset=0; offset<16; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(pointeurVersChiffreAenvoyer + (3*offset+1)));
  }

  // Envoi du bas de l'image (les "1er octets" du chiffre), sur la ligne 4 de l'écran (sur l'axe vertical, j'entends)
  ligneY = 4;
  positionneLeCurseur(colonneX, ligneY);
  for(byte offset=0; offset<16; offset++) {
    envoiDesDonneesAuNokia5510(pgm_read_byte_near(pointeurVersChiffreAenvoyer + (3*offset+0)));
  }

}

Nota : ici, je ne vous ai pas partagé le contenu du fichier « image.h », car celui-ci fait plus de 300 lignes ! Vous le trouverez tout simplement en téléchargement libre et gratuit, sur GitHub, en cliquant sur le lien dédié, tout en bas de cet article !

Alors, pour l’heure, commençons par analyser ce code (nous verrons la partie « téléversement du programme » plus loin, car il faudra utiliser un FTDI).

Globalement, ce code est divisé en blocs, puis en sous-blocs. On retrouve ainsi :

  • des déclarations concernant l’assignation des broches, et les paramètres de l’application
  • la fonction SETUP, classique dans tout programme arduino, qui nous permettra :
    • d’initialiser ces broches
    • d’initialiser l’écran LCD
    • et d’envoyer à l’écran les parties invariantes (images fixes), à savoir : l’entête, le point séparateur de chiffre, et la mention « Vdc » tout en bas
  • la fonction LOOP, classique là aussi, qui contient ce sur quoi notre microcontrôleur va boucler

Au niveau de la fonction LOOP, on retrouve :

  • une lecture de l’entrée analogique A0, répété un certain nombre de fois (cela nous permettra d’avoir une lecture moyenne, bien plus « stable » qu’une simple mesure isolée)
  • une conversion de cette entrée analogique A0 moyennée de 10 bits (valeur entre 0 et 1023) vers une tension comprise entre 0 et 5 volts (pour déterminer quelle tension est « réellement » présente sur l’entrée A0)
  • une conversion de cette tension A0 (0 à 5V) vers une tension comprise entre 0 et 25 volts, indiquant la tension effectivement présente sur l’entrée de notre voltmètre (notre fameuse « tension à mesurer »)
  • une segmentation de ce nombre (tension entre 0 et 25 volts) sur 4 chiffres séparés (2 chiffres avant et après la virgule)
  • 4 appels successifs à une fonction nommée « affichageChiffreAunePositionDonnee », permettant l’affichage de ces chiffres, un après l’autre
  • et un délai de pause entre chaque rebouclage (200 ms, par défaut)

Au niveau de la fonction d’affichage de chiffre (fonction « affichageChiffreAunePositionDonnee »), on retrouve :

  • un calcul de position ligne/colonne (c’est pour ça que je vous avais « longuement » détaillé « l’agencement mémoire » de l’écran Nokia 5110, dans le paragraphe précédent)
  • un pointeur de sélection du chiffre à afficher, à la position calculée
  • un envoi réparti en 3 salves, car il y a 3 octets de données par chiffre (celui-ci faisant 8 x 3 = 24 pixels de haut)

Du reste, je vous passe les détails concernant les registres internes de l’écran compatible Nokia 5110, pour accéder à chaque paramètre et l’envoi de données. Sinon, vous retrouverez tout ça à la page 14/32 du datasheet du PCD 8544.

Nota 1 : on aurait bien évidemment pu faire un programme plus simple, notamment au niveau de l’affichage LCD, à l’aide de la librairie PCD8544 d’Adafruit. Mais là encore, je tenais à vous montrer une autre façon de faire, que celle présentée dans le tuto sur l’écran Nokia 5110 ; c’est donc plus technique ici, mais plus léger en mémoire, tout en offrant un meilleur contrôle des actions !

Nota 2 : concernant l’envoi des données via le bus SPI, on aurait là également pu faire autrement, en choisissant d’autres broches du microcontrôleur ATmega328P, et en utilisant la fonction shiftOut(), par exemple. En fait, encore une fois, je ne fais que vous montrer plusieurs façons différentes de faire, au fil des articles ; à vous de choisir celle qui vous plaira le plus 😉

Fabrication (PCB et soudage des composants)

À présent, revenons à la partie matérielle ! Et voyons ensemble le circuit imprimé de ce voltmètre électronique AT mega 328P :

Le PCB est de type double face (une seule couche par face), avec tous les composants soudés du même côté.

À noter qu’il y a un composant CMS au milieu des autres, qu’il conviendra de souder en premier, pour être plus à l’aise ensuite (il s’agit du convertisseur de tension 3,3 volts, modèle AMS1117-3V3).

Du reste, voici quelques photos prises au moment du soudage, de mon côté :

Sinon, rien de bien compliqué à souder, en fait ! Maintenant, voyons la programmation de l’ATmega328P, véritable coeur de notre voltmètre !

Téléversement du programme arduino dans l’ATmega328P (via FTDI)

Maintenant que nous avons soudés tous les composants/connecteurs, il nous reste plus qu’à uploader le programme arduino (à le téléverser, si vous préférez). Pour cela, nous aurons besoin d’une carte FTDI (convertisseur USB/TTL), de type FT232RL ou équivalent, qu’il faudra brancher sur notre montage, comme suit :

Pour faire simple, le convertisseur USB/TTL (modèle FT232RL de chez FTDI, ou équivalent, visible avec son circuit imprimé rouge/rectangulaire ci-dessus) se place entre notre montage et l’ordinateur. Ainsi, nous allons pouvoir envoyer notre code arduino dans le microcontrôleur ATmega328 P.

Remarque très importante : le microcontrôleur ATmega 328P, que nous allons programmer ici, doit IMPÉRATIVEMENT posséder un bootloader déjà gravé en lui (de type optiboot). Si ce n’est pas le cas, vous devez retirer l’ATmega de la carte, et le programmer en dehors. Pour cela, vous pouvez par exemple suivre le tuto que j’avais fait sur la gravure d’un bootloader sur microcontrôleur AT mega328P (en se servant d’une carte Arduino Uno transformée en « programmateur ISP », pour l’occasion).

À présent, voici les étapes à suivre pour téléverser le programme dans l’ATmega328P, depuis votre ordi, en passant au travers du FTDI :

  • assurez-vous que votre montage soit dépourvu d’alimentation (aucune pile 9V ne doit être insérée, pour l’instant) ; ainsi, l’alimentation de notre voltmètre, pour sa programmation, se fera via le convertisseur USB/TTL, qui devra être réglé en position « +5V » pour l’occasion
  • branchez le convertisseur USB vers TTL (FTDI ou équivalent) à votre PC d’un côté, et au montage de l’autre
  • ouvrez l’IDE Arduino (remarque : nous n’utilisons aucune carte arduino ici, mais pouvons utiliser l’IDE tout comme, étant donné que notre microcontrôleur sera doté du même bootloader qu’un Arduino Uno)
  • copiez/collez le code du voltmètre, présenté plus haut
  • cliquez dans le menu Outils > Port > et sélectionnez le port COM du FTDI (COM12, dans mon cas, mais ce sera sûrement différent chez vous)
  • cliquez dans le menu Outils > Type de carte > et sélectionnez la carte « Arduino Uno ». Encore une fois : bien que nous n’utilisons pas la moindre carte arduino ici, notre ATmega328P pourra se programmer de la sorte, du fait qu’il est muni d’un bootloader identique à celui qu’on retrouve sur une carte uno !
  • cliquez dans le menu Outils > Programmateur > et assurez-vous que « AVRISP mkII » est bien sélectionné (ce doit être le cas normalement, par défaut)
  • puis téléversez le programme (via le menu Croquis > Téléverser, ou à l’aide des touches CTRL+U, au clavier)

Une fois le programme téléversé, vous devriez voir l’écran LCD du voltmètre s’allumer, ainsi que la LED « témoin de bon fonctionnement » s’allumer. Si ce n’est pas le cas, analysez bien le retour log de l’IDE Arduino, afin d’identifier d’où viens le problème (si besoin, reportez vous à l’article que j’avais fait sur la programmation de l’ATmega328P, avec un FTDI, pour plus d’infos).

Tests et essais

Maintenant que le programme tourne, faisons quelques essais (avec le programmateur FTDI retiré, et une pile d’alimentation 9V insérée, bien entendu !).

Pour commencer, branchons notre voltmètre fait-maison sur une alimentation stabilisée, afin de voir s’il fonctionne bien (important : notre montage est conçu pour lire des tensions continues comprises entre 0 et 25 volts ; ne l’exposez donc jamais à une tension inférieure ou supérieure, sous peine de risquer d’endommager le montage). Voici ce que donne le câblage en image, de mon côté :

Branchement voltmètre courant continu DIY sur alimentation stabilisée Kaiweets modèle PS 3010, avec cordons rouge noir à fiches bananes

Nota : l’alimentation utilisée ici est le modèle PS-3010F de chez Kaiweets, dont je vous avais fait la revue récemment (avec essais en charge, calibrage, et tout !).

Et voici les valeurs lues par le voltmètre, lorsque j’ai réglé la tension de l’alim sur 0V, 5V, 12V, puis 25V :

Comme vous pouvez le constater, la justesse de mesure n’est pas si mal (compte tenu du fait que la tension mesurée par notre voltmètre passe par un pont diviseur de tension résistif, avec des résistances à 1% de tolérance !). Mais bon, il ne s’agissait pas là d’essayer de rivaliser avec tout multimètre numérique ou autre, mais bien d’apprendre à concevoir et réaliser un montage ludique 😉

Sinon, voici un autre exemple de mesure de tension simple, avec une petite batterie au plomb 12V :

Essai mesure tension 12V sur batterie au plomb rechargeable, test du projet de voltmètre numérique créé par passion-électronique

Sympa, non ? Pour un petit voltmètre fait-maison, utilisant une petite poignée de composants 😉

Remarques / améliorations possibles

Au oui, j’ai oublié de le préciser … mais vous êtes libre d’utiliser le type de câble à connecteur banane que vous voulez (sondes de mesure à pointes, câble avec fiches crocodiles au bout, etc). Là, j’ai simplement utilisé les câbles d’un de mes multimètres, pour l’exemple :

Au niveau des améliorations possibles, il y en aurait tout plein à faire (mais pour rappel, le but n’était pas de faire ici quelque chose de parfait, mais d’apprendre à mettre en œuvre certains composants électroniques et de voir comment les utiliser ensemble). Sinon, on aurait pu mettre :

  • un fusible de protection pour la pile 9V, qui n’aurait pas été superflu
  • un dispositif d’alerte « pile faible », qui mesurerait la tension de cette pile 9V, afin de savoir « où elle en est »
  • une protection contre les inversions de polarité au niveau de la pile 9V (car même si elle dispose de plots spécifiques évitant les inversions et qu’un bouton on/off l’isole du montage, il suffirait simplement de faire un contact inverse avec le bouton on/off allumé, pour « détruire » le montage)
  • une protection contre les tensions négatives, au niveau de l’entrée de mesure de tension, qui aurait apporté plus de sécurité au montage également (je pense d’ailleurs qu’une simple diode schottky, montée en parallèle et en inverse de la résistance basse du pont diviseur de tension R4, aurait suffit pour protéger l’entrée ADC de notre µC)

Du reste, l’utilisation d’un convertisseur analogique → numérique différentiel type ADS1115 aurait pu apporter une meilleure précision (16 bits), comparé à l’ADC interne à l’ATMEGA328P (10 bits). Mais bon, ça aurait pris bien plus de place sur le montage, et tout et tout !

Liens et téléchargements

Outre la liste des composants électronique détaillée tout en haut, voici quelques fichiers servant de support à ce projet :

Sinon, si vous avez des questions, n’hésitez pas à les poster en zone commentaire, ci-dessous ! J’y répondrai dès que je pourrais, dans la mesure du possible 🙂

Voltmètre 25 Vdc DIY : conclusion !

Voilà ! J’espère que ce projet de voltmètre construit autour d’un ATmega328P vous aura plu, et vous permettra de mieux visualiser comment programmer/utiliser ce microcontrôleur, à l’avenir ! Sans parler de l’écran LCD mis en œuvre ici, avec son convertisseur de niveaux logiques (5V/3V3), qui est sympa à découvrir aussi 😉

Sur ce, je vous dis à très bientôt, pour un prochain article !
Jérôme.

À découvrir aussi : un testeur de servomoteur, piloté par Arduino (avec écran d’affichage OLED)

Ce contenu vous plaît ? Alors abonnez-vous à la Newsletter pour ne rien louper !

(*) Mis à jour le 19/02/2024

2 commentaires sur “Voltmètre 0 à 25 Vdc fait-maison, à base de microcontrôleur ATmega328P + écran lcd Nokia 5110 (projet éducatif)”

    1. Site passionelectronique.fr

      Le PCB est, en quelque sorte, présent dans le fichier Gerber ci-dessus (cf. paragraphe 11 : liens et téléchargements).

      Ce fichier gerber se présente sous la forme d’un fichier ZIP, qu’il suffit de transmettre à un fabricant de PCB (JLCPCB, par exemple), pour qu’il réalise le PCB pour toi !

      Très bonne journée à toi,
      Jérôme.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Symbole danger point d'exclamation site PSE, triangle jaune avec contour noir, texte noir alerte au milieuAfin de filtrer au maximum les messages de type "spam" ou "inappropriés", chaque commentaire est soumis à modération, et validé manuellement. Du coup, il se peut que certains commentaires ne soient pas publiés, ou sinon, avec un peu de retard. Par ailleurs, j'ai malheureusement plus de messages à traiter que de temps pour y répondre ; c'est pourquoi je ne pourrais pas répondre à tout le monde. Désolé …