vendredi 28 décembre 2018

Kit: détecteur de métaux EQKIT MDS-60

Sur des sites comme eBay ou Aliexpress, vous pouvez vous procurer, pour environ 1 euro, un kit permettant de construire un détecteur de métaux pas très performant, mais néanmoins fonctionnel.

Le kit est constitué d'un circuit imprimé qui comporte sur chaque face un fil conducteur en forme de spirale, en plus de 16 composants à souder soi-même: 3 résistances, 5 condensateurs, 3 transistors, une LED, un potentiomètre, un buzzer piézo, un bornier à vis et un interrupteur.



Assemblage

Le kit est livré sans manuel d'instructions, mais les informations écrites directement sur le circuit imprimé sont suffisantes pour permettre à l'utilisateur de placer chaque composant au bon endroit.

La valeur de chaque résistance est indiquée sur le circuit imprimé: R1 est la résistance de 200 kΩ (bandes rouge-noir-jaune), R2 est la résistance de 2 kΩ (bandes rouge-noir-rouge) et R3 est la résistance de 470 Ω (bandes jaune-violet-brun).


C1 et C4 sont des condensateurs céramique de 100 nF (104), alors que C2 et C3 sont des condensateurs céramique de 2,2 nF (222).



Q1 est un transistor S9018 (NPN), alors que Q2 et Q3 sont des transistors S9012 (PNP). Puisque le profil du boîtier TO-92 est clairement dessiné sur le circuit imprimé, il faudrait être particulièrement négligeant pour les souder à l'envers.


En plaçant la LED et le condensateur électrolytique de 100 µF, il faut faire attention à la polarité: le trou entouré d'un carré est la borne positive, et on y insère donc la broche la plus longue.


VR1 est le potentiomètre qui permet de régler la sensibilité du détecteur.



On fait attention à la polarité du buzzer piézo: la borne positive est indiquée sur l'étiquette (c'est aussi la broche la plus longue).


J'ai finalement soudé l'interrupteur marche-arrêt et le bornier à vis.



Mon évaluation de la phase d'assemblage: il s'agit d'un kit facile, qui convient parfaitement aux néophytes (en fait, la plupart des composants ont été soudés par mon fils Zachary, qui n'avait jamais eu l'occasion de souder auparavant).

Test et utilisation du détecteur de métaux

Le détecteur de métaux doit être alimenté par une source de tension continue de 3 à 5 V (qui n'est pas incluse). Au moyen d'un petit tournevis, vous devrez probablement ajuster le potentiomètre (VR1) pour ajuster le circuit (de façon à ce qu'il ne réagisse qu'à proximité d'un objet métallique).

Les premiers tests, réalisés au moyen d'une pièce de monnaie, se sont révélés positifs, mais il faut placer le détecteur vraiment très proche de la pièce (la portée officielle de 6 cm semble quelque peu optimiste, mais peut-être qu'un meilleur réglage du potentiomètre permettrait l'obtention de meilleurs résultats).


Mon évaluation du détecteur de métaux: je le vois plus comme un jouet éducatif que comme un outil vraiment utile. Ne comptez pas trop sur ce dispositif pour trouver des bijoux enfouis sous le sable d'une plage...

Yves Pelletier   (TwitterFacebook)
(avec la précieuse collaboration de Zachary Pelletier)

mardi 25 décembre 2018

Boîte cadeau musicale et lumineuse (Arduino)

À l'occasion de Noël, j'ai fabriqué une boîte cadeau qui sort un peu de l'ordinaire: elle comporte une figurine de Père Noël qui danse (animée par un servomoteur), un haut-parleur qui diffuse une mélodie de Noël, une dizaine de LEDs clignotantes de diverses couleurs, et un écran LCD qui affiche des souhaits de circonstance.

Voyez vous-même:


Toute cette électronique pour ... une boîte?

Si on part du principe qu'une fois ouverte, la boîte sera immédiatement mise au recyclage, il semble peu raisonnable d'y placer tout cet appareillage électronique. Par contre, rien ne vous empêche de repartir avec la boîte après avoir offert le cadeau qu'elle contient.  Autre possibilité: il s'agit d'une façon originale d'offrir en cadeau un kit Arduino...

Le circuit



La base du dispositif est un Arduino Uno. Pour que la boîte puisse facilement être transportée, il est alimenté par une pile de 9 V. Un interrupteur marche-arrêt permet de le mettre en marche au moment approprié et, peut-être plus important encore, l'arrêter quand vous en avez ras le bol...  Puisque ma boîte était de grande dimension, je n'ai pas jugé utile de miniaturiser mon circuit avec un Arduino Nano.


La figurine de Père Noël qui danse est attachée à un petit servomoteur qui effectue un mouvement de va-et-vient de 90° d'amplitude.  Il est contrôlé par la broche 9 de l'Arduino.


Le haut-parleur a été branché à la broche 8 de  l'Arduino par l'entremise d'un transistor, tel que recommandé dans un précédent billet.  Des petits trous on été pratiqués dans la boîte, devant le haut-parleur, pour faciliter la diffusion du son.  Personnellement, je préfère les hauts-parleurs, mais vous pouvez aussi utiliser un piézo.



L'afficheur LCD tient lieu d'étiquette et pourrait être utilisé pour écrire à qui est destiné le cadeau, de la part de qui, etc.  L'effet est plus intéressant si le message affiché change périodiquement.  Pour plus d'informations sur l'utilisation d'un afficheur LCD 2 X 16, consultez ce billet.



Les broches A0 à A5 de l'Arduino sont utilisées comme sorties numériques pour contrôler les LEDs.  Les LEDs rouges et les LEDs vertes ont été placées en paires, mais pas les LEDs bleues, puisqu'elles nécessitent une plus grande tension.



Bien entendu, chaque élément de la boîte est facultatif: vous pouvez fabriquer une boîte cadeau très spectaculaire sans afficheur LCD, par exemple.


Le sketch

Puisque chaque élément du circuit avait déjà été utilisé dans d'autres projets, la seule difficulté, lors de la programmation, a été de faire en sorte que tout s'effectue simultanément sans interférer avec les autres parties du circuit.

Il aurait été facile de jouer la mélodie au complet, de faire ensuite bouger le Père Noël une fois la musique terminée, et finalement faire clignoter quelques LEDs, mais il était important que le Père Noël bouge pendant que la musique joue et que les LEDs clignotent, d'où l'utilisation assez intensive de la fonction millis() pour vérifier si c'est le moment de jouer une nouvelle note, de changer l'état d'une LED, ou de bouger le Père Noël, avec interdiction totale d'utiliser la fonction delay()!!!

À noter que chaque groupe de LED a sa propre fréquence de clignotement, ce qui donne un effet pseudo aléatoire qui me plaît bien.

/****************************************************************************
Boite cadeau de Noël Arduino
Une boîte cadeau qui joue une mélodie de Noël, fait clignoter des LEDs,
affiche un message sur un LCD, et fait bouger un père Noël grâce à un
servomoteur.
Pour plus d'informations:
https://electroniqueamateur.blogspot.com/2018/12/boite-cadeau-musicale-et-lumineuse.html
*****************************************************************************/
// inclusion des bibliothèques
#include <Servo.h> // pour le servomoteur
#include <LiquidCrystal.h> // pour l'afficheur LCD
// Définition des broches
#define pinHautParleur 8 // haut-parleur à la broche 8 de l'Arduino
#define pinServo 9 // servo-moteur à la broche 9 de l'Arduino
#define pinRS 12 // pin 4 (RS) de l'afficheur branchée à pin 12 de l'Arduino
#define pinEnable 11 // pin 6 (Enable) de l'afficheur branchée à pin 11 de l'Arduino
#define pinD4 5 // pin 11 (D4) de l'afficheur branchée à pin 5 de l'Arduino
#define pinD5 4 // pin 12 (D5) de l'afficheur branchée à pin 4 de l'Arduino
#define pinD6 3 // pin 13 (D6) de l'afficheur branchée à pin 3 de l'Arduino
#define pinD7 2 // pin 14 (D7) de l'afficheur branchée à pin 2 de l'Arduino
#define LED1Pin 14 // une paire de LEDs est reliée à A0
#define LED2Pin 15 // une paire de LEDs est reliée à A1
#define LED3Pin 16 // une paire de LEDs est reliée à A2
#define LED4Pin 17 // une paire de LEDs est reliée à A3
#define LED5Pin 18 // une paire de LEDs est reliée à A4
#define LED6Pin 19 // une paire de LEDs est reliée à A5
// variables globales associées à l'afficheur LCD
// Initialisation de la bibliothèque LiquidCrystal en utilisant les pins définies ci-dessus:
LiquidCrystal lcd(pinRS, pinEnable, pinD4, pinD5, pinD6, pinD7);
int message = 0; // numéro du message affiché sur le LCD
unsigned long dernierMessage = 0; // moment du plus récent changement de message
const int delaiMessage = 4000; // nombre de millisecondes entre deux messages successifs
// variables globales associées au servomoteur
Servo myservo;
int pos = 0; // position initiale du servomoteur
int sens = 0; // sens de rotation du servomoteur
const int delaiServo = 20; // nombre de millisecondes entre deux changements de position du servomoteur
unsigned long dernierMvtServo = 0; // moment du plus récent changement de position du servomoteur
const int deplacementMax = 90; // déplacement maximum du servomoteur, en degrés
// variables globales associées à la mélodie jouée au haut-parleur
// fréquence associée à chaque note
// do, do#, ré, ré#, mi, fa, fa#, sol, sol#, la, la#, si
const float note[12] = {65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47 };
const int nombreDeNotes = 49;
int laNote; // numéro de la prochaine note à jouer
int silence = 0; //devient 1 pendant le silence entre deux notes
const int tempo = 150; // delai en millisecondes entre deux notes consécutives
unsigned long derniereNote = 0; // moment du plus recent changement de note
const int melodie[][3] = { {4, 2, 2}, {4, 2, 2}, {4, 2, 4}, {4, 2, 2}, {4, 2, 2}, {4, 2, 4},
{4, 2, 2}, {7, 2, 2}, {0, 2, 3}, {2, 2, 1}, {4, 2, 8},
{5, 2, 2}, {5, 2, 2}, {5, 2, 3}, {5, 2, 1}, {5, 2, 2}, {4, 2, 2}, {4, 2, 3},
{4, 2, 1}, {4, 2, 2}, {2, 2, 2}, {2, 2, 2}, {4, 2, 2}, {2, 2, 4}, {7, 2, 4},
{4, 2, 2}, {4, 2, 2}, {4, 2, 4}, {4, 2, 2}, {4, 2, 2}, {4, 2, 4},
{4, 2, 2}, {7, 2, 2}, {0, 2, 3}, {2, 2, 1}, {4, 2, 8},
{5, 2, 2}, {5, 2, 2}, {5, 2, 3}, {5, 2, 1}, {5, 2, 2}, {4, 2, 2}, {4, 2, 3},
{4, 2, 1}, {7, 2, 2}, {7, 2, 2}, {5, 2, 2}, {2, 2, 2}, {0, 2, 8}
};
// variables globales associées aux LEDs
const int delaiLED1 = 900; // délai en millisecondes avant le changement d'état de la LED
const int delaiLED2 = 1200;
const int delaiLED3 = 1400;
const int delaiLED4 = 1000;
const int delaiLED5 = 1600;
const int delaiLED6 = 1100;
unsigned long dernierLED1 = 0; // moment du plus récent changement d'état de la LED
unsigned long dernierLED2 = 0;
unsigned long dernierLED3 = 0;
unsigned long dernierLED4 = 0;
unsigned long dernierLED5 = 0;
unsigned long dernierLED6 = 0;
void setup() {
pinMode(LED1Pin, OUTPUT);
pinMode(LED2Pin, OUTPUT);
pinMode(LED3Pin, OUTPUT);
pinMode(LED4Pin, OUTPUT);
pinMode(LED5Pin, OUTPUT);
pinMode(LED6Pin, OUTPUT);
myservo.attach(pinServo);
lcd.begin(16, 2);
lcd.setCursor(5, 0);
lcd.print("Joyeux");
// curseur sur la deuxième ligne
lcd.setCursor(4, 1);
lcd.print("Noel !!!");
}
void loop() {
int frequence;
// Contrôle du servomoteur
if ((millis() - dernierMvtServo) > delaiServo) { // c'est le temps de faire bouger le servomoteur
myservo.write(pos);
if (sens == 0) {
pos++;
if (pos > deplacementMax) {
pos = deplacementMax;
sens = 1;
}
}
if (sens == 1) {
pos--;
if (pos < 0) {
pos = 0;
sens = 0;
}
}
dernierMvtServo = millis();
}
// contrôle du haut-parleur
if ((silence == 0) && ((millis() - derniereNote) > 50)) { // c'est le temps de jouer une nouvelle note
frequence = round(note[melodie[laNote][0]] * 2 * (melodie[laNote][1] - 1));
tone(pinHautParleur, frequence);
silence = 1;
derniereNote = millis();
}
else if ((millis() - derniereNote) > ((tempo * melodie[laNote][2] - 50))) { // il faut arrêter une note
noTone(pinHautParleur);
silence = 0;
laNote++;
if (laNote == nombreDeNotes) {
laNote = 0;
}
derniereNote = millis();
}
// contrôle de l'afficheur
if ((millis() - dernierMessage) > delaiMessage) { // c'est le moment de changer le message affiché
lcd.clear();
if (message == 0) {
// curseur sur la première ligne
lcd.setCursor(5, 0);
lcd.print("Joyeux");
// curseur sur la deuxième ligne
lcd.setCursor(4, 1);
lcd.print("Noel !!!");
}
if (message == 1) {
// curseur sur la première ligne
lcd.setCursor(2, 0);
lcd.print("Bonne annee");
// curseur sur la deuxième ligne
lcd.setCursor(4 , 1);
lcd.print("2019 !!!");
}
message++;
if (message > 1) {
message = 0;
}
dernierMessage = millis();
}
//contrôle des LEDs
if ((millis() - dernierLED1) > delaiLED1) {
digitalWrite(LED1Pin, !digitalRead(LED1Pin));
dernierLED1 = millis();
}
if ((millis() - dernierLED2) > delaiLED2) {
digitalWrite(LED2Pin, !digitalRead(LED2Pin));
dernierLED2 = millis();
}
if ((millis() - dernierLED3) > delaiLED3) {
digitalWrite(LED3Pin, !digitalRead(LED3Pin));
dernierLED3 = millis();
}
if ((millis() - dernierLED4) > delaiLED4) {
digitalWrite(LED4Pin, !digitalRead(LED4Pin));
dernierLED4 = millis();
}
if ((millis() - dernierLED5) > delaiLED5) {
digitalWrite(LED5Pin, !digitalRead(LED5Pin));
dernierLED5 = millis();
}
if ((millis() - dernierLED6) > delaiLED6) {
digitalWrite(LED6Pin, !digitalRead(LED6Pin));
dernierLED6 = millis();
}
}

À lire aussi

D'autres projets d'électronique pour Noël: fabrication d'un mini sapin de Noël clignotant et répertoire de mélodies de Noël pour Arduino.

Yves Pelletier   (TwitterFacebook)

mercredi 19 décembre 2018

Arduino chante Noël


Je vous propose aujourd'hui quelques mélodies de Noël qui pourraient s'avérer utile à l'intérieur d'un projet Arduino (carte de souhait musicale ou autre).

Les 5 mélodies sont:
  • Vive le vent (Jingle Bells)
  • We Wish You a Merry Christmas
  • Le petit Renne au nez rouge
  • Petit papa Noël
  • Au royaume du bonhomme hiver

Le circuit

Il s'agit de brancher un haut-parleur ou un piézo à la broche 8 de l'Arduino­.

À cause de la très faible impédance d'un haut-parleur, il est fortement déconseillé de le brancher directement à l'Arduino: utilisez plutôt un circuit comportant un transistor, tel qu'illustré ci-dessous (plus d'informations ici).


Cette précaution n'est pas utile si vous utilisez un piézo, puisque son impédance est très élevée.


Le sketch

Le sketch utilise la fonction tone() pour produire des notes.  Chaque mélodie a été définie à l'intérieur de sa propre fonction, pour faciliter le copier/coller de la mélodie désirée dans votre propre sketch.

/**********************************************************
5 mélodies de Noël jouées par l'Arduino
https://electroniqueamateur.blogspot.com/2018/12/arduino-chante-noel.html
************************************************************/
#define sortie 8 // sortie du son à la broche 8 de l'Arduino
// fréquence associée à chaque note
// do, do#, ré, ré#, mi, fa, fa#, sol, sol#, la, la#, si
const float note[12] = {65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47
};
// chaque note de la mélodie comporte 3 paramètres:
// note (de 0 à 11: 0 pour do, 1 pour do#, etc)
// octave (1 à 3)
// durée (1 pour croche, 2 pour noire, 4 pour ronde)
void jingleBells(void) {
// Vive le vent
const int nombreDeNotes = 49;
const int tempo = 150; // plus c'est petit, plus c'est rapide
const int melodie[][3] = { {4, 2, 2}, {4, 2, 2}, {4, 2, 4}, {4, 2, 2}, {4, 2, 2}, {4, 2, 4},
{4, 2, 2}, {7, 2, 2}, {0, 2, 3}, {2, 2, 1}, {4, 2, 8},
{5, 2, 2}, {5, 2, 2}, {5, 2, 3}, {5, 2, 1}, {5, 2, 2}, {4, 2, 2}, {4, 2, 3},
{4, 2, 1}, {4, 2, 2}, {2, 2, 2}, {2, 2, 2}, {4, 2, 2}, {2, 2, 4}, {7, 2, 4},
{4, 2, 2}, {4, 2, 2}, {4, 2, 4}, {4, 2, 2}, {4, 2, 2}, {4, 2, 4},
{4, 2, 2}, {7, 2, 2}, {0, 2, 3}, {2, 2, 1}, {4, 2, 8},
{5, 2, 2}, {5, 2, 2}, {5, 2, 3}, {5, 2, 1}, {5, 2, 2}, {4, 2, 2}, {4, 2, 3},
{4, 2, 1}, {7, 2, 2}, {7, 2, 2}, {5, 2, 2}, {2, 2, 2}, {0, 2, 8}
};
int frequence;
for ( int i = 0; i < nombreDeNotes ; i++ ) {
frequence = round(note[melodie[i][0]] * 2 * (melodie[i][1] - 1));
tone(sortie, frequence);
delay(tempo * melodie[i][2] - 50);
noTone(sortie);
delay(50);
}
}
void weWishYou (void) {
// We wish you a merry Christmas
const int nombreDeNotes = 29;
const int tempo = 150 ; // plus c'est petit, plus c'est rapide
const int melodie[][3] = { {7, 2, 2}, {0, 3, 2}, {0, 3, 1}, {2, 3, 1}, {0, 3, 1}, {11, 2, 1},
{9, 2, 2}, {9, 2, 2}, {9, 2, 2}, {2, 3, 2}, {2, 3, 1}, {4, 3, 1}, {2, 3, 1}, {0, 3, 1},
{11, 2, 2}, {7, 2, 2}, {7, 2, 2}, {4, 3, 2}, {4, 3, 1}, {5, 3, 1}, {4, 3, 1}, {2, 3, 1},
{0, 3, 2}, {9, 2, 2}, {7, 2, 2}, {9, 2, 2}, {2, 3, 2}, {11, 2, 2}, {0, 3, 4}
};
int frequence;
for ( int i = 0; i < nombreDeNotes ; i++ ) {
frequence = round(note[melodie[i][0]] * 2 * (melodie[i][1] - 1));
tone(sortie, frequence);
delay(tempo * melodie[i][2] - 50);
noTone(sortie);
delay(50);
}
}
void petitRenne (void) {
// le petit renne au nez rouge
const int nombreDeNotes = 56;
const int tempo = 200 ; // plus c'est petit, plus c'est rapide
const int melodie[][3] = { {7, 2, 2}, {9, 2, 1}, {7, 2, 1}, {4, 2, 2}, {0, 3, 2}, {9, 2, 2}, {7, 2, 6},
{7, 2, 1}, {9, 2, 1}, {7, 2, 1}, {9, 2, 1}, {7, 2, 2}, {0, 3, 2}, {11, 2, 6},
{5, 2, 2}, {7, 2, 1}, {5, 2, 1}, {2, 2, 2}, {11, 2, 2}, {9, 2, 2}, {7, 2, 6},
{7, 2, 1}, {9, 2, 1}, {7, 2, 1}, {9, 2, 1}, {7, 2, 2}, {9, 2, 2}, {4, 2, 6},
{7, 2, 2}, {9, 2, 1}, {7, 2, 1}, {4, 2, 2}, {0, 3, 2}, {9, 2, 2}, {7, 2, 6},
{7, 2, 1}, {9, 2, 1}, {7, 2, 1}, {9, 2, 1}, {7, 2, 2}, {0, 3, 2}, {11, 2, 6},
{5, 2, 2}, {7, 2, 1}, {5, 2, 1}, {2, 2, 2}, {11, 2, 2}, {9, 2, 2}, {7, 2, 6},
{7, 2, 1}, {9, 2, 1}, {7, 2, 1}, {9, 2, 1}, {7, 2, 2}, {2, 3, 2}, {0, 3, 6},
};
int frequence;
for ( int i = 0; i < nombreDeNotes ; i++ ) {
frequence = round(note[melodie[i][0]] * 2 * (melodie[i][1] - 1));
tone(sortie, frequence);
delay(tempo * melodie[i][2] - 50);
noTone(sortie);
delay(50);
}
}
void petitPapa(void) {
// petit papa noël
const int nombreDeNotes = 58;
const int tempo = 250 ; // plus c'est petit, plus c'est rapide
const int melodie[][3] = { {7, 2, 2}, {0, 3, 2}, {0, 3, 2}, {0, 3, 2}, {2, 3, 2}, {0, 3, 6},
{0, 3, 1}, {2, 3, 1}, {4, 3, 2}, {4, 3, 2}, {4, 3, 2}, {5, 3, 2}, {4, 3, 6},
{2, 3, 2}, {0, 3, 3}, {0, 3, 1}, {0, 3, 1}, {0, 3, 1}, {11, 2, 1}, {9, 2, 1}, {7, 2, 6},
{7, 2, 1}, {7, 2, 1}, {0, 3, 4}, {0, 3, 1}, {0, 3, 1}, {11, 2, 1}, {0, 3, 1}, {2, 3, 6},
{7, 2, 2}, {0, 3, 2}, {0, 3, 2}, {0, 3, 2}, {2, 3, 2}, {0, 3, 6},
{0, 3, 1}, {2, 3, 1}, {4, 3, 2}, {4, 3, 2}, {4, 3, 2}, {5, 3, 2}, {4, 3, 6},
{2, 3, 2}, {0, 3, 3}, {0, 3, 1}, {0, 3, 1}, {0, 3, 1}, {11, 2, 1}, {9, 2, 1}, {7, 2, 6},
{7, 2, 1}, {7, 2, 1}, {0, 3, 4}, {0, 3, 1}, {0, 3, 1}, {2, 3, 1}, {2, 3, 1}, {0, 3, 6},
};
int frequence;
for ( int i = 0; i < nombreDeNotes ; i++ ) {
frequence = round(note[melodie[i][0]] * 2 * (melodie[i][1] - 1));
tone(sortie, frequence);
delay(tempo * melodie[i][2] - 50);
noTone(sortie);
delay(50);
}
}
void auRoyaume (void) {
//Au royaume du bonhomme hiver (Winter Wonderland)
const int nombreDeNotes = 33;
const int tempo = 150 ; // plus c'est petit, plus c'est rapide
const int melodie[][3] = { {7, 2, 2}, {7, 2, 1}, {7, 2, 9}, {7, 2, 2}, {7, 2, 1}, {4, 2, 2}, {7, 2, 6},
{7, 2, 2}, {7, 2, 1}, {7, 2, 9}, {7, 2, 2}, {7, 2, 1}, {5, 2, 2}, {7, 2, 6},
{7, 2, 1}, {11, 2, 2}, {11, 2, 1}, {11, 2, 2}, {9, 2, 6},
{9, 2, 1}, {7, 2, 2}, {7, 2, 1}, {7, 2, 2}, {5, 2, 6},
{4, 2, 2}, {4, 2, 1}, {4, 2, 2}, {4, 2, 1}, {2, 2, 2}, {2, 2, 1}, {2, 2, 1}, {2, 2, 1}, {0, 2, 9},
};
int frequence;
for ( int i = 0; i < nombreDeNotes ; i++ ) {
frequence = round(note[melodie[i][0]] * 2 * (melodie[i][1] - 1));
tone(sortie, frequence);
delay(tempo * melodie[i][2] - 50);
noTone(sortie);
delay(50);
}
}
void setup() {
}
void loop() {
jingleBells();
delay (2000);
weWishYou ();
delay (2000);
petitRenne();
delay (2000);
petitPapa();
delay (2000);
auRoyaume();
delay (2000);
}




Yves Pelletier   (TwitterFacebook)

samedi 15 décembre 2018

Menus de navigation sur écran Nokia 5110 (Arduino)

Dans ce quatrième billet consécutif mettant en vedette un petit écran LCD de type Nokia 5110 contrôlé par un Arduino Uno, je vous présente un sketch qui permet de naviguer dans des menus au moyen de 4 boutons poussoirs.

(Dans un autre article, ce sketch a été adapté pour un écran OLED SH1106 I2C).

Le menu principal comporte un certain nombre de sous-menus. Chaque sous-menu donne accès à une deuxième page comportant une liste d'items pouvant être sélectionnés par l'utilisateur.

Le bouton "flèche vers le bas" permet de sélectionner l'item se situant une ligne plus bas dans la liste. Le bouton "flèche vers le haut" permet de sélectionner l'item se situant une ligne plus haut dans la liste. Le bouton "flèche vers la droite" permet d'exécuter l'item de la liste qui est sélectionné. Le bouton "flèche vers la gauche" permet de revenir à la page précédente.

Le nombre de sous-menus dans le menu principal ainsi que le nombre d'items dans chaque sous-menu peu facilement être modifié à l'intérieur du sketch.

 Je vous présente immédiatement une courte vidéo montrant le résultat:

   

Le circuit  

L'écran Nokia est branché à l'Arduino de la même façon que dans mes 3 billets précédents: un circuit intégré 4050 a été utilisé afin d'abaisser à 3,3 V les tension de sortie de l'Arduino Uno (voir ce précédent billet pour plus de détails concernant les branchements du 4050).
  • La broche SCE de l'afficheur reçoit le signal provenant de la broche 4 de l'Arduino
  • La broche RST de l'afficheur reçoit le signal provenant de la broche 3 de l'Arduino
  • La broche D/C de l'afficheur reçoit le signal de la broche 5 de l'Arduino
  • La broche DN/MOSI de l'afficheur reçoit le signal de la broche 11 de l'Arduino
  • La broche SCLK de l'afficheur reçoit le signal de la broche 13 de l'Arduino
De plus, 4 boutons sont associés à une résistance de tirage de 10 kΩ et branchés à l'Arduino de la façon suivante:
  • bouton "flèche vers le haut": broche 6 de l'Arduino
  • bouton "flèche vers le bas": broche 7 de l'Arduino
  • bouton "flèche vers la gauche": broche 8 de l'Arduino
  • bouton "flèche vers la droite": broche 9 de l'Arduino


Le sketch

Pour utiliser ce sketch, il faut d'abord avoir installé les bibliothèques Adafruit-PCD8544-Nokia-5110-LCD-library et Adafruit-GFX-Library dans votre IDE Arduino.

La fonction loop() consiste essentiellement à surveiller l'état des boutons et, lorsque l'un d'eux a été enfoncé, modifier l'état des variables appropriées (un délai de 50 millisecondes a été prévu pour éviter les rebonds).

La fonction miseAJour() est responsable de dessiner le contenu de l'écran en fonction de l'état des variables ayant été modifiées au moyen des boutons. Par exemple, la variable NumeroMenu prend la valeur "0" lorsqu'il faut afficher le menu principal, mais devient "1" lorsque le sous-menu numéro 1 a été sélectionné. La variable NumeroItem contient le numéro de l'élément de la liste qui est sélectionné (donc écriture blanche sur fond noir).  Puisque l'écran ne peut montrer que 4 éléments de la liste à la fois, mais que la liste peut contenir plus de 4 éléments. la variable numeroTeteDeListe contient le numéro du premier élément à afficher dans le haut de l'écran.

Bien entendu, le texte de chaque liste peut être modifié à volonté de façon à produire un programme qui répond à vos besoins (dans son état actuel, chaque titre doit comporter un maximum de 14 caractères, ce qui est sensiblement la taille maximale pouvant être affichée sur une ligne de l'écran).


/*****************************************************
Système de menus de navigation contrôlé par 4 boutons
poussoirs sur écran Nokia 5110 et Arduino.
Pour plus d'informations:
https://electroniqueamateur.blogspot.com/2018/12/menus-de-navigation-sur-ecran-nokia.html
*****************************************************/
// bibliothèques pour l'utilisation de l'écran
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
// broches utilisées par l'écran Nokia
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);
// broches utilisées par les boutons poussoirs
#define boutonHAUT 6
#define boutonBAS 7
#define boutonGAUCHE 8
#define boutonDROITE 9
#define nombreDeSousMenus 6 // nombre d'items dans la liste du menu principal
const int nombredItems[nombreDeSousMenus] = {5, 4, 3, 6, 2, 4 }; // nombre d'items dans chacun des sous-menus
int nombreMaxDeSousMenus; // valeur maximale contenue dans le tableau nombredItems (sera calculée dans calculeMax()
int numeroMenu = 0; // numéro du menu affiché à l'écran; on commence par 0, le menu principal
int numeroItem = 1; // numéro de l'item sélectionné; on commence par 1, le premier élément en haut de la liste
int numeroTeteDeListe = 1; // numéro de l'item affiché en haut de la liste visible à l'écran (utile pour les listes plus longues que 4 éléments)
int etatBoutons = 0; // nul quand aucun bouton n'est enfoncé
int etatBoutonsPrecedent = 0; // nul si aucun bouton n'était enfoncé au précédent passage dans la boucle
unsigned long tempsAntiRebond = 0; // dernière fois qu'un changement d'état de bouton a été détecté
const unsigned long delaiAntiRebond = 50; // délai entre le dernier changement d'état de bouton et le début de l'action
// on calcule le nombre maximum d'items qu'il peut y avoir dans un sous-menu
int calculeMax (void) {
int maxim = 0;
for (int i = 0; i < nombreDeSousMenus; i++) {
if (nombredItems[i] > maxim) {
maxim = nombredItems[i];
}
}
nombreMaxDeSousMenus = maxim;
}
void setup() {
pinMode(boutonHAUT, INPUT);
pinMode(boutonBAS, INPUT);
pinMode(boutonGAUCHE, INPUT);
pinMode(boutonDROITE, INPUT);
calculeMax();
display.begin();
display.setContrast(60); // généralement entre 40 et 60: ça dépend de votre écran
display.clearDisplay();
miseAjour();
}
void loop() {
int nombreDeLignes;
int lectureBoutons, lectureBAS, lectureHAUT, lectureGAUCHE, lectureDROITE;
if (numeroMenu == 0) { // menu principal
nombreDeLignes = nombreDeSousMenus;
}
else { // pas le menu principal
nombreDeLignes = nombredItems[numeroMenu - 1];
}
// on vérifie si un des boutons est enfoncé
lectureBAS = digitalRead(boutonBAS);
lectureHAUT = digitalRead(boutonHAUT);
lectureGAUCHE = digitalRead(boutonGAUCHE);
lectureDROITE = digitalRead(boutonDROITE);
// procédure anti-rebonds
lectureBoutons = (lectureBAS || lectureHAUT || lectureGAUCHE || lectureDROITE) ;
if (lectureBoutons != etatBoutonsPrecedent) {
tempsAntiRebond = millis();
}
if ((millis() - tempsAntiRebond) > delaiAntiRebond) {
if (lectureBoutons != etatBoutons) {
// le bouton est nouvellement enfoncé depuis un temps raisonnable
etatBoutons = lectureBoutons;
if ( lectureHAUT ) { // bouton flèche vers le haut (on monte d'une ligne dans la liste)
if (numeroItem > 1) {
numeroItem--;
}
else {
numeroItem = nombreDeLignes;
numeroTeteDeListe = nombreDeLignes - 2;
if (numeroTeteDeListe == 0)
{
numeroTeteDeListe = 1;
}
}
if (numeroTeteDeListe > 1) {
numeroTeteDeListe--;
}
miseAjour();
}
if ( lectureBAS ) { // bouton flèche vers le bas: on descend d'une ligne dans la liste
if (numeroItem < nombreDeLignes) {
numeroItem++;
}
else {
numeroItem = 1;
numeroTeteDeListe = 1;
}
if (numeroItem > 4) {
numeroTeteDeListe++;
}
miseAjour();
}
if ( lectureGAUCHE ) { // bouton flèche vers la gauche: on recule à la page précédente
if ((numeroMenu > 0) && (numeroMenu < 100)) {
numeroItem = numeroMenu;
numeroMenu = 0;
if (numeroItem <= 4) {
numeroTeteDeListe = 1;
}
else {
numeroTeteDeListe = numeroItem - 3;
}
}
else if (numeroMenu > 100) {
numeroItem = numeroMenu % 100;
numeroMenu = numeroMenu / 100;
}
miseAjour();
}
if ( lectureDROITE ) { // bouton flèche vers la droite: on exécute le menu sélectionné
if (numeroMenu == 0) {
numeroMenu = numeroItem;
numeroTeteDeListe = 1;
numeroItem = 1;
}
else {
numeroMenu = numeroMenu * 100 + numeroItem;
}
miseAjour();
}
}
}
etatBoutonsPrecedent = lectureBoutons;
}
void miseAjour(void) // on dessine ce qui doit apparaître à l'écran
{
char* titresSousMenus[] = {"Sous-menu 1", "Sous-menu 2", "Sous-menu 3",
"Sous-menu 4", "Sous-menu 5", "Sous-menu 6"
};
char menuStr[15], itemAStr[15], itemBStr[15], itemCStr[15], itemDStr[15] ;
char titresItems[nombreMaxDeSousMenus][15];
int nombreDeLignes;
display.clearDisplay();
if (numeroMenu < 100) { // nous sommes dans une page de menus
if (numeroMenu == 0) { // menu principal
nombreDeLignes = nombreDeSousMenus;
}
else { // pas le menu principal
nombreDeLignes = nombredItems[numeroMenu - 1];
}
if (numeroMenu == 1) { // sous-menu 1
strcpy(titresItems[0], "Item 1.1");
strcpy(titresItems[1], "Item 1.2");
strcpy(titresItems[2], "Item 1.3");
strcpy(titresItems[3], "Item 1.4");
strcpy(titresItems[4], "Item 1.5");
}
if (numeroMenu == 2) { // sous-menu 2
strcpy(titresItems[0], "Item 2.1");
strcpy(titresItems[1], "Item 2.2");
strcpy(titresItems[2], "Item 2.3");
strcpy(titresItems[3], "Item 2.4");
}
if (numeroMenu == 3) { // sous-menu 1
strcpy(titresItems[0], "Item 3.1");
strcpy(titresItems[1], "Item 3.2");
strcpy(titresItems[2], "Item 3.3");
}
if (numeroMenu == 4) { // sous-menu 1
strcpy(titresItems[0], "Item 4.1");
strcpy(titresItems[1], "Item 4.2");
strcpy(titresItems[2], "Item 4.3");
strcpy(titresItems[3], "Item 4.4");
strcpy(titresItems[4], "Item 4.5");
strcpy(titresItems[5], "Item 4.6");
}
if (numeroMenu == 5) { // sous-menu 1
strcpy(titresItems[0], "Item 5.1");
strcpy(titresItems[1], "Item 5.2");
}
if (numeroMenu == 6) { // sous-menu 2
strcpy(titresItems[0], "Item 6.1");
strcpy(titresItems[1], "Item 6.2");
strcpy(titresItems[2], "Item 6.3");
strcpy(titresItems[3], "Item 6.4");
}
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(BLACK);
// écriture du titre de la page
if (numeroMenu == 0) { // menu principal
strcpy(menuStr, "Menu principal");
}
else {
strcpy(menuStr, titresSousMenus[numeroMenu - 1]);
}
display.println(menuStr);
// rectangle noir à la position de l'item sélectionné
display.fillRect(0, 10 * (numeroItem - numeroTeteDeListe + 1) - 1, 84, 10, BLACK);
// écriture du premier item de la liste
if (numeroMenu == 0) { // menu principal
strcpy(itemAStr, titresSousMenus[numeroTeteDeListe - 1]);
}
else {
strcpy(itemAStr, titresItems[numeroTeteDeListe - 1]);
}
if (numeroItem == 1) {
display.setTextColor(WHITE);
}
else {
display.setTextColor(BLACK);
}
display.setCursor(5, 10);
display.println(itemAStr);
// écriture du 2e item de la liste
if (nombreDeLignes >= 2) {
if (numeroMenu == 0) { // menu principal
strcpy(itemBStr, titresSousMenus[numeroTeteDeListe]);
}
else {
strcpy(itemBStr, titresItems[numeroTeteDeListe]);
}
if (numeroItem == 2) {
display.setTextColor(WHITE);
}
else {
display.setTextColor(BLACK);
}
display.setCursor(5, 20);
display.println(itemBStr);
}
// écriture du 3e item de la liste
if (nombreDeLignes >= 3) {
if (numeroMenu == 0) { // menu principal
strcpy(itemCStr, titresSousMenus[numeroTeteDeListe + 1]);
}
else {
strcpy(itemCStr, titresItems[numeroTeteDeListe + 1]);
}
if (numeroItem == 3) {
display.setTextColor(WHITE);
}
else {
display.setTextColor(BLACK);
}
display.setCursor(5, 30);
display.println(itemCStr);
}
// écriture du 4e item de la liste
if (nombreDeLignes >= 4) {
if (numeroMenu == 0) { // menu principal
strcpy(itemDStr, titresSousMenus[numeroTeteDeListe + 2]);
}
else {
strcpy(itemDStr, titresItems[numeroTeteDeListe + 2]);
}
if (numeroItem >= 4) {
display.setTextColor(WHITE);
}
else {
display.setTextColor(BLACK);
}
display.setCursor(5, 40);
display.println(itemDStr);
}
}
else { // ce n'est pas une page de menu
/* C'est ici que vous pourrez accomplir les actions découlant d'un choix de menu
Par exemple, si la personne a sélectionné l'item 3 du sous-menu 2, la variable
numeroMenu vaut 203 (numéro du sous-menu * 100 + numéro de l'item */
display.setCursor(0, 0);
display.setTextColor(BLACK);
display.println("Vous avez");
display.println("choisi");
display.print("l'item ");
display.println(numeroMenu % 100);
display.print("du sous-menu ");
display.println(numeroMenu / 100);
}
display.display();
}
view raw Nokia_menus.ino hosted with ❤ by GitHub


Yves Pelletier   (TwitterFacebook)

lundi 10 décembre 2018

Graphique cartésien sur écran Nokia 5110 (Arduino)

Pour ce troisième billet consécutif concernant l'utilisation d'un écran Nokia 5110 contrôlé par une carte Arduino, je me suis amusé à présenter sous la forme d'un graphique cartésien la tension mesurée à l'entrée analogique A0 de l'Arduino (graphique tension vs temps).


Puisque l'écran a 84 pixels de largeur et que j'ai choisi de séparer chaque mesure par une distance horizontale de 4 pixels, l'écran présente en tout temps les 21 mesures les plus récentes.

(Dans un autre article, ce sketch a été adapté pour un écran OLED SH1106 I2C).

Connexions

L'écran Nokia 5110 est branché à l'Arduino de la même façon que dans mon précédent article sur le sujet: encore une fois, j'ai utilisé un circuit intégré 4050 afin que le niveau logique de 5 V des signaux issus de l'Arduino soient abaissés à 3,3 V aux entrées de l'écran.

  • La broche SCE de l'afficheur reçoit le signal provenant de la broche 4 de l'Arduino
  • La broche RST de l'afficheur reçoit le signal provenant de la broche 3 de l'Arduino
  • La broche D/C de l'afficheur reçoit le signal de la broche 5 de l'Arduino
  • La broche DN/MOSI de l'afficheur reçoit le signal de la broche 11 de l'Arduino
  • La broche SCLK de l'afficheur reçoit le signal de la broche 13 de l'Arduino

Pour mes tests, j'ai fait varier la tension de l'entrée A0 avec un potentiomètre, qui pourra bien entendu être remplacé par un capteur plus utile.



Le sketch

Le sketch ci-dessous fonctionnera à la condition d'avoir préalablement installé les bibliothèques Adafruit-PCD8544-Nokia-5110-LCD-library et Adafruit-GFX-Library dans votre IDE Arduino.

L'algorithme est légèrement différent pour les 21 premières mesures que pour celles qui suivent. S'il y a encore de l'espace libre sur l'écran, on se contente de tracer le petit bout de graphique qui s'ajoute au dessin déjà affiché.  Par contre, si l'écran est déjà plein, nous devons effectuer une translation du graphique déjà tracé (déplacement de 4 pixels vers la gauche) afin de libérer de l'espace pour notre nouvelle mesure, à l'extrême droite du graphique. Cela impose de redessiner tout le contenu de l'écran.

Le rythme auquel l'Arduino prend ses mesures (et donc la vitesse à laquelle le graphique évolue à l'écran) peut être modifié grâce à la variable "intervalle", qui est le temps en millisecondes entre deux mesures consécutives.

J'ai aussi tracé six traits horizontaux qui représentent les graduations de 0 à 5 volts. Ils peuvent être omis si vous jugez que l'écran est trop surchargé.


/*****************************************************
Affichage d'une mesure analogique sous forme de graphique
cartésien sur un écran Nokia (Arduino)
Pour plus d'informations:
https://electroniqueamateur.blogspot.com/2018/12/graphique-cartesien-sur-ecran-nokia.html
*****************************************************/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);
const int intervalle = 500; // nombre de millisecondes entre deux mesures consécutives
int mesures[21]; // les 21 dernieres mesures
int compteur = 0; // nombre de mesures prises jusqu'à présent
void setup() {
display.begin();
display.setContrast(60); // variable d'un écran à l'autre (40 à 60)
display.clearDisplay();
}
void loop() {
int nouvelleValeur;
// mesure de la tension à l'entrée A0 et conversion en pixels
nouvelleValeur = 47 - map(analogRead(A0), 0, 1023, 0, 47); // car l'écran a 48 pixels de haut
if (compteur > 20) {
// l'écran est déjà rempli: on fait glisser le graphique vers la gauche
for (int i = 0; i < 20; i++) {
mesures[i] = mesures[i + 1];
}
mesures[20] = nouvelleValeur;
display.clearDisplay(); // on repart à neuf
// tracé de la courbe
for (int i = 1; i <= 20; i++) {
display.drawLine(4 * (i - 1), mesures[i - 1], 4 * i, mesures[i], BLACK);
}
// 6 lignes horizontales: 0 V, 1 V, 2 V...
for (int i = 0; i <= 5; i++) {
display.drawFastHLine(0, i * 9.5, 84, BLACK);
}
}
if ((compteur > 0) && (compteur <= 20)) {
// pas assez de mesures pour remplir tout l'écran: on ajoute notre nouvelle valeur
// au graphique déjà visible à l'écran
mesures[compteur] = nouvelleValeur;
// on trace une droite reliant la mesure précédente à notre nouvelle mesure
display.drawLine(4 * (compteur - 1), mesures[compteur - 1], 4 * compteur, mesures[compteur], BLACK);
compteur = compteur + 1;
}
else if (compteur == 0) {
// c'est la première mesure: on la met en variable,
// mais on ne trace rien à l'écran, sauf le quadrillage
mesures[0] = nouvelleValeur;
compteur = compteur + 1;
// 6 lignes horizontales: 0 V, 1 V, 2 V...
for (int i = 0; i <= 5; i++) {
display.drawFastHLine(0, i * 9.5, 84, BLACK);
}
}
display.display(); // affichage de notre travail à l'écran
delay(intervalle); // on attend un peu avant la prochaine mesure
}

Vidéo

Pour terminer, voici une courte vidéo montrant le tracé du plan cartésien en temps réel.



Yves Pelletier   (TwitterFacebook)


vendredi 7 décembre 2018

Présentation d'une mesure analogique sur écran Nokia 5110 (Arduino)

Après avoir exploré les différentes possibilités offertes par les bibliothèques PCD8544 et GFX d'Adafruit pour piloter un écran Nokia 5110 avec un Arduino, nous pouvons maintenant mettre en pratique nos connaissances afin de produire une application spécifique: l'affichage de la tension reçue à une des entrées analogiques de l'Arduino sous la forme d'un nombre ainsi que d'une jauge linéaire.


(Dans cet autre article, le sketch a été adapté pour un écran OLED SH1106 I2C).

Montage

L'écran Nokia est branché à l'Arduino de la même façon que dans mon article précédent (je vous invite à vous y référer pour plus de détails).  Un circuit intégré 4050 est utilisé pour abaisser à 3,3 V les signaux logiques produits par les sorties de l'Arduino, afin de respecter la fiche technique du contrôleur PCD8544.

En résumé:

  • La broche SCE de l'afficheur reçoit le signal provenant de la broche 4 de l'Arduino
  • La broche RST de l'afficheur reçoit le signal provenant de la broche 3 de l'Arduino
  • La broche D/C de l'afficheur reçoit le signal de la broche 5 de l'Arduino
  • La broche DN/MOSI de l'afficheur reçoit le signal de la broche 11 de l'Arduino
  • La broche SCLK de l'afficheur reçoit le signal de la broche 13 de l'Arduino
Pour effectuer mes tests, j'ai utilisé un potentiomètre afin de faire varier la tension appliquée à l'entrée A0 de l'Arduino. Bien entendu, vous pouvez remplacer le potentiomètre par tout autre capteur analogique (photorésistance, thermistance, etc.).  De plus, à la condition de modifier le sketch, vous pouvez remplacer le capteur analogique par un capteur numérique.



Sketch

Le sketch est plutôt simple.  À intervalles réguliers, la valeur de l'entrée analogique A0 est mesurée grâce à la fonction analogRead().

Cette valeur, qui peut varier entre 0 et 1023, est ensuite convertie en volts au moyen de la fonction map().  Vous pourrez facilement modifier le sketch si vous désirez afficher la valeur brute entre 0 et 1023, ou si vous voulez la transformer afin d'afficher autre chose qu'une tension en volts.

De plus, une jauge linéaire montre le résultat de façon graphique (il s'agit d'un mince rectangle dont la longueur horizontale est proportionnelle à la valeur mesurée).

Pour que le sketch fonctionne, il faut  avoir préalablement installé les bibliothèques Adafruit-PCD8544-Nokia-5110-LCD-library et Adafruit-GFX-Library dans votre IDE Arduino.


/*****************************************************
Affichage d'une mesure analogique sur un écran Nokia
(Arduino)
Instructions complètes:
http://electroniqueamateur.blogspot.com/2018/12/presentation-dune-mesure-analogique-sur.html
*****************************************************/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);
void setup() {
display.begin();
display.setContrast(60); // la valeur optimale dépend de votre écran (pourrait être 40)
display.clearDisplay();
}
void loop() {
int valeur;
// mesure de la tension à l'entrée A0
valeur = map(analogRead(A0), 0, 1023, 0, 500);
// on écrit "tension", en petits caractères, centré en haut de l'écran:
display.setCursor(15, 5);
display.setTextSize(1);
display.println("Tension:");
// on écrit la valeur numérique de la tension un peu plus bas, en plus gros
display.setCursor(5, 15);
display.setTextSize(2);
display.print(valeur/100); // partie entière
display.print(","); // virgule
if ((valeur % 100) < 10){
display.print("0");
}
display.print(valeur % 100); // partie décimale, après la virgules
display.println(" V"); // unités de mesure
// enveloppe de la jauge rectangulaire
display.fillRect( 4, 35, 80, 10, WHITE);
display.drawRect( 4, 35, 80, 10, BLACK);
// partie mobile de la jauge rectangulaire
display.fillRect( 6, 37, map(valeur, 0, 500, 0, 76), 6, BLACK);
display.display();
delay(500);
display.clearDisplay();
}
view raw jauge_nokia.ino hosted with ❤ by GitHub

Vidéo

Pour terminer, voici une vidéo du montage en action.



Yves Pelletier
   (TwitterFacebook)


dimanche 2 décembre 2018

Afficheur LCD Nokia 5110 et Arduino

Dans cet article, je vais tenter de vous expliquer de la façon la plus claire et complète possible comment piloter un petit écran à cristaux liquide de type "Nokia 5110" au moyen d'un Arduino Uno: vous saurez comment procéder pour brancher l'afficheur et pour programmer l'Arduino afin que l'écran affiche du texte et des images.


"Nokia 5110" est, en fait, le nom d'un modèle de téléphone portable commercialisé entre 1998 et 2001 qui utilisait ce type d'écran. Il s'agit d'un afficheur LCD monochrome associé à un contrôleur Philips PCD8544, avec une résolution de 84 X 48 pixels (sa taille réelle est de 3,5 cm par 2,5 cm environ).  Vous pouvez y afficher du texte et des dessins mais, bien entendu, ce ne sera pas de la haute résolution...

Pour faciliter les branchements avec un microcontrôleur, il existe  sur le marché deux types de breakout: le modèle rouge commercialisé par Sparkfun, et le modèle bleu commercialisé par Adafruit. Des clones de ces deux modèles sont proposés pour environ la moitié du prix par les revendeurs asiatiques. J'ai moi-même utilisé le modèle de type Sparkfun, mais vous pouvez sans problème utiliser les informations que je vous présente ici avec le modèle de type Adafruit.  Vous devrez souder vous-même une barrette de 8 connecteurs (mâles ou femelles, selon votre préférence).



Téléchargement et installation des bibliothèques

Je vous recommande l'utilisation de la bibliothèque Adafruit-PCD8544-Nokia-5110-LCD-library qui, comme son nom l'indique, a été mise au point par la compagnie Adafruit. Vous devez également installer la bibliothèque Adafruit-GFX-Library, qui comporte les routines permettant de dessiner à l'écran ("GXF" dans le sens de "graphics").

Au cas où ça vous intéresserait: il existe aussi une bibliothèque conçue par Carlos Rodrigues qui offre beaucoup moins de possibilités,  mais est moins gourmande en ressources. Ça pourrait s'avérer intéressant si vous désirez uniquement afficher du texte (caractères de 5 X 8 pixels). Je n'ai pas fait l'essai de cette bibliothèque allégée, puisque la bibliothèque proposée par Adafruit a parfaitement répondu à mes besoins.

Connexions

Mauvaise nouvelle: le pilote PCD8544 fonctionne à un niveau logique de 3,3 V.  Si vous utilisez un Arduino Uno (ou un autre modèle d'Arduino fonctionnant à un niveau logique de 5 V), il est recommandé abaisser la tension avant de l'acheminer à l'afficheur.

Bien sûr, vous trouverez sur le web tout un tas de tutoriels proposant de brancher directement les sorties 5 V de l'Arduino aux entrées 3,3 V de l'afficheur sous prétexte que les entrées de l'afficheur tolèrent les tensions de 5 V; mais ce n'est pas ce que dit le site de Sparkfun, ni celui d'Adafruit. Si vous branchez directement l'afficheur aux sorties de l'Arduino sans abaisser le niveau logique, il fonctionnera sans doute très bien, mais sa durée de vie utile pourrait être sérieusement diminuée.

J'ai donc utilisé un circuit intégré 4050, qui est spécialement conçu pour ce genre d'applications.

Voici donc le circuit complet:


Attention: le circuit illustré utilise la version Sparkfun de l'afficheur. Si vous utilisez plutôt la version Adafruit, les broches de l'afficheur ne sont pas dans le même ordre. Référez-vous plutôt aux noms des broches indiqués ci-dessous.

Alimentation:
  • La broche VCC de l'afficheur et la broche 1 du 4050 sont branchés à la sortie 3.3 V de l'Arduino.
  • La broche GND de l'afficheur et la broche 8 du 4050 sont branchés à la broche GND de l'Arduino.
Sorties de l'Arduino:
  • La broche 3 de l'Arduino est branchée à la broche 3 du 4050
  • La broche 4 de l'Arduino est branchée à la broche 5 du 4050
  • La broche 5 de l'Arduino est branchée à la broche 7 du 4050
  • La broche 11 de l'Arduino est branchée à la broche 14 du 4050
  • La broche 13 de l'Arduino est branchée à la broche 11 du 4050
(Notez que vous pouvez choisir d'autres sorties de l'Arduino si vous préférez, en faisant les changements appropriés dans le sketch. Toutefois, l'utilisation des broches 11 et 13 de l'Arduino permet une plus grande vitesse de communication avec l'afficheur).

Entrées de l'afficheur:
  • La broche SCE ou CS de l'afficheur est branchée à la broche 4 du 4050
  • La broche RST de l'afficheur est branchée à la broche 2 du 4050
  • La broche D/C de l'afficheur est branchée à la broche 6 du 4050
  • La broche DN (MOSI) ou DIN de l'afficheur est branchée à la broche 15 du 4050
  • La broche SCLK ou CLK de l'afficheur est branchée à la broche 12 du 4050
  • La broche LED de l'afficheur n'est pas branchée (je n'avais pas besoin du rétroéclairage).
En résumé, après l'abaissement du niveau logique par le 4050:
  • La broche SCE de l'afficheur reçoit le signal provenant de la broche 4 de l'Arduino
  • La broche RST de l'afficheur reçoit le signal provenant de la broche 3 de l'Arduino
  • La broche D/C de l'afficheur reçoit le signal de la broche 5 de l'Arduino
  • La broche DN/MOSI de l'afficheur reçoit le signal de la broche 11 de l'Arduino
  • La broche SCLK de l'afficheur reçoit le signal de la broche 13 de l'Arduino
Si vous n'avez pas de circuit intégré 4050 sous la main, le tutoriel de Sparkfun propose un moindre mal: insérer une résistance de protection entre les sorties de l'Arduino et l'afficheur (notez que je n'ai pas testé cette option).

Utilisation des bibliothèques:

Au début de votre sketch, lorsque vous définissez les broches de l'Arduino que vous utilisez, vous avez le choix entre deux modes:

Le mode "hardware SPI" (celui que nous avons utilisé, car il est plus rapide). Dans ce mode, les sorties 11 et 13 de l'Arduino sont nécessairement utilisées, et il ne reste qu'à indiquer le numéro des 3 autres broches (dans l'ordre: D/C, SCE ou CS , RST ):

Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);

Le mode "software SPI" (que certains préfères utiliser, si les sorties 11 et 13 sont déjà affectées à d'autres tâches). Il faut alors indiquer le numéro de toutes les broches utilisées (dans l'ordre: SCLK, DIN ou DN, D/C, SCE ou CS , RST ):

Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

De plus, il est important de bien comprendre la numérotation des pixels: la position de chaque pixel est déterminée par une coordonnée x (numéro de colonne) et une coordonnée y (numéro de ligne). La première ligne en haut de l'écran et la première colonne à gauche portent le numéro 0. Ainsi, le premier pixel en haut à gauche se trouve aux coordonnées x = 0, y = 0. Le dernier pixel en bas à droite se trouve aux coordonnées x = 83, y = 47.

Il est possible de contrôler individuellement chacun de ces 4032 pixels, mais c'est rarement nécessaire, car la bibliothèque nous offre des raccourcis utiles pour écrire du texte ou dessiner des formes géométriques à l'écran.

Lorsque vous programmez ce qui apparaîtra à l'écran, les modifications sont d'abord apportées en mémoire, dans un buffer.  Ce n'est que lorsque vous invoquez la commande display() que le contenu du buffer est transposé à l'écran.

clearDisplay() efface à la fois le contenu du buffer et de l'écran.

Écrire du texte

Pour l'écriture de texte à l'écran, on utilise les commandes "print" ou "println" comme lorsqu'on veut faire apparaître un message dans le moniteur série. Par défaut, les polices de caractère ont 5 pixels de largeur et 8 pixels de hauteur, mais on peut grossir les caractères grâce à la commande setTextSize().

       display.setCursor(5, 5);  // le texte commencera à x = 5 et y = 5
       display.setTextColor(BLACK);   // texte en noir
       display.setTextSize(2);   // taille deux fois plus grande que normal
       display.println("Bonjour");   // écriture du texte désiré.
       display.display(); // nécessaire pour que le résultat s'affiche à l'écran

Il existe également une commande qui permet d'afficher un caractère unique:

       display.drawChar(15, 5, 'A',  BLACK, WHITE, 1);

Les arguments de drawChar sont, dans l'ordre: position x, position y, caractère ASCII devant être écrit, couleur du texte, couleur du fond.   La ligne ci-dessus demande donc d'écrire la lettre A à la position x= 15 et y = 5, en noir, sur fond blanc, à la taille par défaut de 5 X 8 pixels.

Dessiner des lignes et des formes géométriques

drawPixel() permet de dessiner un pixel spécifique en noir ou en blanc:

       drawPixel(24, 12, BLACK);  // pour mettre en noir le pixel x = 24, y = 12

drawLine() permet de dessiner une ligne droite:

       display.drawLine(3, 7, 22, 30, BLACK);

(La ligne précédente permet de tracer en noir une ligne droite de la position x = 3 , y = 7 jusqu'à la position x = 22, y = 30.)

drawRect() dessine le contour d'un rectangle (l'intérieur du rectangle demeure transparent):

       display.drawRect(10, 5, 12, 16, BLACK);

(la ligne précédente dessine en noir le contour d'un rectangle dont le coin supérieur gauche se trouve à la position x = 10, y = 5, avec une largeur de 12 pixels et une hauteur de 16 pixels.)

fillRect() dessine un rectangle plein:

       display.fillRect(20, 10, 35, 13, BLACK);

(la ligne précédente dessine un rectangle entièrement noir dont le coin supérieur gauche se trouve à la position x = 20, y = 10, avec une largeur de 35 pixels et une hauteur de 13 pixels.)

drawCircle() dessine le contour d'un cercle:

       display.drawCircle(32, 18, 12, BLACK);

(la ligne précédent dessine en noir le contour d'un cercle dont le centre se trouve à la position x = 32, y = 18, de 12 pixels de rayon).

Avec les mêmes paramètres, fillCircle() dessine un cercle plein.

Pour dessiner un rectangle aux coins arrondis, on utilise drawRoundRect() ou fillRoundRect():

       display.fillRoundRect(8, 12, 43, 17, 6, WHITE);

(la ligne précédente trace un rectangle aux coins arrondi dont le coin supérieur gauche se trouve à la position x = 8, y = 12, de 43 pixels de large et 17 pixels de haut. Les cercles de coin ont un rayon de 6 pixels, et le rectangle est tout blanc (on suppose qu'il est tracé sur fond noir).)

On peut également dessiner un triangle avec drawTriangle() ou fillTriangle():

       display.drawTriangle(5, 31, 10, 18, 34, 25, BLACK);

(la ligne précédente trace le contour d'un triangle dont les 3 coins se trouvent aux positions x= 5, y = 31 , x = 10, y = 18, et x = 34, y = 25).

Afficher une image bitmap

Finalement, la fonction drawBitmap() permet d'afficher à l'écran une image bitmap préalablement stockée en mémoire:

       display.drawBitmap(20, 0, myBitmap, 34, 48, BLACK);

(la ligne précédente dessine l'image stockée dans la variable myBitmap. Il s'agit d'une image de 34 pixels de largeur et de 48 pixels de hauteur, et son coin supérieur gauche doit se situer à la position x = 20, y = 0.)

Encore faut-il définir cette image sous la forme d'octets qui indiquent la couleur (noir ou blanc) de 8 pixels adjacents sur l'écran.  Heureusement, il existe des outils qui permettent de transformer l'image d'un fichier (bmp, jpeg ou autre) en un tableau prêt à être utilisé dans votre programme.

À cet effet, je vous recommande l'outil en ligne image2ccp.

Vous sélectionnez d'abord le fichier contenant l'image que vous désirez afficher.


Vous réglez ensuite différents paramètres (taille désirée, etc).


Vous sélectionnez le type de code désiré ("Arduino code, single bitmap"), choisissez le nom désiré pour la variable, puis cliquez sur le bouton "Générate code": il ne reste plus qu'à copier le résultat et le coller dans votre sketch Arduino!



Sketch d'exemple

Voici un sketch dans lequel j'utilise tout ce qui a été mentionné dans cet article.

/*********************************************************************
Démonstration d'un écran Nokia 5110 avec un Arduino,
en utilisant les bibliothèques conçues par Adafruit:
https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library
https://github.com/adafruit/Adafruit-GFX-Library
Instructions complètes:
http://electroniqueamateur.blogspot.com/2018/12/afficheur-lcd-nokia-5110-et-arduino.html
*********************************************************************/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
Adafruit_PCD8544 display = Adafruit_PCD8544(5, 4, 3);
// D/C broche 5,CSE ou CS broche 4, RST broche 3
/* Définition d'une image bitmap: logo du blog Électronique en Amateur
Réalisée avec l'outil en ligne http://javl.github.io/image2cpp/ */
const unsigned char myBitmap [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0xf0, 0x00, 0x00, 0x03, 0x9f, 0xff, 0xe0, 0x00, 0x07,
0x9f, 0xff, 0xfe, 0x00, 0x0f, 0xdf, 0x0f, 0xbe, 0x00, 0x1f, 0xde, 0x06, 0x0e, 0x00, 0x3f, 0xdc,
0x04, 0x0e, 0x00, 0x3f, 0xdc, 0x00, 0x06, 0x00, 0x3f, 0xdc, 0x00, 0x06, 0x00, 0x3f, 0xdc, 0x60,
0x06, 0x00, 0x3f, 0xdc, 0xf1, 0x8e, 0x00, 0x3f, 0xdc, 0xf3, 0xce, 0x00, 0x3f, 0xde, 0x63, 0xde,
0x00, 0x3f, 0xdf, 0x09, 0x9e, 0x00, 0x3f, 0xdf, 0xfc, 0x7e, 0x00, 0x3f, 0xde, 0x7f, 0xfe, 0x00,
0x3f, 0xde, 0x7f, 0xf6, 0x00, 0x3f, 0xdf, 0x3f, 0xe6, 0x00, 0x3f, 0xdf, 0x8f, 0x8e, 0x00, 0x3f,
0xdf, 0xe0, 0x3e, 0x00, 0x3f, 0x00, 0x3f, 0xfe, 0x00, 0x3e, 0xff, 0xc0, 0x1e, 0x00, 0x3d, 0xff,
0xff, 0xc0, 0x00, 0x3b, 0xff, 0xff, 0xfe, 0x00, 0x37, 0xff, 0xff, 0xfe, 0x00, 0x2f, 0xff, 0xff,
0xfe, 0x00, 0x0e, 0x1f, 0xff, 0xfe, 0x00, 0x1f, 0x9f, 0x9f, 0xfe, 0x00, 0x3f, 0x9f, 0x9f, 0x9e,
0x00, 0x3f, 0x9f, 0x9f, 0x9e, 0x00, 0x3f, 0x9f, 0x9f, 0x9e, 0x00, 0x3f, 0x9f, 0x9f, 0x9c, 0x00,
0x1f, 0x9f, 0x9f, 0x98, 0x00, 0x0f, 0x9f, 0x9f, 0x90, 0x00, 0x07, 0x9f, 0x9f, 0x90, 0x00, 0x00,
0x9f, 0x9f, 0x90, 0x00, 0x00, 0x9f, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91,
0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91,
0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90, 0x00, 0x00, 0x91, 0x91, 0x90,
0x00, 0x00, 0xf1, 0xd1, 0x90, 0x00, 0x00, 0x01, 0xc1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00
};
void setup() {
display.begin(); // initialisation de l'afficheur
display.setContrast(60); // réglage du contraste (40-60) variable selon votre écran
display.clearDisplay(); // ça efface à la fois le buffer et l'écran
}
void loop() {
/**************** Éxcriture de texte ***************/
// taille par défaut
display.setCursor(10, 5); // coordonnées du point de départ du texte
display.setTextColor(BLACK);
display.setTextSize(1); // taille par défaut
display.println("Petit...");
display.display(); // affichage à l'écran
delay(1000);
// deux fois plus gros
display.setCursor(10, 25); // coordonnées du point de départ du texte
display.setTextSize(2); // taille double
display.println("GROS!");
display.display(); // affichage à l'écran
delay(1000);
display.clearDisplay(); // on efface tout
/************* Remplir tout l'écran d'un fond noir ********************/
display.fillScreen(BLACK);
display.display();
delay(1000);
/************** Écriture d'un caractère ********************************/
display.drawChar(15, 5, 'A', WHITE, BLACK, 2);
display.display();
delay(1000);
display.drawChar(35, 15, 'B', WHITE, BLACK, 2);
display.display();
delay(1000);
display.drawChar(55, 25, 'C', WHITE, BLACK, 2);
display.display();
delay(1000);
display.clearDisplay();
/******************** Dessiner une ligne ******************************************/
// ligne horizontale au centre de l'écran
display.drawLine(0, display.height() / 2, display.width() , display.height() / 2, BLACK);
// ligne verticale au centre de l'écran
display.drawLine(display.width() / 2, 0, display.width() / 2, display.height(), BLACK);
/********************* Dessiner des contours de formes géométriques ******************/
display.drawRect( 8, 5, 25, 15, BLACK); // contour d'un rectangle
display.drawCircle(60, 10, 8, BLACK); // contour d'un cercle
display.drawRoundRect(5, 30, 30, 16, 5, BLACK); // contour d'un rectangle à coins arrondis
display.drawTriangle(65, 30, 50, 45, 80, 45, BLACK); // contour d'un triangle
display.display();
delay(2000);
display.clearDisplay();
/******************* Dessiner des formes géométriqeus pleines *************************/
// Grand rectangle noir aux coins arrondis
display.fillRoundRect(2, 2, display.width() - 4, display.height() - 4, 10, BLACK);
display.display();
delay(1000);
// cercle blanc dans le rectangle noir aux coins arrondis
display.fillCircle(display.width() / 2, display.height() / 2, 20, WHITE);
display.display();
delay(1000);
// petit triangle noir dans le cercle blanc
display.fillTriangle(display.width() / 2 - 14, display.height() / 2 + 10, display.width() / 2 + 14, display.height() / 2 + 10, display.width() / 2, display.height() / 2 - 14, BLACK);
display.display();
delay(1000);
// petit rectangle blanc dans le triangle noir:
display.fillRect( display.width() / 2 - 4, display.height() / 2 , 8, 8, WHITE);
display.display();
delay(2000);
display.clearDisplay();
/********************** Dessiner un pixel à la fois ***********************************************/
// on trace une fonction sinusoidale, point par point
for (int x = 1; x < 84; x++) {
int y = 24 + round(16.0 * sin(x / 5.0));
display.drawPixel(x, y, BLACK);
}
display.display();
delay(2000);
display.clearDisplay();
/**************************** Dessiner une image bitmap **********************************/
// on affiche l'image stockée dans la constante myBitmap définie au début de ce fichier.
display.drawBitmap(20, 0, myBitmap, 34, 48, BLACK);
display.display();
delay(2000);
display.clearDisplay();
}
view raw demo_Nokia.ino hosted with ❤ by GitHub

Résultat

Finalement, une courte vidéo montrant l'afficheur pendant l'exécution du sketch.




(NB: Dans cet autre article, un sketch similaire a été produit pour un écran OLED SH1106 I2C).

Yves Pelletier   (TwitterFacebook)


dimanche 25 novembre 2018

Deux cahiers d'activités avec mBlock

Je vous présente aujourd'hui deux livres qui proposent à un jeune public des activités d'initiation à la programmation, à l'électronique et à la robotique au moyen du logiciel mBlock: Arduino pour les kids, par Frédéric Pain, et 36 activités avec le robot mBot, par Dominique Nibart.

mBlock est un logiciel qui permet de programmer un microcontrôleur (Arduino, micro:bit, mBot, etc.)  en utilisant le langage Scratch: il s'agit de faire glisser à l'écran des blocs représentant des bouts de programme, et de les imbriquer de façon à obtenir un programme complet. Puisque l'utilisateur n'a pas à apprendre la syntaxe du langage, il s'agit d'une façon simple et amusante d'initier les écoliers à la programmation.

(Je n'ai encore jamais eu l'occasion d'expérimenter mBlock, mais je vous ai déjà parlé de S4A et de Blockly@rduino, qui sont similaires).



Arduino pour les Kids
par Frédéric Pain
Publié par Eyrolles en 2018
64 pages

Ce petit livre a pour objectifs d'initier les écoliers de 8 ans et plus aux bases de la programmation et de l'électronique. En programmant une carte Arduino au moyen de mBlock, ils apprennent à faire clignoter une LED et à faire varier sa luminosité, à lire un potentiomètre ou une photorésistance, mesurer une température, etc.  Comme il se doit, les activités sont amusantes (déplacer un personnage animé au moyen d'un joystick, par exemple).

Des encadrés (dont la lecture n'est pas obligatoire pour réaliser les activités) présentent des explications supplémentaires pour mieux comprendre le comportement des circuits (PWM, utilisation de la loi d'Ohm).

Bien sûr, compte tenu de la jeunesse du public cible, il ne faut pas s'attendre à l'équivalent d'un manuel complet sur l'Arduino: chacun des 7 montages présentés est extrêmement simple.  (Si vous cherchez à assouvir la soif de connaissance d'un enfant un peu plus vieux, le livre À l'aventure avec Arduino sera peut-être plus approprié).

Extrait du livre "Arduino pour les kids" en format pdf


36 activités avec le robot mBot
par Dominique Nibart
Publié par Eyrolles en 2018
64 pages

Comme son titre l'indique, ce livre présente un grand nombre d'activités à réaliser avec le robot mBot. Il s'adresse au élèves du primaire, des collèges et des lycées.

mBot est petit robot sur roues commercialisé par la compagnie MakeBlock, et qui se programme avec au moyen du logiciel mBlock.  Il comporte une télécommande, un télémètre à ultrasons et un module de détection de lignes, mais il est également possible de lui ajouter des capteurs supplémentaires.

Sans trop de surprise, on y apprendra comment programmer le robot pour qu'il se déplace en suivant une ligne ou en évitant les obstacles, mais on est également invités à lui faire accomplir des actions qui sont moins traditionnellement associées aux robots, comme jouer de la musique ou produire des animations sur une matrice de LEDs.

Le livre va droit au but, sans digressions inutiles: la plupart des projets sont présentés en une seule page comportant un bref paragraphe d'introduction, un résumé de l'algorithme et le programme lui-même (généralement très court, puisqu'il s'agit d'accomplir une action spécifique).

Extrait du livre "36 activités avec le robot mBot" en format pdf.

Yves Pelletier   (TwitterFacebook)

mardi 6 novembre 2018

Kit: oscilloscope de poche DSO150


Aujourd'hui, je vous glisse quelques mots concernant un oscilloscope de poche DSO150 acheté sous forme de kit. (Prix payé:  19 USD, frais de port inclus.)

Le kit est constitué de deux cartes sur lesquelles de nombreux composants montés en surface on déjà été soudés, d'une douzaine de composants traversants à souder soi-même, d'un boîtier en plastique, de câbles pour la prise de mesure et d'un manuel d'instructions.

Pour fonctionner, l'oscilloscope nécessite toutefois une alimentation en courant continu de 9 V, et cette dernière n'est pas fournie.




Le manuel d'instructions est assez bien fait: les photographies en couleur sont très claires, et l'anglais est tout à fait compréhensible.  Le seul inconvénient (mineur), c'est qu'il y a une seule version du manuel pour les deux versions possibles du kit: celle où on doit aussi souder les composants montés en surface, et celle où les composants montés en surface sont déjà soudés. Certaines étapes sont donc superflues lorsqu'on a la version la plus simple du kit. Le manuel prétend aussi que nous devons nous-mêmes souder 15 résistances et 4 condensateurs céramique sur la carte analogique alors que dans mon kit, tout ça était déjà installé.



Après avoir vérifié le fonctionnement correct de l'écran couleur, on soude 8 composants sur la carte principale: le connecteur pour le signal de test, un connecteur d'alimentation secondaire (qui deviendra inaccessible lorsque nous aurons assemblé le boîtier!), un interrupteur marche/arrêt, une barrette de 4 broches (qui servira plus tard à brancher le codeur rotatif), et 4 gros boutons poussoirs.  De plus, il faut retirer la résistance R30, dont l'unique fonction a été de nous permettre de vérifier le bon fonctionnement de l'écran avant d'avoir soudé l'interrupteur marche/arrêt.





Nous passons ensuite à la carte analogique. Nous devons y souder trois condensateurs électrolytiques, un commutateur à 3 positions (AC-DC-GND), le connecteur BNC qui nous permettra de prendre des mesures et une barrette comportant deux rangées de 5 broches (ces broches feront le lien entre la carte principale et la carte analogique).



Ensuite, on soude le codeur rotatif sur la petite carte qui lui est destinée...



...qu'on visse et soude à la carte principale.


Roulement de tambour...c'est le moment de vérifier que toutes nos soudures sont bien réussies: on assemble la carte analogique à la carte principale (en insérant les 10 broches mâles de la carte analogique dans les 10 connecteurs femelles de la carte principale), on allume l'appareil, on place le commutateur en position GND, et on mesure la tension à 8 endroits. Si les tensions mesurées correspondent à celles qui sont indiquées à l'étape 4 des instructions, tout va bien et l'assemblage est presque terminé.  Sinon, on révise nos soudures... (à la toute fin du manuel, la section "troubleshooting" indique la cause probable de chaque mauvaise mesure).


Il y a aussi deux condensateurs variables C3 et C5 qu'on doit ajuster avec un petit tournevis pour éviter une déformation du signal à l'écran.

Il ne reste plus qu'à assembler le boîtier...



... et notre oscilloscope est prêt à être utilisé!

L'utilisation est assez simple: pour ajuster l'échelle de l'ordonnée, on appuie sur le bouton V/DIV, et on tourne le codeur rotatif. Pour ajuster l'échelle de l'abscisse, on appuie sur le bouton SEC/DIV et on tourne le codeur rotatif.  Le bouton TRIGGER permet de modifier le mode de déclenchement horizontal, et le bouton OK permet de figer l'affichage pour que ça cesse de bouger.  Si on appuie au moins 3 secondes sur le bouton OK, une liste de paramètres numériques apparaissent à l'écran:



Parmi les points forts de l'oscilloscope, nous pouvons citer:
  • son prix!
  • sa petite taille (la nécessité de lui adjoindre une alimentation 9 V le rend un tout petit peu moins portable, mais ce truc demeure tout de même plus petit qu'on multimètre!)
  • sa facilité d'utilisation
  • la possibilité de mesurer un signal d'une amplitude maximale de 50 V
  • le plaisir de participer à la construction de l'appareil, même s'il faut bien admettre que l'essentiel du travail avait déjà été accompli en usine.


Mais soyons réaliste,  il ne s'agit aucunement d'un appareil de mesure destiné aux professionnels. Parmi les inconvénients notables:
  • la bande passante de 200 kHz en fait un appareil plutôt lent. C'est acceptable si on désire visualiser un signal PWM ou un signal de fréquence audible, mais ça peut devenir un inconvénient important pour des signaux plus rapides.
  • Il n'y a qu'un seul canal, on ne peut donc y brancher qu'une seule sonde. Bien difficile, donc, de comparer entre eux deux signaux différents, mesurer un déphasage, etc.
  • L'écran est très, très petit.
  • Je ne suis pas convaincu que les petits interrupteurs à glissière pourront tenir le coup éternellement (bien sûr, je pourrai les remplacer au besoin).
Donc, un gadget utile pour certaines applications, mais qui ne doit pas être considéré comme l'équivalent d'un véritable oscilloscope de bonne qualité.  Si vous n'avez pas les moyens de vous procurer un tel oscilloscope, c'est certainement mieux que rien du tout...

Yves Pelletier   (TwitterFacebook)

dimanche 4 novembre 2018

ESP8266 ou ESP32 et afficheur LCD 16 X 2

Lorsque vous créez un objet connecté au moyen d'un  ESP8266 ou d'un ESP32, il est parfois utile que votre dispositif soit en mesure d'afficher un court message de façon autonome, ne serait-ce que pour indiquer que sa tentative de connexion au réseau WiFi n'a pas fonctionné, pour afficher son adresse IP, etc.

C'est pourquoi je vous présente aujourd'hui un court article sur le contrôle d'un afficheur à cristaux liquides 16 X 2 basé sur le contrôleur Hitachi HD44780, au moyen d'un module ESP8266 ou ESP32.


Préparation de l'IDE Arduino

Nous allons programmer l'ESP au moyen de l'IDE Arduino. Les fichiers nécessaires à la programmation de ce module doivent donc avoir été ajoutés au moyen du gestionnaire de cartes du logiciel; pour plus d'informations à ce sujet, voir voir cet article pour l'ESP8266 ou celui-ci pour l'ESP32.

Connexions

L'afficheur LCD occupe 6 broches de l'ESP, sans compter l'alimentation. Assurez-vous d'utiliser un afficheur qui accepte de fonctionner à un niveau logique de 3,3 V, car ce n'est pas toujours le cas.  De plus, si vous programmez le module avec un convertisseur USB-série, il est très important qu'il s'agisse d'un modèle fonctionnant sous 3,3 V, et non 5 V.

Les 16 broches de l'afficheur LCD sont connectées de la façon suivante:
  • Broche 1 de l'afficheur (VSS): GND
  • Broche 2 de l'afficheur (VDD): 3,3 V
  • Broche 3 de l'afficheur (contraste): potentiomètre variant de 0 à 3,3 V.
  • Broche 4 de l'afficheur (RS): broche GPIO4 de l'ESP8266
  • Broche 5 de l'afficheur (RW): GND
  • Broche 6 de l'afficheur (E): GPIO05 de l'ESP8266
  • Broches 7, 8, 9 et 10 de l'afficheur (D0, D1, D2, D3): pas connectées
  • Broche 11 de l'afficheur (D4): GPIO12 de l'ESP8266
  • Broche 12 de l'afficheur (D5): GPIO13 de l'ESP8266
  • Broche 13 de l'afficheur (D6): GPIO14 de l'ESP8266
  • Broche 14 de l'afficheur (D7): GPIO15 de l'ESP8266
  • Broche 15 de l'afficheur (rétroéclairage): 3,3 V
  • Broche 16 de l'afficheur: GND
Ce qui donne ce résultat avec ma carte de développement ESP32:

...et celui-ci avec une carte Wemo D1 Mini:


De plus, si vous utilisez un module ESP8266 qui n'est pas intégré à une carte de développement (genre NodeMCU ou Wemos), vous devrez, comme d'habitude, brancher ses broches VCC, RST et CH_PD (enable) à 3,3 V, et brancher ses broches GND et GPIO0 à GND. La broche TXD de l'ESP8266 se branche sur le RX du convertisseur USB-série, et la broche RXD de l'ESP8266 se branche sur le TX du convertisseur USB-série.



Sketch minimal

Bonne nouvelle: si vous avez déjà utilisé ce type d'afficheur avec une carte Arduino, ce sera exactement la même chose, puisque la bibliothèque LiquidCrystal fournie avec l'IDE Arduino est pleinement compatible avec l'ESP8266.

Voici un premier sketch qui ne fait que le strict minimum: afficher un message sur l'afficheur LCD.


/**********************************************************
Utilisation d'un afficheur LCD 16 X 2 (compatible Hitachi
HD44780 et de la bibliothèque LiquidCrystal avec l'ESP8266
ou l'ESP32.
Instructions complètes:
http://electroniqueamateur.blogspot.com/2018/11/esp8266-et-afficheur-lcd-16-x-2.html
**********************************************************/
#include <LiquidCrystal.h> // blibliotheque LiquidCrystal
// définition des broches auxquelles on a branché l'afficheur LCD
const int pinRS = 4; // broche 4 (RS) de l'afficheur branchée à GPIO04 de l'ESP8266
const int pinEnable = 5; // broche 6 (Enable) de l'afficheur branchée à GPIO05 de l'ESP8266
const int pinD4 = 12; // broche 11 (D4) de l'afficheur branchée à GPIO12 de l'ESP8266
const int pinD5 = 13; // broche 12 (D5) de l'afficheur branchée à GPIO13 de l'ESP8266
const int pinD6 = 14; // broche 13 (D6) de l'afficheur branchée à GPIO14 de l'ESP8266
const int pinD7 = 15; // broche 14 (D7) de l'afficheur branchée à GPIO15 de l'ESP8266
// Initialisation de la bibliothèque LiquidCrystal en utilisant les broches définies ci-dessus:
LiquidCrystal lcd(pinRS, pinEnable, pinD4, pinD5, pinD6, pinD7);
void setup() {
// On indique que notre afficheur comporte 2 lignes de 16 caractères:
lcd.begin(16, 2);
}
void loop() {
lcd.clear(); // on efface tout
lcd.print(" Electronique");
lcd.setCursor(0, 1); // deuxième ligne
lcd.print(" en amateur");
delay(5000);
lcd.clear(); // on efface tout
lcd.print("LCD et");
lcd.setCursor(0, 1); // deuxième ligne
lcd.print(" ESP8266");
delay(5000);
}
view raw ESP8266_LCD.ino hosted with ❤ by GitHub


Affichage d'un message éditable par une page web

Essayons maintenant un mini-projet qui utilisera un peu mieux les caractéristiques de l'ESP8266 / ESP32: le message qui sera affiché par le LCD pourra être modifié à distance au moyen d'une page web.


/**********************************************************************
ESP8266 LCD WiFi
Au moyen d'une page web, on contrôle le message affiché par un LCD
branché à un ESP8266 ou un ESP32.
Instructions complètes:
http://electroniqueamateur.blogspot.com/2018/11/esp8266-et-afficheur-lcd-16-x-2.html
***********************************************************************/
// inclusion des bibliothèques utiles
#if defined ARDUINO_ARCH_ESP8266 // s'il s'agit d'un ESP8266
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#elif defined ARDUINO_ARCH_ESP32 // s'il s'agit d'un ESP32
#include "WiFi.h"
#include <WebServer.h>
#endif
#include <WiFiClient.h>
#include <LiquidCrystal.h>
// modifiez ces deux constantes pour qu'elles contiennent les caractéristiques de
// votre réseau Wifi
#define ssid "**********" // le nom (SSID) de votre réseau WiFi
#define password "**********" // votre mot de passe WiFi
// définition des broches auxquelles on a branché l'afficheur LCD
const int pinRS = 4; // broche 4 (RS) de l'afficheur branchée à GPIO04 de l'ESP8266
const int pinEnable = 5; // broche 6 (Enable) de l'afficheur branchée à GPIO05 de l'ESP8266
const int pinD4 = 12; // broche 11 (D4) de l'afficheur branchée à GPIO12 de l'ESP8266
const int pinD5 = 13; // broche 12 (D5) de l'afficheur branchée à GPIO13 de l'ESP8266
const int pinD6 = 14; // broche 13 (D6) de l'afficheur branchée à GPIO14 de l'ESP8266
const int pinD7 = 15; // broche 14 (D7) de l'afficheur branchée à GPIO15 de l'ESP8266
// Initialisation de la bibliothèque LiquidCrystal en utilisant les broches définies ci-dessus:
LiquidCrystal lcd(pinRS, pinEnable, pinD4, pinD5, pinD6, pinD7);
#if defined ARDUINO_ARCH_ESP8266 // s'il s'agit d'un ESP8266
ESP8266WebServer server(80);
#elif defined ARDUINO_ARCH_ESP32 // s'il s'agit d'un ESP32
WebServer server(80);
#endif
// Affichage initial sur le LCD
String ligne1STR = "Bonjour!";
String ligne2STR = ":)";
/* La fonction construitPage retourne un string qui contient toute notre page web */
String construitPage() {
String bouton1Str, bouton2Str;
String page = "<html lang=fr-FR><head>";
page += "<title>ESP8266 Afficheur WiFi</title>";
page += "<style> body { background-color: #fffff; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }</style>";
page += "</head><body><h1>ESP8266 Afficheur WiFi</h1>";
page += "<form action='/' method='POST'>";
page += "<h3>&Eacute;crivez ci-dessous le message &agrave; afficher:</h3>";
page += "<p>Ligne 1:</p>";
page += "<p><INPUT type='text' name='ligne1' value='" + ligne1STR + "'></p>";
page += "<p>Ligne 2:</p>";
page += "<p><INPUT type='text' name='ligne2' value='" + ligne2STR + "'></p>";
page += "<INPUT type='submit' value='Appliquer'><br><br>";
page += "</body></html>";
return page;
}
/* La fonction gestionPage modifie les caractéristiques du moteur si le bouton
Appliquer a été cliqué. */
void gestionPage() {
if ( server.hasArg("ligne1") ) {
ligne1STR = server.arg("ligne1");
ligne2STR = server.arg("ligne2");
// Affichage sur le moniteur série, pour débogage
Serial.print("Commande recue. Message: ");
Serial.println(ligne1STR);
Serial.println(ligne2STR);
// mise à jour de l'afficheur LCD
lcd.clear();
lcd.print(ligne1STR);
lcd.setCursor(0, 1); // deuxième ligne
lcd.print(ligne2STR);
}
server.send ( 200, "text/html", construitPage() );
}
void setup() {
lcd.begin(16, 2);
lcd.print(ligne1STR);
lcd.setCursor(0, 1); // deuxième ligne
lcd.print(ligne2STR);
// pour affichage dans le moniteur série (utile pour le débogage)
Serial.begin ( 115200 );
// initialisation de la communication WiFi
WiFi.begin ( ssid, password );
while ( WiFi.status() != WL_CONNECTED ) {
delay ( 500 ); Serial.print ( "." );
}
Serial.println ( "" );
Serial.print ( "Maintenant connecte a " );
Serial.println ( ssid );
Serial.print ( "Adresse IP: " );
Serial.println ( WiFi.localIP() );
// On indique le nom de la fonction qui gère l'interraction avec la page web
server.on ( "/", gestionPage );
server.begin();
Serial.println ( "Serveur HTTP en fonction" );
}
void loop() {
server.handleClient();
delay(1000);
}

Au démarrage du sketch, l'ESP8266 se connecte au réseau WiFi et son adresse IP s'affiche dans le moniteur série de l'IDE Arduino.  Il s'agit de coller cette adresse IP dans le navigateur web d'un appareil (ordinateur ou téléphone) branché au même réseau local pour faire apparaître une page web générée par l'ESP8266.


Vous écrivez un message dans les champs de texte de la page web (un champ pour chaque ligne du LCD) et, lorsque vous cliquez sur le bouton "Appliquer", le message s'affiche sur le LCD.

Yves Pelletier   (TwitterFacebook)