Exemples de codes Arduino, avec schémas associés

° ex0010_blink_pin13_digitalWrite.ino
Un programme basique qui fait clignoter la LED connectée sur la PIN 13.
° ex0020_blink_pin13_12_11.ino
Un programme qui fait clignoter les LEDs connectées sur les PINs 13, 12 et 11, à des rythmes différents.
° ex0030_attenue_pin11_pause.ino
Un programme qui fait varier l'intensité de la LED connectée à la PIN 11.
° ex0040_lecture_bouton.ino
Lecture de l'état d'un bouton, pressé ou non, relié à la PIN 12.
° ex0050_lecture_bouton_Serial_print.ino
Un programme qui lit l'état un bouton et l'affiche dans le moniteur série.
° ex0051_lecture_bouton_Serial_print_ameliore.ino
Un programme qui améliore le précédent.
° ex0052_lecture_bouton_Serial_print_ameliore_bis.ino
Un programme qui améliore plus le précédent.
° ex0055_lecture_bouton_frequence_variable.ino
Deux boutons permettent de faire varier la fréquence de clignotement d'une LED.
Une amélioration est faite dans l'exemple : ex0085_lecture_bouton_frequence_variable_ameliore
° ex0060_lecture_Serial_read.ino
Lecture du port série.
° ex0070_lecture_analogique_resistance_variable.ino
Lecture d'une tension sur le port analogique A0.
° ex0080_temps_bouton_presse.ino
Mesure le temps en micro secondes durant lequel un bouton est pressé.
° ex0085_lecture_bouton_frequence_variable_ameliore.ino
Deux boutons permettent de faire varier la fréquence de clignotement d'une LED.
C'est une amélioration du programme : ex0055_lecture_bouton_frequence_variable.ino
° ex0090_lecture_analogique_photo_resistance.ino
Lecture de luminosité en utilisant une photo-résistance.
° ex0100_mesure_temps_aide_photo_resistance.ino
Mesure de temps en utilisant une photo-résistance.
° ex0110_photo_resistance_lien_analogique_digital.ino
Test de lien entre une mesure Analogique et Digitale, d'une tension.
° ex0120_buzzer_avec_photo_resistance.ino
Un buzzer émet un son à une fréquence dépendante de la lumière arrivant sur une photo-résistance.
° ex0125_liquidCrystal_Simple_Hello_World.ino
L'afficheur LCD HD44780 de 2 lignes de 16 caractères.
° ex0126_mesure_temperature_DS18B20.ino
Mesure de température avec une précision de 0,5 à 0,25 °C, en utilisant le chip DS18B20.
Voir aussi l'ex0127, avec affichage sur un écran LCD.
° ex0127_liquidCrystal_Temperature_measure.ino
Comme l'ex0125, affichage sur un écran LCD.
En plus, comme l'ex0126, lit la température.
Ensuite, la température est affichée sur l'écran LCD.
Mesure de température avec une précision de 0,5 à 0,25 °C, en utilisant le chip DS18B20.
° ex0130_liquid_crystal_hello_world.ino
Test l'afficheur LCD (à cristaux liquides) de deux lignes de 16 caractères.
La lecture des boutons est lente (5 millisecondes), mais faite en un seul appel.
Je préfère la version suivante, "ex0131".
° ex0131_liquid_crystal_hello_world.ino
Test l'afficheur LCD (à cristaux liquides) de deux lignes de 16 caractères.
La lecture des boutons est rapide (100 microsecondes), mais faire en plusieurs appels de la fonction de lecture d'état des boutons. C'est pratique pour les programmes sensible au temps, tels que les générateurs de fréquence.
° ex0140_Frequences_HP_Menu_LiquidCrystal.ino
Pour faire vibrer un H.P. a une fréquence précise, de quelques dizaines ou centaines de Hz.
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
° ex0142_Menu_Do_Re_Mi_Fa_Sol.ino
Joue les notes : "Do Re Mi Fa Sol La Si Do".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
° ex0143_Menu_Jai_du_bon_tabac.ino
Joue la mélodie : "J'ai du bon tabac dans ma tabatière".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
Utilisation de tableaux, pour mémoriser la suite de notes à jouer.
Utilisation d'un pointeur sur le tableau contenant la mélodie désirée.
° ex0150_LED_Matrix.zip
Pour afficher des symboles sur des matrices de LED.
Le programme est assez complexe et conporte 5 fichiers.
° ex0161_Tachimetre_Stroboscope_LiquidCrystal.ino
Tachimètre infrarouge et stroboscope adapté à la fréquence mesurée par le Tachimètre.
° ex0220_ultrasonic_sensor_HC_SR04.ino
Émetteur - récepteur ultrason, pour mesurer des distances.
° ex380_moteur_pas_a_pas.ino
Un premier exemple de pilote de moteur pas à pas, utilisant la librairie standard.
Il est conseillé de prendre l'exemple suivant, le "ex381_moteur_pas_a_pas", qui est meilleur.
° ex381_moteur_pas_a_pas.ino
Une meilleure version de pilote de moteur pas à pas, utilisant la librairie "AccelStepper", qu'il faut télécharger du site AccelStepper.
Plus précisément, il faut télécharger le fichier : AccelStepper-?.??. Les ? changeront avec le temps.
Voici une bonne référence (en anglais).
° ex0385_moteur_pas_a_pas__LiquidCrystal.ino
Utilisation d'un circuit L293 pour piloter un moteur pas à pas bipolaire. (Moteur 28BYJ-48)
Vu que le code est long, il est caché par défaut.


La suite se trouve dans une autre page Web

° ex0400_timer_2_interrupt.ino
Un petit exemple d'utilisation du timer du ATmega328 de l'Arduino, pour qu'il génère des "interrupt", qui accèdent régulièrement à une fonction.
° ex0401_timer_2_interrupt.ino
Exemples d'utilisations du timer du ATmega328 de l'Arduino, pour modifier les fréquences et temps à l'état haut des 6 pins PWM (Pulse Width Modulated) liés à la commande "analogWrite(...)".
° ex0405_timer_2_interrupt.ino
Exemple d'utilisation du timer 2 pour générer des interruptions.
La fréquence de clignotement de la LED pin 13 va augmenter avec le temps.
° ex0406_timer_2_interrupt.ino
Exemples d'utilisations du timer 2 du ATmega328 de l'Arduino, pour générer une rampe en fréquence sur la pin 13.
° ex0440_Menu_LiquidCrystal_vitesses_tests.ino
Mesures de temps d'exécution de diverses instructions.
La mesure n'est pas précise, car elle utilise la fonction "micros()".
Les exemples suivantes, "ex0441" et "ex448", feront des mesures beaucoup plus précises, car elles utilisent le registre TCNT1 qui compte le temps au cycle d'horloge près.
Il y a 16'000'000 cycles d'horloge par seconde.
Utilise l'afficheur LCD 1602 avec 5 boutons, pour afficher les résultats et choisir la mesure désirée.
Permet également de voir à quelle valeur de l'ADC0 est attaché chaque bouton.
° ex0441_DigitalWrite_speed.ino
Mesures de temps d'exécution de la fonction "DigitalWrite".
La mesure est précise, car elle utilise le registre TCNT1 qui compte le temps au cycle d'horloge près.
Il y a 16'000'000 cycles d'horloge par seconde.
Affichage de résultats des mesures dans le moniteur série.
° ex0448_Menu_LCD_vitesses_tests.ino
Mesures de temps d'exécution de diverses instructions.
Les mesures sont précises, car elles utilisent le registre TCNT1 qui compte le temps au cycle d'horloge près.
Il y a 16'000'000 cycles d'horloge par seconde.
Utilisation de l'afficheur LCD 1602 avec 5 boutons. Utilisation d'un menu pour sélectionner le test à faire.
Indique également la valeur de l'ADC0 associé à chaque bouton.
° Commentaires et informations sur le Timer 1, utile pour la suite.
Ce sont des commentaires généraux, valident pour les exemples ex0450 à ex0464 qui suivent.
° ex0450_timer_1_interrupt.ino
Exemple d'utilisation du timer 1 pour générer des interruptions à des fréquences variables.
Utilise un Arduino Mega.
L'exemple suivant est meilleur. La méthode utilisée dans cet exemple n'est pas conseillée.
° ex0451_timer_1_interrupt_OCR1A.ino
Exemple d'utilisation du timer 1 pour générer des interruptions à des fréquences variables.
Utilisation du registre OCR1A pour bien contrôler les intervalles de temps entre deux interruptions.
La fréquence d'oscillation de la pin 13 va augmenter avec le temps, puis diminuer et recommencer.
La mémoire des variables est presque entièrement utilisée.
C.f. l'ex0452 suivant, qui utilise l'instruction PROGMEM pour stocker un tableau de valeurs constantes dans la mémoire du programme.
° ex0452_timer_1_interrupt_OCR1A_PROGMEM.ino
Similaire à l'ex0451, qui a le défaut d'utiliser presque toute la mémoire RAM pour stocker un tableau.
Cet exemple utilise l'instruction PROGMEM pour stocker un tableau de valeurs constantes dans la mémoire du programme.
Cela libère la RAM de stockage des variables.
Exemple d'utilisation du timer 1 pour générer des interruptions à des fréquences variables.
Utilisation du registre OCR1A pour bien contrôler les intervalles de temps entre deux interruptions.
La fréquence d'oscillation de la pin 13 va augmenter avec le temps, puis diminuer et recommencer.
° ex0453_timer_1_interrupt_OCR1A_PROGMEM_LED.ino
Similaire à l'ex0452.
Utilise l'instruction PROGMEM pour stocker un tableau de valeurs constantes dans la mémoire du programme.
Utilisation de l'afficheur LCD1602 pour indiquer la fréquence générée.
° ex0460_timer_1_interrupt_OCR1A_LCD.ino
Utilisation du timer 1 pour générer des fréquences sur les pins 2 et 3 de l'arduino.
Utilisation du timer 0 pour des mesures de temps.
Utilisation de l'afficheur LCD 1602 avec les 5 boutons, pour avoir un menu qui sélectionne la fréquence désirée.
Un menu permet d'augmenter la fréquence par 24e d'octave.
Utilise des instructions de bas niveau, pour accéder plus rapidement aux ports de l'Arduino et pour lire la valeur de l'ADC0, sans attendre les 100 micro-secondes de temps de conversion.
° ex0462_timer_1_interrupt_LCD_sinus.ino
Utilisation des mêmes techniques que dans l'ex0460, avec comme objectif de générer un signal sinusoïdal, juste en chargeant - déchargeant un condensateur ou en maintenant constant sa tension en mettant sous haute impédence la pin 3 qui lui est reliée.
Les commentaires du code explique comment cela est obtenu.
° ex0463_timer_1_interrupt_digital_oscillo_LCD.ino
Utilisation du timer 1 pour générer des fréquences sur les pins 11 et 12 de l'arduino.
Utilisation du timer 0 pour des mesures de temps.
Utilisation de l'afficheur LCD 1602 avec les 5 boutons, pour avoir un menu qui sélectionne les fréquences désirées.
Utilise des instructions de bas niveau, pour accéder plus rapidement aux ports de l'Arduino et pour lire la valeur de l'ADC0, sans attendre les 100 micro-secondes de temps de conversion.
Voir les commentaire de l'ex0464, qui est une version plus complète et mieux aboutie de génération d'une paire de fréquence ajustable.
° ex0464_timer_1_interrupt_digital_oscillo_LCD.ino
Extension de l'ex0463, avec des améliorations, version plus aboutie.
Si on utilise le schéma de l'ex0460 avec le haut-parleur et les bons branchements, deux cas limites sont intéressants à étudier.
1) Vers les basses fréquences, entre 10 et 80 [Hz], expérimenter à partir de quelle fréquence on endent un son continu et non des TACs distincts.
2) En augmentant la fréquence de 1'000 à 20'000 [Hz], à partir de quelle fréquence on entent plus rien.
Cela dépend beaucoup de l'âge de la personne qui écoute.
Les jeunes entendent jusqu'à entre 17'000 et 20'000 [Hz], des personnes âgées n'entendent plus rien au delà de 10'000 [Hz].
Par défaut, les fréquences ne sont pas affichées, car l'utilisation est destinées à des élèves qui apprennent à manier un oscilloscope.
En introduisant le bon code dans le bon menu, les fréquences apparaîssent.


Voir aussi :
°   Exemples du site de référence.
°   Exemples déjà codés dans l'interface Arduino (Build in examples).
°   Contôle de moteur pas à pas (Stepper motor). C'est un début, mais le lien suivant est bien meilleur !
Au lieu du "SN754410ne H-Bridge", on peut utiliser un L293 ou un L298.
28BYJ48 Stepper Motor Information très bonne.
28BYJ48 Stepper Motor information sur un moteur pas à pas courant pour l'Arduino.
28BYJ48 Stepper Motor autre information sur le même moteur.
°   Arduino Motor Shield.
Bonne explications en anglais de ce "shield", utilisable pour deux moteurs à courant continu (moteur électrique standard) ou un moteur pas à pas.
Lien sur le site officiel de Arduino.

Du site : astenor.free.fr/Arduino/, plusieurs exemples du "Starter Kit Arduino" :
  9.  Moulinet motorisé, montre l'utisation du moteur, avec un transistor, avec code et image des branchements.
Ne permet de faire tourner le moteur que dans un sens.
10.  Zoetrope, montre l'utisation du moteur, avec le chip 293, avec code et image des branchements.
Permet de faire tourner le moteur dans les deux sens.
11.  Boule de cristal, montre l'utiisation de l'afficheur LCD, avec code et image des branchements.
12.  Serrure sonore, montre l'utisation du buzzer et du servo moteur, avec code et image des branchements.
13.  Lampe tactile, montre l'utisation d'un effet capacitif pour allumer ou éteindre une LED, avec code et image des branchements.
15.  Piratez les boutons, montre l'utilisation d'un optocoupleur, avec code et image des branchements.

datasheetcatalog.com, pour des références sur toutes les composantes électroniques.
.

Avec la colorisation syntaxique   ...   Sans la colorisation syntaxique

    - Suivant, ex0020
ex0010_blink_pin13_digitalWrite.ino   TOP
Un programme basique qui fait clignoter la LED connectée sur la PIN 13.
Voir aussi : Arduino Blink du site de référence.
/*
ex0010_blink_pin13
Fait clignoter la LED de la PIN 13 régulièrement
*/

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
pinMode(13, OUTPUT);
} // setup

void loop() {
//===========
digitalWrite(13, HIGH);  // set LED on
delay(500);              // wait for some milliseconds
digitalWrite(13, LOW);    // set the LED off
delay(500);              // wait for some milliseconds
} // loop
ex0010 blink
ex0010_blink_pin13.ino
Le fil rouge est connecté au 5V de la carte Arduino.
Le fil noir est connecté au GND (ground) de la carte Arduino, qui représente le 0 V.
La résistance est de 150 ohms. Code couleurs : brun ; vert ; brun.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0030   ;   Précédent, ex0010
ex0020_blink_pin13_12_11.ino   TOP
Un programme qui fait clignoter les LEDs connectées sur les PINs 13, 12 et 11, à des rythmes différents.
-> Voir une version améliorée ...
/*
ex0020_blink_pin13_12_11
Fait clignoter la LED de la PIN 13 régulièrement,
la PIN 12 deux fois plus lentement,
la PIN 11 quatre fois plus lentement.
*/

void setup() {
//============
// Initialise les PINs digital 13, 12 et 11 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);

// Fait clignoter les LED en 13, 12 et 10, 15 fois à une période de 2x100=200 [ms]
for (int nn=1; nn<=15; nn++) {
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(100);
  } // for
} // setup

void loop() {
//===========
digitalWrite(13, HIGH);   // set the LED on
digitalWrite(12, HIGH);
digitalWrite(11, HIGH);
delay(500);              // wait for some milliseconds
digitalWrite(13, LOW);   // set the LED off
delay(500);              // wait for some milliseconds
digitalWrite(13, HIGH);
digitalWrite(12, LOW);
delay(500);
digitalWrite(13, LOW);
delay(500);              // wait for some milliseconds
digitalWrite(13, HIGH);
digitalWrite(12, HIGH);
digitalWrite(11, LOW);
delay(500);
digitalWrite(13, LOW);
delay(500);              // wait for some milliseconds
digitalWrite(13, HIGH);
digitalWrite(12, LOW);
delay(500);
digitalWrite(13, LOW);
delay(500);              // wait for some milliseconds
} // loop
ex0020 blink
ex0020_blink_pin13_12_11.ino : Montage similaire au précédent ex0010, avec deux LEDs de plus.


    - Suivant, ex0040   ;   Précédent, ex0020
ex0030_attenue_pin11_pause.ino   TOP
Un programme qui Fait varier l'intensité de la LED connectée à la PIN 11.
/*
ex0030_attenue_pin11_pause
Fait varier l'intensité de la LED connectée à la PIN 11,
en faisant une petite pause lorsque la PIN 11 est à 0
*/

#define pinA 11 // Définition d'une constante.

int nBrightness = 0;  // Intensité de la LED
int nFadeAmount = 1;  // Quantité de variation de l'intensité

void setup()  {
//=============
// Initialise le PIN digital pinA comme OUTPUT
pinMode(pinA, OUTPUT);
}

void loop()  {
//============
// Etablit l'intensité de la LED connectée à la PIN pinA
analogWrite(pinA, nBrightness);

// Change l'intensité de la LED
nBrightness = nBrightness + nFadeAmount;

// Si on atteint une extreme, change le sens de variation d'intensité
if (nBrightness == 0 || nBrightness == 255) {
   nFadeAmount = -nFadeAmount;

   // Si l'intensité est à son minimum, éteint la LED et attend un petit moment
   if (nBrightness == 0) {
      digitalWrite(pinA, LOW);
      delay(500);
      }
   }

// wait for 10 milliseconds to see the dimming effect
delay(10);
} // loop
ex0030 blink
ex0031_attenue_pin11_pause.ino : Ce sont presque les mêmes connections que pour l'exemple ex0010
Au lieu de connecter la LED à la PIN 13, elle est connectée à la PIN 11.


    - Suivant, ex0050   ;   Précédent, ex0030
ex0040_lecture_bouton.ino   TOP
Lecture de l'état d'un bouton, pressé ou non, relié à la PIN 12.
/*
ex0040_lecture_bouton
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, allume la LED connectée à la PIN 13 durant un instant
*/

#define pinOut 13 // Définition de constantes.
#define pinIn 12

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise la PIN digital pinIn comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinIn, INPUT);
digitalWrite(pinOut, LOW);    // set the LED off
} // setup

void loop() {
//===========
if (digitalRead(pinIn) == 1) {
  // On a pressé sur le bouton qui met la PIN pinIn à l'état haut (HIGH)
  digitalWrite(pinOut, HIGH);  // set LED on
  delay(1000);             // wait for some milliseconds
  }

digitalWrite(pinOut, LOW);    // set the LED off
delay(50); // Juste pour voir qu'elle s'éteint, meme si le bouton reste pressé
} // loop
ex0040 blink
ex0040_lecture_bouton.ino : La résistance entre le 0 V et le bouton assure que l'état par défaut du bouton est de 0 V.
Sa valeur n'est pas très importante, entre 4,7 k ohms et 10 k ohms est conseillé.
Sur l'exemple une résistance de 4,7 kohms (4700 ohms) est placée.
Code couleurs : jaune ; violet ; rouge.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0051   ;   Précédent, ex0040
ex0050_lecture_bouton_Serial_print.ino   TOP
Un programme qui lit l'état un bouton et l'affiche dans le moniteur série.
/*
ex0050_lecture_bouton_Serial_print
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, allume la LED connectée à la PIN 13 et
affiche dans le "moniteur série" (Ctrl+Maj+M) l'état de la PIN 12,
c'est-à-dire l'état "pressé" ou non du bouton.
Ce programme utilise la PIN 1 (tx) pour la communication série.
S'il y avait lecture "Serial.read()", la PIN 0 (rx) serait utilisée.

Le défaut, c'est qu'on détecte plusieurs fois que le bouton est pressé.
C.f. ex0051_lecture_bouton_Serial_print  pour une amélioration
C.f. ex0052_lecture_bouton_Serial_print  pour une meilleure amélioration
*/

#define pinOut 13 // Définition de constantes.
#define pinIn 12

int nCompteur = 0;

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise la PIN digital pinIn comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinIn, INPUT);
digitalWrite(pinOut, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (digitalRead(pinIn) == 1) {
  // On a pressé sur le bouton qui met la PIN pinIn à l'état haut (HIGH)
  digitalWrite(pinOut, HIGH);  // set LED on
  nCompteur = nCompteur + 1;
  Serial.println(nCompteur);        // rien correspond à DEC
  // "println" envoie un retour à la ligne, contrairement à "print".
  // Serial.print(nCompteur, DEC);  // sortie par défaut, sortie sous forme de string
                                    // Si nCompteur = 37,  sortie = "37", donc deux caractères
                                    // Si nCompteur = 254,  sortie = "254", donc trois caractères
  // Serial.print(nCompteur, BIN); // sortie binaire sous forme de string
  // Serial.print(nCompteur, HEX); // sortie hexadécimale sous forme de string
  // Serial.print(nCompteur, BYTE); // sortie sous forme de nombre
                              // Si bIn = 37,  sortie = 37, un nombre
  // Serial.write(nCompteur); // sortie sous forme du nombre se trouvant dans la variable
  }
else {
  digitalWrite(pinOut, LOW);    // set the LED off
  }
} // loop
ex0050 blink
ex0050_lecture_bouton_Serial_print.ino : Même schéma que pour l'exemple ex0040


    - Suivant, ex0052   ;   Précédent, ex0050
ex0051_lecture_bouton_Serial_print_ameliore.ino   TOP
Un programme qui améliore le précédent.
/*
ex0051_lecture_bouton_Serial_print_ameliore
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, allume la LED connectée à la PIN 13 et
affiche dans le "moniteur série" (Ctrl+Maj+M) l'état de la PIN 12,
c'est-à-dire l'état "pressé" ou non du bouton.
Ce programme utilise la PIN 1 (tx) pour la communication série.
S'il y avait lecture "Serial.read()", la PIN 0 (rx) serait utilisée.

Amélioration de  ex0050_lecture_bouton_Serial_print  pour une amélioration
Il y a encore le problème que parfois, une pression sur le bouton est comptée à double.
C'est typique des rebonds.
C.f. ex0052_lecture_bouton_Serial_print_amelioration_bis  pour une meilleure amélioration
*/

#define pinOut 13 // Définition de constantes.
#define pinIn 12

int nCompteur = 0;
int nEtatLast = 0; // mémorise le dernier état du bouton

void setup() {
//============
// Initialise la PIN digital pinOut comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise la PIN digital pinIn comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinIn, INPUT);
digitalWrite(pinOut, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (digitalRead(pinIn) == 1) {
  // On a pressé sur le bouton qui met la PIN pinIn à l'état haut (HIGH)
  // Test qu'il n'était pas déjà pressé avant.
  if (nEtatLast == 0) {
    nEtatLast = 1; // Mémorise qu'on a pressé sur le bouton

    digitalWrite(pinOut, HIGH);  // set LED on
    nCompteur = nCompteur + 1;
    Serial.println(nCompteur);        // rien correspond à DEC
    // "println" envoie un retour à la ligne, contrairement à "print".
    // Serial.print(nCompteur, DEC);  // sortie par défaut, sortie sous forme de string
                                      // Si nCompteur = 37,  sortie = "37", donc deux caractères
                                      // Si nCompteur = 254,  sortie = "254", donc trois caractères
    // Serial.print(nCompteur, BIN); // sortie binaire sous forme de string
    // Serial.print(nCompteur, HEX); // sortie hexadécimale sous forme de string
    // Serial.print(nCompteur, BYTE); // sortie sous forme de nombre
                                // Si bIn = 37,  sortie = 37, un nombre
    // Serial.write(nCompteur); // sortie sous forme du nombre se trouvant dans la variable
    }
  }
else { // bouton relaché
  nEtatLast = 0; // Mémorise qu'on a relaché le bouton

  digitalWrite(pinOut, LOW);    // set the LED off
  }
} // loop
ex0051 blink
ex0051_lecture_bouton_Serial_print_ameliore.ino : Même schéma que pour l'exemple ex0040


    - Suivant, ex0055   ;   Précédent, ex0051
ex0052_lecture_bouton_Serial_print_ameliore_bis.ino   TOP
Un programme qui améliore plus le précédent.
ex0053 amélioration, utilisant une lecture précise de temps avec "micros();".
/*
ex0052_lecture_bouton_Serial_print_ameliore_bis
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, allume la LED connectée à la PIN 13 et
affiche dans le "moniteur série" (Ctrl+Maj+M) l'état de la PIN 12,
c'est-à-dire l'état "pressé" ou non du bouton.
Ce programme utilise la PIN 1 (tx) pour la communication série.
S'il y avait lecture "Serial.read()", la PIN 0 (rx) serait utilisée.

Amélioration de  ex0051_lecture_bouton_Serial_print_ameliore
Une petite amélioration en ajoutant une attente lorsque le bouton a été pressé,
pour éviter les rebonds et compter à double une pression sur le bouton.
*/

#define pinOut 13 // Définition de constantes.
#define pinIn 12

int nCompteur = 0;
int nEtatLast = 0; // mémorise le dernier état du bouton

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise la PIN digital pinIn comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinIn, INPUT);
digitalWrite(pinOut, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (digitalRead(pinIn) == 1) {
  // On a pressé sur le bouton qui met la PIN pinIn à l'état haut (HIGH)
  // Test qu'il n'était pas déjà pressé avant.
  if (nEtatLast == 0) {
    nEtatLast = 1; // Mémorise qu'on a pressé sur le bouton
    delay(1); // attente d'une milliseconde, pour éviter les rebonds

    digitalWrite(pinOut, HIGH);  // set LED on
    nCompteur = nCompteur + 1;
    Serial.println(nCompteur);        // rien correspond à DEC
    }
  }
else { // bouton relaché
  nEtatLast = 0; // Mémorise qu'on a relaché le bouton

  digitalWrite(pinOut, LOW);    // set the LED off
  }
} // loop
ex0052 blink
ex0052_lecture_bouton_Serial_print_ameliore_bis.ino : Même schéma que pour l'exemple ex0040


    - Suivant, ex0060   ;   Précédent, ex0052
ex0055_lecture_bouton_frequence_variable.ino   TOP
Deux boutons permettent de faire varier la fréquence de clignotement d'une LED.
Une amélioration est faite dans l'exemple : ex0085_lecture_bouton_frequence_variable_ameliore
/*
ex0055_lecture_bouton_frequence_variable
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, augmente la valeur d'un compteur.
Lecture de l'état du bouton connecté à la PIN 11
S'il est pressé, diminue la valeur d'un compteur.
Affiche dans le "moniteur série" (Ctrl+Maj+M) la valeur du compteur.

En plus, fait clignoter une LED a une fréquence égale à (1/2) de celle du compteur.
Évite que le compteur soit plus petit que 1.
Des améliorations viendrons dans une version qui utilisent une variable de temps et
la fonction de lecture de temps : micros();
*/

#define pinOut 13 // Définition de constantes.
#define pinInA 12
#define pinInB 11

int nCompteur = 5;
int nEtatLast12 = 0; // mémorise le dernier état du bouton 12
int nEtatLast11 = 0; // mémorise le dernier état du bouton 11
byte bEtatLED = LOW; // L'état de la LED

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise les PINs digitals pinInA et pinInB comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinInA, INPUT);
pinMode(pinInB, INPUT);
digitalWrite(pinOut, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (digitalRead(pinInA) == 1) {
  // On a pressé sur le bouton qui met la PIN pinInA à l'état haut (HIGH)
  // Test qu'il n'était pas déjà pressé avant.
  if (nEtatLast12 == 0) {
    nEtatLast12 = 1; // Mémorise qu'on a pressé sur le bouton
    delay(1); // attente d'une milliseconde, pour éviter les rebonds

    nCompteur = nCompteur + 1;
    Serial.println(nCompteur);
    }
  }
else { // bouton relaché
  nEtatLast12 = 0; // Mémorise qu'on a relaché le bouton
  }

if (digitalRead(pinInB) == 1) {
  // On a pressé sur le bouton qui met la PIN pinInB à l'état haut (HIGH)
  // Test qu'il n'était pas déjà pressé avant.
  if (nEtatLast11 == 0) {
    nEtatLast11 = 1; // Mémorise qu'on a pressé sur le bouton
    delay(1); // attente d'une milliseconde, pour éviter les rebonds

    nCompteur = nCompteur - 1;
    if (nCompteur < 1) nCompteur = 1;  // Test que le compteur ne soit pas inférieur à 1.
    Serial.println(nCompteur);
    }
  }
else { // bouton relaché
  nEtatLast11 = 0; // Mémorise qu'on a relaché le bouton
  }

// Change l'état de la LED
bEtatLED = 1 - bEtatLED; // change son état
digitalWrite(pinOut, bEtatLED);
delay(1000 / nCompteur);  // attente correspondant à la fréquence désirée.
} // loop
ex0055 blink
ex0055_lecture_bouton_frequence_variable.ino
Schéma similaire à celui de l'exemple ex0040 avec un bouton de plus.


    - Suivant, ex0070   ;   Précédent, ex0055
ex0060_lecture_Serial_read.ino   TOP
Lecture du port série.
/*
ex0060_lecture_Serial_read
Si le caractère '0' est envoyé, éteint  la LED connectée à la PIN 13
Si le caractère '1' est envoyé, allume  la LED connectée à la PIN 13
Si le caractère '2' est envoyé, éteint  la LED connectée à la PIN 12
Si le caractère '3' est envoyé, allume  la LED connectée à la PIN 12
Si le caractère '4' est envoyé, éteint  la LED connectée à la PIN 11
Si le caractère '5' est envoyé, allume  la LED connectée à la PIN 11
Il affiche à travers le port série le nombre total de caractères qu'il a lu.
Ce programme utilise la PIN 1 (tx) pour la communication série.
Il utilise aussi la PIN 0 (rx) pour la lecture série "Serial.read()".
*/

#define pinA 13 // Définition de constantes.
#define pinB 12
#define pinC 11

int nCompteur = 0;
char cIn = '0';  // Pour la lecture du caractère envoyé par le port série.

void setup() {
//============
// Initialise les PINs digital pinA, pinB et pinC comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
pinMode(pinA, OUTPUT);
pinMode(pinB, OUTPUT);
pinMode(11, OUTPUT);
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (Serial.available()) {
  // des données sont disponibles sur le port série
  cIn = Serial.read(); // Lecture d'un caractère disponible sur le port série
  if (cIn == '1') {
    digitalWrite(pinA, HIGH);  // set LED on
    }
  else if (cIn == '0') {
    digitalWrite(pinA, LOW);  // set LED off
    }
  else if (cIn == '3') {
    digitalWrite(pinB, HIGH);  // set LED on
    }
  else if (cIn == '2') {
    digitalWrite(pinB, LOW);  // set LED off
    }
  else if (cIn == '5') {
    digitalWrite(pinC, HIGH);  // set LED on
    }
  else if (cIn == '4') {
    digitalWrite(pinC, LOW);  // set LED off
    }
  //else   // On ignore la valeur des autres caratères

  // Indique le nombre total de caractères lus.
  nCompteur = nCompteur + 1;
  Serial.println(nCompteur);
  }
} // loop
ex0060 blink
ex0060_lecture_Serial_read.ino : Même schéma que pour l'exemple ex0020


    - Suivant, ex0080   ;   Précédent, ex0060
ex0070_lecture_analogique_resistance_variable.ino   TOP
Lecture d'une tension sur le port analogique A0.
/*
ex0070_lecture_analogique_resistance_variable
Lecture d'une tension variable, réglée avec une résistance variable.
Affiche à travers le port série la tension lue.
Ce programme utilise la PIN 1 (tx) pour la communication série.
Il utilise aussi la PIN 0 (rx) pour la lecture série "Serial.read()".
*/

int nSensorValue = 0;    // Valeur lue sur le port analogique A0
int nSensorValueOld = 0; // Dernière valeur lue sur le port analogique A0
int nOutputValue = 0;    // Valeur écrite sur la PIN 11, pour faire varier l'intensité de la LED

void setup() {
//============
// Initialise la PIN digital 11 comme OUTPUT
pinMode(11, OUTPUT);
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
nSensorValue = analogRead(A0); // Lecture de la tension sur le port analogique A0
                               // La tension varie entre 0 et 5 Volts, correspondant
                               // aux nombres entre 0 et 1023.

if (abs(nSensorValue - nSensorValueOld) > 10) {
  // La valeur du port analogique A0 a changé,
  nSensorValueOld = nSensorValue; // Mémorise la nouvelle valeur du port analogique A0

  // Convertie la valeur lue, qui est entre 0 et 1023 en un nombre entre 0 et 255.
  nOutputValue = map(nSensorValue, 0, 1023, 0, 255);

  analogWrite(11, nOutputValue);  // Change la luminosité de la LED

  // affiche la valeur lue
  Serial.println(nSensorValue);
  }
} // loop
ex0070 blink
ex0070_lecture_analogique_resistance_variable.ino : La résistance variable peut être entre 4,7 kohms et 100 kohms.
En tournant le bouton de la résistance variable, on fait varier la tension de la borne du milieur entre 0 V et le maximum, 5 Volts.
Le programme lit cette tension et change ainsi le rapport de cycle "haut-bas" appliqué à la LED, faisant ainsi varier son intensité.


La lecture du port série peut aussi se faire depuis un programme Python, ci-dessous un petit exemple de code Python, qui lit ce qui est envoyé par l'Arduino et affiche le nombre reçu.
# py0020_serial_arduino.py
# Test de communication à travers le port série avec un arduino
# Depuis Synaptic, j'ai installé le module "python-serial" (sous linux)
# c.f. https://playground.arduino.cc/Interfacing/Python
# c.f. Arduino : ex0070_lecture_analogique_resistance_variable.ino

import serial
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=1) # timeout en secondes

nVal = 0  # Valeur reçue par le port série
nCpt = 0   # compteur de sécurité, pour être sur que le programme s'arrête.
strS = "chaine de caractères" # pour récupérer la chaine de caractères du port série

# Lectures pour vider le buffer du port série.
strS = ser.readline()
strS = ser.readline()

# Boucle pour attendre de recevoir un nombre du port série
while (nVal < 1015) & (nCpt < 30):
   nCpt = nCpt + 1

   strS = ser.readline() # Lecture du port série
   # print(strS)  # pour information

   # Conversion du nombre reçu sous forme de tableau en nombre.
   nVal = 0
   for cc in strS:
      if (cc >= ord('0')) and (cc <= ord('9')):
        nVal = 10 * nVal + cc - ord('0');

   if (len(strS) > 0):
      # Un nombre a été reçu du port série, affiche-le
      print(nVal)


print("Terminé")

    - Suivant, ex0040   ;   Précédent, ex0070
ex0080_temps_bouton_presse.ino   TOP
Mesure le temps en micro secondes durant lequel un bouton est pressé.
/*
ex0080_temps_bouton_presse
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, allume la LED connectée à la PIN 13
Mesure en micro secondes durant combien de temps il est pressé
affiche dans le "moniteur série" (Ctrl+Maj+M) ce temps.
Ce programme utilise la PIN 1 (tx) pour la communication série.
S'il y avait lecture "Serial.read()", la PIN 0 (rx) serait utilisée.

Avec une petite amélioration en ajoutant une attente lorsque le bouton a été pressé,
pour éviter les rebonds et compter à double une pression sur le bouton.
*/
int nEtatLast = 0; // mémorise le dernier état du bouton
unsigned long lwTimeStart = 0; // Temps en micros secondes du départ de bouton appuyé
unsigned long lwTimeStop = 0;  // Temps en micros secondes d'arret du bouton

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise la PIN digital 12 comme INPUT
pinMode(13, OUTPUT);
pinMode(12, INPUT);
digitalWrite(13, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
if (digitalRead(12) == 1) {
  // On a pressé sur le bouton qui met la PIN 12 à l'état haut (HIGH)
  // Test qu'il n'était pas déjà pressé avant.
  if (nEtatLast == 0) {
    lwTimeStart = micros();
    nEtatLast = 1; // Mémorise qu'on a pressé sur le bouton
    delay(1); // attente d'une milliseconde, pour éviter les rebonds

    digitalWrite(13, HIGH);  // set LED on
    }
  }
else { // bouton relaché
  if (nEtatLast == 1) {
    // On vient de relacher le bouton
    lwTimeStop = micros();
    nEtatLast = 0; // Mémorise qu'on a relaché le bouton

    Serial.println(lwTimeStop - lwTimeStart); // Affiche en micro secondes le temps durant lequel le bouton était pressé

    digitalWrite(13, LOW);    // set the LED off
    }
  }
} // loop
ex0080 blink
ex0080_temps_bouton_presse.ino : Même schéma que pour l'exemple ex0040


    - Suivant, ex0090   ;   Précédent, ex0080
ex0085_lecture_bouton_frequence_variable_ameliore.ino   TOP
Deux boutons permettent de faire varier la fréquence de clignotement d'une LED.
C'est une amélioration du programme : ex0055_lecture_bouton_frequence_variable.ino
Cette version a encore des défauts de rebonds, qui sont amélioré dans la version suivante : ex0086 amélioration.
/*
ex0085_lecture_bouton_frequence_variable_ameliore
Amélioration de "ex0055_lecture_bouton_frequence_variable"
Une autre amélioration est disponible sous : "ex0086_lecture_bouton_frequence_variable_ameliore_bis"
en ayant une fréquence beaucoup plus précise, en utilisant la fonction "micros()".
Lecture de l'état du bouton connecté à la PIN 12
S'il est pressé, augmente la valeur d'un compteur.
Lecture de l'état du bouton connecté à la PIN 11
S'il est pressé, diminue la valeur d'un compteur.
Affiche dans le "moniteur série" (Ctrl+Maj+M) la valeur du compteur.

En plus, fait clignoter une LED a une fréquence égale à (1/2) de celle du compteur.
Évite que le compteur soit plus petit que 1.
*/

#define pinOut 13 // Définition de constantes.
#define pinInA 12
#define pinInB 11

int nCompteur = 5;
int nEtatLast12 = 0; // mémorise le dernier état du bouton 12
int nEtatLast11 = 0; // mémorise le dernier état du bouton 11
byte bEtatLED = LOW; // L'état de la LED
unsigned long lwTimeNow = 0;   // Temps actuel en micros secondes
unsigned long lwTimeNext = 0;  // Temps définissant le prochain changement d'état en micros secondes
                               // qui aura lieu lorsque (lwTimeNow - lwTimeNext >= lwTimeDelta=
unsigned long lwTimeDelta = 200000; // Temps en micros secondes à attendre avant le prochain changement d'état

void setup() {
//============
// Initialise la PIN digital pinOut comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
// Initialise les PINs digitals pinInA et pinInB comme INPUT
pinMode(pinOut, OUTPUT);
pinMode(pinInA, INPUT);
pinMode(11, INPUT);
digitalWrite(13, LOW); // set the LED off
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
lwTimeNow = micros();
lwTimeNext = micros();
} // setup

void loop() {
//===========
// Test s'il faut changé l'état de la LED
lwTimeNow = micros();
if (lwTimeNow - lwTimeNext >= lwTimeDelta) {
   // Change l'état de la LED
   bEtatLED = 1 - bEtatLED; // change son état
   digitalWrite(pinOut, bEtatLED);
   lwTimeNext = lwTimeNow; // Temps définissant le prochain changement d'état
   }

if ((lwTimeNow - lwTimeNext < lwTimeDelta - 1200) || (nCompteur > 800)) {
    // Ne lit sur un bouton que si le temps de traitement est suffisamment long

    if (digitalRead(pinInA) == 1) {
      // On a pressé sur le bouton qui met la PIN pinInA à l'état haut (HIGH)
      // Test qu'il n'était pas déjà pressé avant.
      if (nEtatLast12 == 0) {
        nEtatLast12 = 1; // Mémorise qu'on a pressé sur le bouton
        delay(1); // attente d'une milliseconde, pour éviter les rebonds

        nCompteur = nCompteur + 1;
        Serial.println(nCompteur);
        lwTimeDelta = 1000000 / nCompteur;  // Temps en micros secondes à attendre avant le prochain changement d'état
        }
      }
    else { // bouton relaché
      if (nEtatLast12 == 1) {
         nEtatLast12 = 0; // Mémorise qu'on a relaché le bouton
         delay(1); // attente d'une milliseconde, pour éviter les rebonds
         }
      }

    if (digitalRead(pinInB) == 1) {
      // On a pressé sur le bouton qui met la PIN pinInB à l'état haut (HIGH)
      // Test qu'il n'était pas déjà pressé avant.
      if (nEtatLast11 == 0) {
         nEtatLast11 = 1; // Mémorise qu'on a pressé sur le bouton
         delay(1); // attente d'une milliseconde, pour éviter les rebonds

         nCompteur = nCompteur - 1;
         if (nCompteur < 1) nCompteur = 1;  // Test que le compteur ne soit pas inférieur à 1.
         Serial.println(nCompteur);
         lwTimeDelta = 1000000 / nCompteur;  // Temps en micros secondes à attendre avant le prochain changement d'état
         }
      }
    else { // bouton relaché
      if (nEtatLast11 == 1) {
         nEtatLast11 = 0; // Mémorise qu'on a relaché le bouton
         delay(1); // attente d'une milliseconde, pour éviter les rebonds
         }
      }
    }
} // loop
ex0085 blink
ex0085_lecture_bouton_frequence_variable_ameliore.ino
Même schéma que celui de l'exemple ex0055.
La différence est que la fréquence est beaucoup plus précise.


    - Suivant, ex0100   ;   Précédent, ex0085
ex0090_lecture_analogique_photo_resistance.ino   TOP
Lecture de luminosité en utilisant une photo-résistance.
On peut remplacer la résistance variable de l'ex0070 par une photo-résistance selon le schéma ci-dessous, en utilisant le code de l'ex0070.
/*
ex0090_lecture_analogique_photo_resistance
Lecture d'une tension variable, réglée par la luminosité
arrivant sur une photo résistance.
Allume des LEDs parmis 3, en fonction de la luminosité.
Donne sur les LEDs un codage binaire de l'intensité lue.
*/

int nSensorValue = 0;    // Valeur lue sur le port analogique A0
int nConvertValue = 0;   // Valeur lue, convertit dans un autre intervalle

void setup() {
//============
// Initialise les PINs digital 13, 12 et 11 comme OUTPUT
// La PIN 13 a une LED connectée sur la plupart des cartes Arduino
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
// Pour TESTER
//Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
nSensorValue = analogRead(A0); // Lecture de la tension sur le port analogique A0
                               // La tension varie entre 0 et 5 Volts, correspondant
                               // aux nombres entre 0 et 1023.

// Convertie la valeur lue, qui est entre 0 et 1023 en un nombre entre 0 et 7.
nConvertValue = map(nSensorValue, 0, 1023, 0, 7);

// Test le niveau global d'intensité
if (nConvertValue >= 4) {
  digitalWrite(13, HIGH);
  }
else {
  digitalWrite(13, LOW);
  }

if ((nConvertValue % 4) >= 2) {
  digitalWrite(12, HIGH);
  }
else {
  digitalWrite(12, LOW);
  }

if ((nConvertValue % 2) >= 1) {
  digitalWrite(11, HIGH);
  }
else {
  digitalWrite(11, LOW);
  }

// affiche la valeur convertie  POUR TESTER
// Serial.println(nConvertValue);  delay(500);
} // loop
ex0090 blink
ex0090_lecture_analogique_photo_resistance.ino : La photo-résistance varie entre 1 kohms et 50 kohms.
Pour une luminosité moyenne, sa valeur est d'environ 10 kohms, c'est ce qui dicte le choix de la résistance de 10 kohms.
S'il y a beaucoup de lumière, la photo-résistance est faible, comme elle est connectée au +5V, la tension lue sera proche de +5V.
S'il y a peu de lumière, la photo-résistance est grande, comme l'autre résistance est connectée au 0V, la tension lue sera proche de 0V.
La résistance est de 10 kohms (10'000). Code couleurs : brun ; noire ; orange.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0110   ;   Précédent, ex0090
ex0100_mesure_temps_aide_photo_resistance.ino   TOP
Mesure de temps en utilisant une photo-résistance.
/*
ex0100_mesure_temps_aide_photo_resistance
Mesure du temps de passage d'un objet devant une photorésistance
Le temps sera transmis à travers le port série.
Mesure durant combien de microsecondes la photorésistance
recoit une luminosité faible.
L'utilisation de la lecture analogique est lente,
elle prend environ 100 micro-secondes, donc la précision est limitée.
Seul l'entrée analogique A0 est utilisée.
La PIN 13 est utilisée pour indiquer que la mesure est en cours.
Ce programme utilise la PIN 1 (tx) pour la communication série.
Il utilise aussi la PIN 0 (rx) pour la lecture série "Serial.read()".
*/

int nSensorValue = 0;    // Valeur lue sur le port analogique A0
int nSensorValueOld = 0; // Dernière valeur lue sur le port analogique A0
unsigned long lwTimeStart = 0; // Temps en micros secondes du départ de bouton appuyé
unsigned long lwTimeStop = 0;  // Temps en micros secondes d'arret du bouton

void setup() {
//============
// Initialise la PIN digital 13 comme OUTPUT
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
nSensorValueOld = analogRead(A0); // Lecture de la tension sur le port analogique A0
                                  // La tension varie entre 0 et 5 volts, correspondant
                                  // aux nombres     entre 0 et 1023.
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
nSensorValue = analogRead(A0); // Lecture de la tension sur le port analogique A0
                               // La tension varie entre 0 et 5 volts, correspondant
                               // aux nombres entre 0 et 1023.

if ((nSensorValue < 500) & (nSensorValueOld > 500)) {
   // Début de la mesure de temps
   lwTimeStart = micros();
   nSensorValueOld = nSensorValue;  // < 500, donc une mesure est en cours
   digitalWrite(13, HIGH); // Allume la LED pour indiquer qu'une mesure est en cours
   }

if ((nSensorValue > 550) & (nSensorValueOld < 500)) {
   // Fin de la mesure de temps
   lwTimeStop = micros();
   nSensorValueOld = nSensorValue; // > 500, donc une prochaine mesure peut etre faite
   digitalWrite(13, LOW); // Eteint la LED, ce qui indique la fin de mesure.

   // Affiche le temps
   Serial.println(lwTimeStop - lwTimeStart);
   }
} // loop
ex0100 blink
ex0100_mesure_temps_aide_photo_resistance.ino : La photo-résistance varie entre 1 kohms et 50 kohms.
Pour une luminosité moyenne, sa valeur est d'environ 10 kohms, c'est ce qui dicte le choix de la résistance de 10 kohms.
S'il y a beaucoup de lumière, la photo-résistance est faible, comme elle est connectée au +5V, la tension lue sera proche de +5V.
S'il y a peu de lumière, la photo-résistance est grande, comme l'autre résistance est connectée au 0V, la tension lue sera proche de 0V.
La résistance est de 10 kohms (10'000). Code couleurs : brun ; noire ; orange.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0120   ;   Précédent, ex0100
ex0110_photo_resistance_lien_analogique_digital.ino   TOP
Test de lien entre une mesure Analogique et Digitale, d'une tension.
/*
ex0110_photo_resistance_lien_analogique_digital
L'utilisation de la lecture analogique est lente,
elle prend environ 100 micro-secondes.

C'est la raison pour laquelle, il peut etre préférable d'utiliser une
entrée digitale pour mesurer l'état de la résistance variable.

Le but de ce code est de voir pour quelle plage de valeurs mesurées sur A0,
une mesure digitale donne 0.

La PIN 13 est utilisée pour indiquer la valeur digitale lue.
Ce programme utilise la PIN 1 (tx) pour la communication série.
Il utilise aussi la PIN 0 (rx) pour la lecture série "Serial.read()".

RESULTATS :
Il y a une hystérésis, l'état digital dépend de son éta précédent.
Si l'état de la PIN 8 est à 1, A0 doit descendre en dessous de 450 pour que la PIN 8 passe à 0
Si l'état de la PIN 8 est à 0, A0 doit monter en-dessus de 520 pour que la PIN 8 passe à 1
*/

int nSensorValue = 0;   // Valeur lue sur le port analogique A0
int nDigitalValue = 0;  // Valeur lue sur l'entrée digitale 8

void setup() {
//============
pinMode(13, OUTPUT); // Initialise la PIN digital 13 comme OUTPUT
pinMode( 8, INPUT);  // Initialise la PIN digital  8 comme INPUT
digitalWrite(13, LOW);
Serial.begin(115200);  // Initialise la communication série à une haute vitesse.
                       // La vitesse de 9600 bauds est souvent utilisée par défaut.
} // setup

void loop() {
//===========
nSensorValue = analogRead(A0); // Lecture de la tension sur le port analogique A0
                               // La tension varie entre 0 et 5 volts, correspondant
                               // aux nombres entre 0 et 1023.

nDigitalValue = digitalRead( 8); // Lecture de l'état de l'entrée de la PIN 8

// La LED indique l'état digital lu.
if (nDigitalValue > 0) digitalWrite(13, HIGH);
else                   digitalWrite(13, LOW);

// Affiche les états lus, analogique et digital
Serial.print("A0 = ");
Serial.print(nSensorValue);
Serial.print("  PIN8 = ");
Serial.println(nDigitalValue); // Ici, l'affichage passe à la ligne
delay(500);
} // loop
ex0110 blink
ex0110_photo_resistance_lien_analogique_digital.ino : La photo-résistance varie entre 1 kohms et 50 kohms.
Pour une luminosité moyenne, sa valeur est d'environ 10 kohms, c'est ce qui dicte le choix de la résistance de 10 kohms.
S'il y a beaucoup de lumière, la photo-résistance est faible, comme elle est connectée au +5V, la tension lue sera proche de +5V.
S'il y a peu de lumière, la photo-résistance est grande, comme l'autre résistance est connectée au 0V, la tension lue sera proche de 0V.
La résistance est de 10 kohms (10'000). Code couleurs : brun ; noire ; orange.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0125   ;   Précédent, ex0110
ex0120_buzzer_avec_photo_resistance.ino   TOP
Un buzzer émet un son à une fréquence dépendante de la lumière arrivant sur une photo-résistance.
/*
ex0120_buzzer_avec_photo_resistance
Un buzzer émet un son à une fréquence dépendante de la valeur lue sur
l'entrée  A0,  déterminée par la lumière arrivant sur une photo-résistance.
*/

int nSensorValue = 0;   // Valeur lue sur le port analogique A0
unsigned long lwTimeLast = 0; // Dernier temps lu en micros secondes
unsigned long lwTimeNow = 0;  // Temps lu en micros secondes


void setup() {
//============
pinMode(12, OUTPUT);
lwTimeLast = micros(); // Lecture du temps au départ
lwTimeNow = micros(); // Lecture du temps au départ
} // setup

void loop() {
//===========
nSensorValue = analogRead(A0); // Lecture de la tension sur le port analogique A0
                               // La tension varie entre 0 et 5 volts, correspondant
                               // aux nombres entre 0 et 1023.

// Attente, jusqu'à ce que le temps atteigne une demi période
while (lwTimeNow - lwTimeLast < 5*nSensorValue) lwTimeNow = micros();
digitalWrite(12, HIGH);
lwTimeLast = lwTimeNow; // mémorise le changement d'état

// Nouvelle lecture de l'entrée analogique, pour régler la période.
nSensorValue = analogRead(A0);

// Attente, jusqu'à ce que le temps atteigne une demi période
while (lwTimeNow - lwTimeLast < 5*nSensorValue) lwTimeNow = micros();
digitalWrite(12, LOW);
lwTimeLast = lwTimeNow; // mémorise le changement d'état
} // loop
ex0120 blink
ex0120_buzzer_avec_photo_resistance.ino : La photo-résistance varie entre 1 kohms et 50 kohms.
Pour une luminosité moyenne, sa valeur est d'environ 10 kohms, c'est ce qui dicte le choix de la résistance de 10 kohms.
S'il y a beaucoup de lumière, la photo-résistance est faible, comme elle est connectée au +5V, la tension lue sera proche de +5V.
S'il y a peu de lumière, la photo-résistance est grande, comme l'autre résistance est connectée au 0V, la tension lue sera proche de 0V.
La résistance est de 10 kohms (10'000). Code couleurs : brun ; noire ; orange.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0126   ;   Précédent, ex0120
ex0125_liquidCrystal_Simple_Hello_World.ino   TOP
L'afficheur LCD HD44780 de 2 lignes de 16 caractères.
Voir aussi : Liquid Crydtal Library du site de référence. Chercher "Liquid Crystal Library" dans la page.
Donne des exemples et des références.
/*
ex0125_liquidCrystal_Simple_Hello_World.ino
Utilise l'affichage LCD (à cristaux liquides),
pour afficher du texte.

Une version plus simple à utiliser et plus complète
est présenté dans "ex0130_liquid_crystal_hello_world.ino"
C'est un "Shield", la connexion est plus simple et de plus, 
5 boutons en plus du bouton reset sont ajoutés,
pour avoir des entrées possibles.
Ainsi, l'Arduino devient autonome pour beaucoup d'applications,
sans nécessité d'un ordinateur pour l'utiliser et
afficher des résultats.

Ici, l'afficheur écrit "Hello World!" et "Bonjour a tous!"
  
Affichage d'un texte.
Lecture de l'état des Pushbutton. 
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 2
 * LCD Enable pin to digital pin 3
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

Voir :
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 
PINs qui restent libre et utilisables :
13, 12, 11, 10, 9, 8, 1 et 0

Les PINs  0  et  1  sont utilisés pour la transmission série par USB,

L'afficheur HD44780s peut être préprogrammé avec deux jeux de caractères,
Soit asiatique, soit européen.
c.f. : http://www.martyncurrey.com/arduino-with-hd44780-based-lcds/
Si le jeu par défaut est asiatique, il n'y a pas de caractères accentués.
On peut en créer 8, mais l'affichage se complique un peu. 
Aussi c.f. : http://arduino-projects4u.com/ldc-character/
 */

// Inclus la librairie qui gère l'affichage
#include <LiquidCrystal.h>

// Initialisation, pour indiquer quelles sont les PINs utilisées par l'afficheur LCD
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd( 2, 3,  4,  5,  6,  7);
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20];   // Un "array" de caractères, pour conversion de nombre en un String.
String strS = ""; // Une chaine de caractères.

// temps en micro secondes 
unsigned long lwTemps = 0; // sur 32 bits, de 0 à 2^32 -1 = 4'294'967'295

int sensorValue = 0; // valeur de la résistance variable, lue sur l'entrée analogique A0.

// Pour créer des caractères personnalisées.  Matrices 8x5 (8 lignes et 5 colonnes)
// Pour des exemples, voir : https://www.hackmeister.dk/2010/08/custom-lcd-characters-with-arduino/
// Pour créer des caractères simplement : https://omerk.github.io/lcdchargen/
byte smiley[8] = {
  B00000,
  B10001,
  B00000,
  B00000,
  B10001,
  B01110,
  B00000,
  B00000
};
byte agrave[8] = { // caractère "a accent grave"
  B01000,
  B00100,
  B01110,
  B00001,
  B01111,
  B10001,
  B01111,
  B00000
};

void setup() {
//============
// Indique que l'afficheur LCD a deux lignes de 16 caractères
lcd.begin(16, 2);

// Création d'un caractère personnalisé, correspondant au code '0'
// Les codes 0 à 7 sont disponnibles.
lcd.createChar(0, smiley);
lcd.createChar(1, agrave);

// Affiche un message au départ, pour vérifier le bon fonctionnement.
lcd.setCursor(0, 0); // Première colonne, première ligne
lcd.print("Hello, World!");
lcd.setCursor(14, 0); // suit le texte par un smiley
lcd.write(byte(0));

lcd.setCursor(0, 1); // Première colonne, deuxième ligne
lcd.print("Bonjour ");
lcd.setCursor(8, 1); // Première colonne, deuxième ligne
lcd.write(byte(1));  // pour afficher le "a accent grave"
lcd.setCursor(9, 1); // Première colonne, deuxième ligne
lcd.print(" Tous!");  // Les caractères accentués ne passent pas.
delay(3000);                   // Attente de 2 secondes
lcd.setCursor(0, 0);           // Première ligne
lcd.print("                "); // efface le texte 16 caractères
lcd.setCursor(0, 1);           // Deuxième ligne
lcd.print("                "); // efface le texte 16 caractères
//lcd.autoscroll();
} // setup

void loop() {
//===========
// Affiche le temps écoulé depuis le dernier Reset, en secondes.
delay(200); // attente en [ms]
// Pour sprintf, c.f. https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
// %d ou %i pour signed decimal integer
// %u pour unsigned decimal integer
// %ld ou %li pour long signed decimal integer
// %lu pour long unsigned decimal integer
lwTemps = millis(); // temps en millisecondes. remis à 0 toutes les 4'294,967 secondes ( = 71,5827 minutes)
//sprintf(acStr, "%8.3f", millis()/1000.0); // Ne fonctionne pas
//sprintf(acStr, "%9lu", millis()); // Fonctionne bien
dtostrf(millis()/1000.0, 12, 3, acStr);  // Marche bien pour convertir un float en un string, avec un format
// millis()  retourne le nombre de millisecondes écoulé depuis la mise sous tension ou le reset de l'Arduino

// Affichage du temps sur la 1ère ligne
lcd.setCursor(0, 0);
lcd.print(acStr);

// La lecture des boutons se fait par l'intermédiaire du port A0
sensorValue = analogRead(0);
sprintf(acStr, "%4d ", sensorValue); 

// Affichage de la valeur de la résistance variable sur la 2ème ligne
lcd.setCursor(0, 1);
lcd.print(acStr);
lcd.setCursor(14, 1); // suit le texte par un smiley
lcd.write(byte(0));
} // loop
ex0125

ex0125_liquidCrystal_Simple_Hello_World.ino
Le potentiomètre est de 10 kohms. N'importe quelle valeur entre 4 et 50 kohms convient.
Il sert à régler le contraste de l'affichage LCD.
La résistance est de 220 ohms. Code couleurs : rouge ; rouge ; brun.
Le fil violet - rose n'est pas nécessaire, il sert juste à afficher la valeur du potentiomètre, en unités arbitraires.
Code de couleur des résistance, sur wikipedia.org.


    - Suivant, ex0127   ;   Précédent, ex0125
ex0126_mesure_temperature_DS18B20.ino   TOP
Mesure de température avec une précision de 0,5 à 0,25 °C, en utilisant le chip DS18B20.
Voir aussi l'ex0127, avec affichage sur un écran LCD.
/*
ex0126_mesure_temperature_DS18B20.ino
Exemple de code pour lire un unique capteur DS18B20 sur un bus 1-Wire.
Programme et information récupérée de :
https://www.carnetdumaker.net/articles/mesurer-une-temperature-avec-un-capteur-1-wire-ds18b20-et-une-carte-arduino-genuino/

Pour installer la librairie "OneWire", téléchargez le fichier .zip  "OneWire.zip" ou "OneWire-master.zip"
et enregistrez-le dans un dossier de votre choix.
Lieu de téléchargement : https://github.com/PaulStoffregen/OneWire
Cliquez sur "Clone or download" > Download ZIP.
Depuis le logiciel Arduino, allez dans "Croquis" > "Inclure une bibliothèque" > "Ajoutez la bibliothèque .Zip..."
Sélectionnez le fichier "OneWire.zip" que vous venez de télécharger.
La librairie devrait ainsi etre installée.
Cela a bien fonctionné avec la version 1.8.3.

Les librairies sont stockées sous : $HOME/sketchbook/libraries

c.f. : https://www.arduino.cc/en/Reference/Libraries

Avec l'ancienne versions 1.0.5 de Arduino, le fichier "OneWire-master.zip" n'a pas été accepté.
J'ai décompressé son contenu, renommé "OneWire-master" en "OneWire" et compressé dans "OneWire.zip",
ensuite l'installation a fonctionnée.
*/
 
/* Dépendance pour le bus 1-Wire */
#include <OneWire.h>
 
/* Broche du bus 1-Wire */
const byte pinBROCHE_ONEWIRE = 7;

/* Code de retour de la fonction getTemperature() */
enum DS18B20_RCODES {
  READ_OK,  // Lecture ok
  NO_SENSOR_FOUND,  // Pas de capteur
  INVALID_ADDRESS,  // Adresse reçue invalide
  INVALID_SENSOR  // Capteur invalide (pas un DS18B20)
  };

// Création de l'objet OneWire pour manipuler le bus 1-Wire
OneWire ds(pinBROCHE_ONEWIRE);
 
byte getTemperature(float *temperature, byte reset_search) {
//==========================================================
// Fonction de lecture de la température via un capteur DS18B20.

byte data[9], addr[8];
// data[] : Données lues depuis le scratchpad
// addr[] : Adresse du module 1-Wire détecté

/* Reset le bus 1-Wire ci nécessaire (requis pour la lecture du premier capteur) */
if (reset_search) {
  ds.reset_search();
  }

/* Recherche le prochain capteur 1-Wire disponible */
if (!ds.search(addr)) {
  // Pas de capteur
  return NO_SENSOR_FOUND;
  }

/* Vérifie que l'adresse a été correctement reçue */
if (OneWire::crc8(addr, 7) != addr[7]) {
  // Adresse invalide
  return INVALID_ADDRESS;
  }

/* Vérifie qu'il s'agit bien d'un DS18B20 */
if (addr[0] != 0x28) {
  // Mauvais type de capteur
  return INVALID_SENSOR;
  }

/* Reset le bus 1-Wire et sélectionne le capteur */
ds.reset();
ds.select(addr);

/* Lance une prise de mesure de température et attend la fin de la mesure */
ds.write(0x44, 1);
delay(800);

/* Reset le bus 1-Wire, sélectionne le capteur et envoie une demande de lecture du scratchpad */
ds.reset();
ds.select(addr);
ds.write(0xBE);

/* Lecture du scratchpad */
for (byte i = 0; i < 9; i++) {
  data[i] = ds.read();
  }
 
/* Calcul de la température en degré Celsius */
*temperature = ((data[1] << 8) | data[0]) * 0.0625; 

// Pas d'erreur
return READ_OK;
} // getTemperature

void setup() {
//============
// Initialisation du port série pour afficher la température dans le "Moniteur série".
Serial.begin(115200);
} // setup 
 
void loop() {
//===========  
float temperature;
delay(1000);
   
// Lit la température ambiante
byte bErr = getTemperature(&temperature, true);
if (bErr != READ_OK) {
  // Erreur qui ne devrait pas se produire ?!?
  Serial.print("Erreur de lecture du capteur, erreur n° : ");
  Serial.println(bErr); // Cela ne donne pas beaucoup d'information, mais c.f. "enum DS18B20_RCODES ci-dessus"
  }
else {
  /* Affiche la température */
  Serial.print(F("Temperature : "));
  Serial.print(temperature, 2);
  Serial.println("°C");
  }
} // loop
ex00xx blink
ex0126_mesure_temperature_DS18B20.ino


    - Suivant, ex0130   ;   Précédent, ex0126
ex0127_liquidCrystal_Temperature_measure.ino   TOP
Comme l'ex0125, affichage sur un écran LCD.
En plus, comme l'ex0126, lit la température.
Ensuite, la température est affichée sur l'écran LCD.
Mesure de température avec une précision de 0,5 à 0,25 °C, en utilisant le chip DS18B20.
-> Voir une version améliorée ...
/*
ex0127_liquidCrystal_Temperature_measure.ino
c.f. ex0126_mesure_temperature_DS18B20.ino
Mesure la température et l'affiche sur l'écran à LCD
Mesure de température avec une précision de 0,5 à 0,25 °C, en utilisant le chip DS18B20.

Utilise l'affichage LCD (à cristaux liquides),
pour afficher du texte.
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 2
 * LCD Enable pin to digital pin 3
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

Voir :
 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 
PINs qui restent libre et utilisables :
13, 12, 11, 10, 9, 8, 1 et 0

Les PINs  0  et  1  sont utilisés pour la transmission série par USB,

L'afficheur HD44780s peut être préprogrammé avec deux jeux de caractères,
Soit asiatique, soit européen.
c.f. : http://www.martyncurrey.com/arduino-with-hd44780-based-lcds/
Si le jeu par défaut est asiatique, il n'y a pas de caractères accentués.
On peut en créer 8, mais l'affichage se complique un peu. 
Aussi c.f. : http://arduino-projects4u.com/ldc-character/
 */

// Inclus la librairie qui gère l'affichage
#include <LiquidCrystal.h>
 
/* Dépendance pour le bus 1-Wire */
#include <OneWire.h>

// Initialisation, pour indiquer quelles sont les PINs utilisées par l'afficheur LCD
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd( 2, 3,  4,  5,  6,  7);
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20];   // Un "array" de caractères, pour conversion de nombre en un String.
String strS = ""; // Une chaine de caractères.

/* Broche du bus 1-Wire */
const byte pinBROCHE_ONEWIRE = 12;

/* Code de retour de la fonction getTemperature() */
enum DS18B20_RCODES {
  READ_OK,  // Lecture ok
  NO_SENSOR_FOUND,  // Pas de capteur
  INVALID_ADDRESS,  // Adresse reçue invalide
  INVALID_SENSOR  // Capteur invalide (pas un DS18B20)
  };

// Création de l'objet OneWire pour manipuler le bus 1-Wire
OneWire ds(pinBROCHE_ONEWIRE);
 
byte getTemperature(float *temperature, byte reset_search) {
//==========================================================
// Fonction de lecture de la température via un capteur DS18B20.

byte data[9], addr[8];
// data[] : Données lues depuis le scratchpad
// addr[] : Adresse du module 1-Wire détecté

/* Reset le bus 1-Wire ci nécessaire (requis pour la lecture du premier capteur) */
if (reset_search) {
  ds.reset_search();
  }

/* Recherche le prochain capteur 1-Wire disponible */
if (!ds.search(addr)) {
  // Pas de capteur
  return NO_SENSOR_FOUND;
  }

/* Vérifie que l'adresse a été correctement reçue */
if (OneWire::crc8(addr, 7) != addr[7]) {
  // Adresse invalide
  return INVALID_ADDRESS;
  }

/* Vérifie qu'il s'agit bien d'un DS18B20 */
if (addr[0] != 0x28) {
  // Mauvais type de capteur
  return INVALID_SENSOR;
  }

/* Reset le bus 1-Wire et sélectionne le capteur */
ds.reset();
ds.select(addr);

/* Lance une prise de mesure de température et attend la fin de la mesure */
ds.write(0x44, 1);
delay(800);

/* Reset le bus 1-Wire, sélectionne le capteur et envoie une demande de lecture du scratchpad */
ds.reset();
ds.select(addr);
ds.write(0xBE);

/* Lecture du scratchpad */
for (byte i = 0; i < 9; i++) {
  data[i] = ds.read();
  }
 
/* Calcul de la température en degré Celsius */
*temperature = ((data[1] << 8) | data[0]) * 0.0625; 

// Pas d'erreur
return READ_OK;
} // getTemperature

void setup() {
//============
// Indique que l'afficheur LCD a deux lignes de 16 caractères
lcd.begin(16, 2);

// Affiche un message au départ, pour vérifier le bon fonctionnement.
lcd.setCursor(0, 0); // Première colonne, première ligne
lcd.print("Temperature");
lcd.setCursor(14, 0); // suit le texte par un smiley

lcd.setCursor(0, 1); // Première colonne, deuxième ligne
lcd.print("mesure ");
lcd.setCursor(8, 1); // Première colonne, deuxième ligne
delay(3000);                   // Attente de 2 secondes
lcd.setCursor(0, 0);           // Première ligne
lcd.print("                "); // efface le texte 16 caractères
lcd.setCursor(0, 1);           // Deuxième ligne
lcd.print("                "); // efface le texte 16 caractères
//lcd.autoscroll();
} // setup

void loop() {
//===========
// Affiche la température lue avec un chip DS18b20
delay(200); // attente en [ms]
// Pour sprintf, c.f. https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
// %d ou %i pour signed decimal integer
// %u pour unsigned decimal integer
// %ld ou %li pour long signed decimal integer
// %lu pour long unsigned decimal integer

float temperature;
delay(1000);
   
// Lit la température ambiante
byte bErr = getTemperature(&temperature, true);
if (bErr != READ_OK) {
  // Erreur qui ne devrait pas se produire ?!?
  sprintf(acStr, "Erreur n° :%4d", bErr);
  strS = acStr;
  lcd.setCursor(0, 0);  
  lcd.print(strS);
  }
else {
  /* Affiche la température */
  dtostrf( temperature, 6, 2, acStr);
  strS = acStr;
  strS = "Temp = " + strS + "C";
  lcd.setCursor(0, 0);  
  lcd.print(strS);
  }
} // loop
ex0127 blink
ex0127_liquidCrystal_Temperature_measure.ino :
Montage similaire au ex0125, avec l'adjonction du chip DS18B20, comme sur l'exemple "ex0126".


    - Suivant, ex0131   ;   Précédent, ex0127
ex0130_liquid_crystal_hello_world.ino   TOP
Test l'afficheur LCD (à cristaux liquides) de deux lignes de 16 caractères.
La lecture des boutons est lente (5 millisecondes), mais faite en un seul appel.
Je préfère la version suivante, "ex0131".
/*
ex0130_liquid_crystal_hello_world
Utilise l'affichage LCD (à cristaux liquides),
pour afficher du texte.
De plus, il existe un "shield" qui ajoute 5 boutons en plus du bouton reset,
pour avoir des entrées possibles.
Ainsi, l'Arduino devient autonome pour beaucoup d'applications,
sans nécessité d'un ordinateur pour l'utiliser et
afficher des résultats.

La lecture des boutons est lente, elle prend plus de 5 milli-secondes,
mais elle se fait en un seul appelle à la fonction : read_LCD_buttons()
Pour une version que je préfère, c.f. : ex0131_liquid_crystal_hello_world

Ici, l'afficheur écrit "Hello World!" et "Bonjour a tous!"
Puis mesure le temps et indique quelle touche est pressée.
  
Affichage d'un texte.
Lecture de l'état des Pushbutton. 
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 
 c.f. :
 https://arduino-info.wikispaces.com/LCD-Pushbuttons

PINs qui restent libre et utilisables :
13, 12, 11, 3, 2, 1 et 0
La PIN 10 sert à allumer ou éteindre la "backlight", la rétro - lumière
pinMode(10, OUTPUT);  // Permet d'éteindre ou d'allumer la "backlight"
digitalWrite(10, HIGH);   // allume la "backlight"
digitalWrite(10, LOW);   // éteind la "backlight"

Les PINs  0  et  1  sont utilisés pour la transmission série par USB,
 */

// Inclus la librairie qui gère l'affichage
#include <LiquidCrystal.h>

// Déclaration de Constantes
#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

int nNumButton = 0;  // N° du bouton pressé
int nNumButtonLast = 0;  // N° du dernier bouton pressé

// Initialisation, pour indiquer quelles sont les PINs utilisées par l'afficheur LCD
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20];   // Un "array" de caractères, pour conversion de nombre en un String.
String strS = ""; // Une chaine de caractères.

// Indique le bouton pressé
String astrS[6];  // Indices vont de astrS[0] à astrS[5],  l'indice  6  n'est pas valide !

void setup() {
//============
// Indique que l'afficheur LCD a deux lignes de 16 caractères
lcd.begin(16, 2);
// Affiche un message au départ, pour vérifier le bon fonctionnement.
lcd.setCursor(0, 0); // Première colonne, première ligne
lcd.print("hello, world!");
lcd.setCursor(0, 1); // Première colonne, deuxième ligne
lcd.print("bonjour a tous!");  // Les caractères accentués ne passent pas.
delay(2000);
lcd.setCursor(0, 0);           // Première ligne
lcd.print("                "); // efface le texte 16 caractères
lcd.setCursor(0, 1);           // Deuxième ligne
lcd.print("                "); // efface le texte 16 caractères
//lcd.autoscroll();

// Texte qui peut etre affiché
astrS[btnNONE]   = "None  ";
astrS[btnSELECT] = "Select";
astrS[btnLEFT]   = "Left  ";
astrS[btnDOWN]   = "Down  ";
astrS[btnUP]     = "Up    ";
astrS[btnRIGHT]  = "Right ";

pinMode(10, OUTPUT); // Permet d'allumer ou d'éteindre le rétro-éclairage.
digitalWrite(10, HIGH); // allume le rétro-éclairage
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
int nAdc_key_in = analogRead(0); // Lecture du bouton pressé
delay(5); // Attente, pour laisser des rebonds se terminer.
int nAdc_Delta = (analogRead(0) - nAdc_key_in); // Deuxième lecture du bouton, pour vérification.
if (5 < abs(nAdc_Delta)) return btnNONE;  // Si la deuxième lecture est trop différente de la première, ignore le bouton.
// Mes valeurs lues sont :                            0, 130, 306, 479,  720,  1023
//                                                  Right Up Down Left  Select none
// On additionne environ 50 à ces valeurs pour tester dans quelle tranche la valeur a été lue
if (nAdc_key_in > 800) return btnNONE; // Ce test vient en premier, car c'est la réponse la plus habituelle
if (nAdc_key_in > 550) return btnSELECT; // entre 479 et 800
if (nAdc_key_in > 380) return btnLEFT;   // entre 306 et 479
if (nAdc_key_in > 180) return btnDOWN;   // entre 130 et 306
if (nAdc_key_in >  70) return btnUP;     // entre   0 et 130
return btnRIGHT;  // adc__key_in est plus petit que 71
}

void loop() {
//===========
// Affichage du temps sur la 2ème ligne
lcd.setCursor(0, 1);

// Affiche le temps en secondes, depuis le départ.
//delay(100);
// Pour sprintf, c.f. https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
// %d ou %i pour signed decimal integer
// %u pour unsigned decimal integer
// %ld ou %li pour long signed decimal integer
// %lu pour long unsigned decimal integer
//sprintf(acStr, "%8.3f", millis()/1000.0); // Ne fonctionne pas
//sprintf(acStr, "%9lu", millis()); // Fonctionne bien
dtostrf(millis()/1000.0, 12, 3, acStr);  // Marche bien pour convertir un float en un string, avec un format
// millis()  retourne le nombre de millisecondes écoulé depuis la mise sous tension ou le reset de l'Arduino
lcd.print(acStr);

// La lecture des boutons se fait par l'intermédiaire du port A0
int sensorValue = analogRead(0);
//sprintf(acStr, "%4d  %4d    ", sensorValue, read_LCD_buttons()); // Fonctionne bien
sprintf(acStr, "%4d ", sensorValue); 
if (nNumButton != btnNONE) nNumButtonLast = nNumButton; // mémorise le dernier bouton pressé
nNumButton = read_LCD_buttons();  // Lecture du bouton pressé
strS = acStr + astrS[nNumButton];
lcd.setCursor(0, 0);
lcd.print(strS);

if (nNumButton == btnSELECT) {
  if (nNumButtonLast == btnDOWN) digitalWrite(10, LOW); // éteind le rétro-éclairage
  if (nNumButtonLast == btnUP) digitalWrite(10, HIGH); // allume le rétro-éclairage
  }
} // loop
ex0130 blink
ex0130_liquid_crystal_hello_world.ino : L'afficheur LCD se fiche dans la carte Arduino.
On peut ajouter des connecteurs dans les 7 trous du haut et les trous du bas de l'afficheur LCD,
pour accéder aux PINs 13, 12, 11, 3, 2, 1, 0 et A1 à A5. (A0 est utilisé pour tester l'état des boutons.)
La PIN 10 sert à allumer ou éteindre le rétro-éclairage.


    - Suivant, ex0140   ;   Précédent, ex0130
ex0131_liquid_crystal_hello_world.ino   TOP
Test l'afficheur LCD (à cristaux liquides) de deux lignes de 16 caractères.
La lecture des boutons est rapide (100 microsecondes), mais faire en plusieurs appels de la fonction de lecture d'état des boutons. C'est pratique pour les programmes sensible au temps, tels que les générateurs de fréquence.
/*
ex0131_liquid_crystal_hello_world
Utilise l'affichage LCD (à cristaux liquides),
pour afficher du texte.
De plus, il existe un "shield" qui ajoute 5 boutons en plus du bouton reset,
pour avoir des entrées possibles.
Ainsi, l'Arduino devient autonome pour beaucoup d'applications,
sans nécessité d'un ordinateur pour l'utiliser et
afficher des résultats.

La lecture des boutons se fait en plusieurs passes,
mais chaque passe prend environ 100 micro-secondes.
C'est un avantage pour les applications sensibles au temps,
telles que les générateurs de fréquences.

Ici, l'afficheur écrit "Hello World!" et "Bonjour a tous!"
Puis mesure le temps et indique quelle touche est pressée.
  
Affichage d'un texte.
Lecture de l'état des Pushbutton. 
 
 Demonstrates the use a 16x2 LCD display.  The LiquidCrystal
 library works with all LCD displays that are compatible with the 
 Hitachi HD44780 driver. There are many of them out there, and you
 can usually tell them by the 16-pin interface.
 
 This sketch prints "Hello World!" to the LCD
 and shows the time.
 
  The circuit:
 * LCD RS pin to digital pin 8
 * LCD Enable pin to digital pin 9
 * LCD D4 pin to digital pin 4
 * LCD D5 pin to digital pin 5
 * LCD D6 pin to digital pin 6
 * LCD D7 pin to digital pin 7
 * 10K resistor:
 * ends to +5V and ground
 * wiper to LCD VO pin (pin 3)

 http://www.arduino.cc/en/Tutorial/LiquidCrystal
 
 c.f. :
 https://arduino-info.wikispaces.com/LCD-Pushbuttons

PINs qui restent libre et utilisables :
13, 12, 11, 3, 2, 1 et 0
La PIN 10 sert à allumer ou éteindre la "backlight", la rétro - lumière
pinMode(10, OUTPUT);  // Permet d'éteindre ou d'allumer la "backlight"
digitalWrite(10, HIGH);   // allume la "backlight"
digitalWrite(10, LOW);   // éteind la "backlight"

Les PINs  0  et  1  sont utilisés pour la transmission série par USB,
 */

// Inclus la librairie qui gère l'affichage
#include <LiquidCrystal.h>

// Déclaration de Constantes
#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

int nNumButton = 0;  // N° du bouton pressé
int nNumButtonLast = 0;  // N° du dernier bouton pressé

// Initialisation, pour indiquer quelles sont les PINs utilisées par l'afficheur LCD
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
LiquidCrystal   lcd(8, 9, 4, 5, 6, 7);
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20];   // Un "array" de caractères, pour conversion de nombre en un String.
String strS = ""; // Une chaine de caractères.

// Indique le bouton pressé
String astrS[6];  // Indices vont de astrS[0] à astrS[5],  l'indice  6  n'est pas valide !

unsigned long lwTempsStart = 0; // temps en milli secondes du départ
unsigned long lwTempsStop = 0; // temps en milli secondes de l'arret

void setup() {
//============
// Indique que l'afficheur LCD a deux lignes de 16 caractères
lcd.begin(16, 2);
// Affiche un message au départ, pour vérifier le bon fonctionnement.
lcd.setCursor(0, 0); // Première colonne, première ligne
lcd.print("hello, world!");
lcd.setCursor(0, 1); // Première colonne, deuxième ligne
lcd.print("bonjour a tous!");  // Les caractères accentués ne passent pas.
delay(2000);
lcd.setCursor(0, 0);           // Première ligne
lcd.print("                "); // efface le texte 16 caractères
lcd.setCursor(0, 1);           // Deuxième ligne
lcd.print("                "); // efface le texte 16 caractères
//lcd.autoscroll();

// Texte qui peut etre affiché
astrS[btnRIGHT]  = "Right ";
astrS[btnUP]     = "Up    ";
astrS[btnDOWN]   = "Down  ";
astrS[btnLEFT]   = "Left  ";
astrS[btnSELECT] = "Select";
astrS[btnNONE]   = "None  ";

pinMode(10, OUTPUT); // Permet d'allumer ou d'éteindre le rétro-éclairage.
digitalWrite(10, HIGH); // allume le rétro-éclairage
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
// Il faut détecter 10 fois de suite le même bouton pour qu'on estime détecté le bon bouton pressé.
// L'avantage de cette manière de faire est que la lecture des boutons ne prend que
// le temps d'une lecture analogique, soit environ 100 micro secondes.
int nAdc_key_in = 0;
byte bButton = btnNONE; // Button pressed according to the value of adc_key_in
static byte bButtonLast = btnNONE; // Last button
static byte bButtonCount = 0; // compte le nombre de fois que le même boutton est détecté à la suite.

nAdc_key_in = analogRead(0);  // Lecture de la valeur du bouton pressé. 
// La lecture des boutons sont centrée autour des valeurs  0, 144, 329, 504, 741
// J'ai ajouté environ 50 à ces valeurs pour la détection des boutons

if (nAdc_key_in > 790) { 
  // Aucun bouton pressé.
  bButtonLast = btnNONE;
  bButtonCount = 0;
  return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  }
else if (nAdc_key_in > 555) bButton = btnSELECT;
else if (nAdc_key_in > 380) bButton = btnLEFT; 
else if (nAdc_key_in > 195) bButton = btnDOWN; 
else if (nAdc_key_in >  55) bButton = btnUP; 
else                        bButton = btnRIGHT;
  
if (bButton == bButtonLast) {
  // Le même bouton a été détecté
  if (bButtonCount > 10) return bButton;   // Le même bouton a été détecté .. fois de suite, donc c'est le bon
  bButtonCount++;  // compte combien de fois de suite le même bouton est détecté.
  }
else {
  // Un nouveau bouton est détecté.
  bButtonLast = bButton;
  bButtonCount = 1;
  }

return btnNONE; // On est pas encore sûr que le bon bouton est bButton.
} // read_LCD_buttons

void loop() {
//===========
// Affichage du temps sur la 2ème ligne
lcd.setCursor(0, 1);

// print the number of seconds since reset:
//delay(100);
// Pour sprintf, c.f. https://www.tutorialspoint.com/c_standard_library/c_function_sprintf.htm
// %d ou %i pour signed decimal integer
// %u pour unsigned decimal integer
// %ld ou %li pour long signed decimal integer
// %lu pour long unsigned decimal integer
//sprintf(acStr, "%8.3f", millis()/1000.0); // Ne fonctionne pas
//sprintf(acStr, "%9lu", millis()); // Fonctionne bien
//dtostrf(millis()/1000.0, 12, 3, acStr);  // Marche bien pour convertir un float en un string, avec un format
// millis()  retourne le nombre de millisecondes écoulé depuis la mise sous tension ou le reset de l'Arduino
//lcd.print(acStr);

// La lecture des boutons se fait par l'intermédiaire du port A0
int sensorValue = analogRead(0);
//sprintf(acStr, "%4d  %4d    ", sensorValue, read_LCD_buttons()); // Fonctionne bien
sprintf(acStr, "%4d ", sensorValue); 
if (nNumButton != btnNONE) nNumButtonLast = nNumButton; // mémorise le dernier bouton pressé
nNumButton = read_LCD_buttons();  // Lecture du bouton pressé
strS = acStr + astrS[nNumButton];
lcd.setCursor(0, 0);
lcd.print(strS);

if (nNumButton == btnLEFT) {
   // temps de départ
   lwTempsStart = millis();
   }

if ((nNumButton == btnRIGHT) && (lwTempsStart > 0)) {
   // temps de d'arret
   lwTempsStop = millis();
   dtostrf((lwTempsStop - lwTempsStart)/1000.0, 12, 3, acStr); 
   lcd.setCursor(0, 1);
   lcd.print(acStr);
   lwTempsStart = 0;
   }

if (lwTempsStart > 0) {
   // affichage du temps
   lwTempsStop = millis();
   dtostrf((lwTempsStop - lwTempsStart)/1000.0, 12, 3, acStr); 
   lcd.setCursor(0, 1);
   lcd.print(acStr);   
   }

if (nNumButton == btnSELECT) {
  if (nNumButtonLast == btnDOWN) digitalWrite(10, LOW); // éteind le rétro-éclairage
  if (nNumButtonLast == btnUP) digitalWrite(10, HIGH); // allume le rétro-éclairage
  }
} // loop
ex0130 blink
ex0131_liquid_crystal_hello_world.ino : L'afficheur LCD se fiche dans la carte Arduino.
On peut ajouter des connecteurs dans les 7 trous du haut et les trous du bas de l'afficheur LCD,
pour accéder aux PINs 13, 12, 11, 3, 2, 1, 0 et A1 à A5. (A0 est utilisé pour tester l'état des boutons.)
La PIN 10 sert à allumer ou éteindre le rétro-éclairage.


    - Suivant, ex0142   ;   Précédent, ex0131
ex0140_Frequences_HP_Menu_LiquidCrystal.ino   TOP
Pour faire vibrer un H.P. a une fréquence précise, de quelques dizaines ou centaines de Hz.
Montre également l'utilisation d'un menu avec l'afficheur à critaux liquide.
/*
ex0140_Frequences_HP_Menu_LiquidCrystal
Pour faire vibrer un H.P. a une fréquence précise, de quelques dizaines de Hz.
Montre également l'utilisation d'un menu avec l'afficheur à critaux liquide

Connections :
LCD   Arduino (pin) ou tension
 1 - Vss = 0 V
 2 - Vcc = 5 V
 3 - V0 = Tension variable réglée par une résistance variable, pour la lumineusité de l'affichage
 4 - RS = pin 7 (Register Select) 
 5 - R/W = 0 V donc uniquement en Write
 6 - E = pin 6  Enable, mise à haut pour accepter les données.
 7 .. 10 = connecté à la commande de rétro-éclairage "back light"
11 - D4 = pin 5, données sur 4 bits 
12 - D5 = pin 4, données sur 4 bits 
13 - D6 = pin 3, données sur 4 bits 
14 - D7 = pin 2, données sur 4 bits 
15 - LED + = 220 Ohm - +5V
16 - LED - = 0V

Autres connexions :
push button 1 - pin  8
push button 2 - pin  9
push button 3 - pin 10
push button 4 - pin 11
Tension réglée par une résistance variable - Analog 0
Tension réglée par une résistance variable - Analog 1

Sortie commande de la LED - pin 13, juste pour montrer que le code a été chargé.

This example code is in the public domain.

c.f. : http://www.arduino.cc/en/Tutorial/LiquidCrystal
c.f. : https://arduino-info.wikispaces.com/LCD-Pushbuttons

Pin qui restent libre et utilisables :
pin 0, pin 1, utilisé pour la transmission par USB,
======================================================== */

// include the library code:
#include <LiquidCrystal.h>

// Déclaration de Constantes
#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

#define pinFreqP  2 // pour générer une fréquence
#define pinFreqN  3 // = état opposé à celui de pintFreqP lors du fonctionnement.
#define pinFreqOnOff 11 // pour enclencher ou arrêter le générateur de fréquences

// initialize the library with the numbers of the interface pins
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String strS = ""; 
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20]; // Pour conversion de nombre en un string.

int  nButtonPush = btnNONE; // Bouton pressé
byte bMenu1 = 4;  // indique le menu sélectionné
byte bMenu1_Last = 0;  // indique le dernier menu sélectionné
                         // que lorsque adc_key_in a suffisemment changé.
String strCode = ""; // pour indiquer l'état du code

byte bEtat0 = 0; // Etat du signal 0 de la LED de la pin 13
byte bEtat1 = 0; // Etat du signal 1,  LOW=0 ou HIGH=1
byte bEtat_enable = 0; // Etat de la pin "enable" du contrôle de l'Haut-Parleur

unsigned long lwFrequ1 = 30000; // Fréquence au millième de Herz du signal 1 (PINs 2 et 3)
unsigned long lwTemps = 0; // temps en micro secondes
unsigned long lwTempsActionLast = 0; // temps en micro secondes de la dernière commande 
unsigned long lwTempsNext1 = 0; // Temps en micro secondes de la prochaine transition du signal 1 (PINs 2 et 3)
unsigned long lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période en micro-secondes du signal 1 (PINs 2 et 3)

unsigned long lwTempsSignal0 = 100000; // temps en micros-seconde d'un état du signal de la pin 13
unsigned long lwTempsLast0 = 0;  // temps de la dernière transision du signal 0 LED de la pin 13


void setup() {
//============  
// set up the LCD's number of columns and rows: 
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Pour H.P. freq.");
delay(800);
lcd.setCursor(0, 0);
lcd.print("             "); // efface le texte
//lcd.autoscroll();

lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période du signal 1
lwTemps = micros();
lwTempsNext1   = lwTemps;

pinMode(13, OUTPUT); // clignote, pour indiquer que tout fonctionne correctement.
pinMode(pinFreqOnOff, OUTPUT); // 
pinMode( pinFreqN, OUTPUT);  // controle une borne de l'haut-parleur
pinMode( pinFreqP, OUTPUT);  // controle l'autre borne de l'haut-parleur

bEtat_enable = 0; // = LOW
digitalWrite(pinFreqOnOff, LOW);  // Arrêté
digitalWrite( pinFreqN, LOW);  // borne 1 à 0 V
digitalWrite( pinFreqP, LOW);  // borne 2 à 0 V

AfficheEtat();
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
// Il faut détecter 10 fois de suite le même bouton pour qu'on estime détecté le bon bouton pressé.
// L'avantage de cette manière de faire est que la lecture des boutons ne prend que
// le temps d'une lecture analogique, soit environ 100 micro secondes.
int nAdc_key_in = 0;
byte bButton = btnNONE; // Button pressed according to the value of adc_key_in
static byte bButtonLast = btnNONE; // Last button
static byte bButtonCount = 0; // compte le nombre de fois que le même boutton est détecté à la suite.

nAdc_key_in = analogRead(0);  // Lecture de la valeur du bouton pressé. 
// La lecture des boutons sont centrée autour des valeurs  0, 144, 329, 504, 741
// J'ai ajouté environ 50 à ces valeurs pour la détection des boutons

if (nAdc_key_in > 790) { 
  // Aucun bouton pressé.
  bButtonLast = btnNONE;
  bButtonCount = 0;
  return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  }
else if (nAdc_key_in > 555) bButton = btnSELECT;
else if (nAdc_key_in > 380) bButton = btnLEFT; 
else if (nAdc_key_in > 195) bButton = btnDOWN; 
else if (nAdc_key_in >  55) bButton = btnUP; 
else                        bButton = btnRIGHT;
  
if (bButton == bButtonLast) {
  // Le même bouton a été détecté
  if (bButtonCount > 10) return bButton;   // Le même bouton a été détecté .. fois de suite, donc c'est le bon
  bButtonCount++;  // compte combien de fois de suite le même bouton est détecté.
  }
else {
  // Un nouveau bouton est détecté.
  bButtonLast = bButton;
  bButtonCount = 1;
  }

return btnNONE; // On est pas encore sûr que le bon bouton est bButton.
} // read_LCD_buttons

void AfficheEtat() {
//==================
// Affichage de la fréquence ou de la variation de fréquence, suivant le menu

if (bMenu1 <= 5) {
  // Affiche Fréquence du signal 1
  if (bMenu1 != bMenu1_Last) {
    lcd.setCursor(0, 0);
    if      (bMenu1 == 1) lcd.print("Frequ +-0.001 Hz");
    else if (bMenu1 == 2) lcd.print("Frequ +- 0.01 Hz");
    else if (bMenu1 == 3) lcd.print("Frequ +- 0.10 Hz");
    else if (bMenu1 == 4) lcd.print("Frequ +- 1 Hz   ");
    else if (bMenu1 == 5) lcd.print("Frequ +- 10 Hz  ");
    }
  
  dtostrf(lwFrequ1/1000.0, 8, 3, acStr);
  strS = acStr;
  strS = "Frequ.= " + strS;
  lcd.setCursor(0, 1);
  lcd.print(strS);
  }

} // AfficheEtat

void MenuTreat() {
//================
// On a appuyé sur un bouton, traite l'action adéquat.

// Mémorise le temps de la dernière action utilisateur, pour pas en faire plusieurs lorsqu'on presse sur un bouton
lwTempsActionLast = micros();

if (bMenu1 == 1) {
  // Changement de fréquence du signal 1 de +-1 milli-Hz
  if (nButtonPush == btnUP) lwFrequ1 += 1;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 1;
  }

if (bMenu1 == 2) {
  // Changement de fréquence du signal 1 de +-10 milli-Hz
  if (nButtonPush == btnUP) lwFrequ1 += 10;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 10;
  }

if (bMenu1 == 3) {
  // Changement de fréquence du signal 1 de +-100 milli-Hz
  if (nButtonPush == btnUP) lwFrequ1 += 100;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 100;
  }

if (bMenu1 == 4) {
  // Changement de fréquence du signal 1 de +-1 Hz
  if (nButtonPush == btnUP) lwFrequ1 += 1000;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 1000;
  }

if (bMenu1 == 5) {
  // Changement de fréquence du signal 1 de +-10 Hz
  if (nButtonPush == btnUP) lwFrequ1 += 10000;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 10000;
  }

if ((1 <= bMenu1) && (bMenu1 <= 5)) {
  if (lwFrequ1 <      1000) lwFrequ1 = 1000; // Minimum = 1 Hertz
  if (lwFrequ1 > 1500000ul) lwFrequ1 = 1000; // Correction de l'erreur décrite ci-dessous.
  if (lwFrequ1 > 1200000ul) lwFrequ1 = 1200000ul; // Maximum = 1'200 Hertz
  // Ici, il y a une petite erreur (de sémentique). Le programme fonctionne correctement,
  // mais, il ne fait pas exactement ce qu'on veut.
  // Si Le changement de fréquence est de 10 Hz et qu'on diminue une fréquence de 1 à 9 Hz,
  // la fréquence finale sera de 800 Hz.  Il suffit de rajouter la bonne ligne au bon endroit 
  // pour corriger ce problème !

  lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période en micro-secondes du signal
  }

// Le bouton "Select" active ou désactive le signal
if (nButtonPush == btnSELECT) {
  bEtat_enable = 1 - bEtat_enable;
  digitalWrite(pinFreqOnOff, bEtat_enable);  // on - off
  digitalWrite( pinFreqP, bEtat1 & bEtat_enable);       // off si signal désactivé
  digitalWrite( pinFreqN, (1 - bEtat1) & bEtat_enable);
  lwTempsNext1   = lwTemps;
  }

AfficheEtat();
} // MenuTreat

void Menu1_Change() {
//===================
// Changement du Menu1
lwTempsActionLast = micros();

bMenu1_Last = bMenu1; // Mémorise le dernier menu

if (nButtonPush == btnLEFT) {
   bMenu1 -= 1;
   if (bMenu1 == 0) bMenu1 = 5;  // boucle
  }

if (nButtonPush == btnRIGHT) {
   bMenu1 += 1;
   if (bMenu1 > 5) bMenu1 = 1;  // boucle
  }

AfficheEtat();
} // Menu1_Change

void loop() {
//===========
// Génère un signal carré d'une fréquence sélectionnable.
//  Serial.print(sensorValue, DEC);
//    Serial.println();

lwTemps = micros();


// Ne lit l'état des boutons que si un bouton a été traité il y a plus de 0,2 secondes = 200000 [us].
if (lwTemps - lwTempsActionLast > 200000ul) {
   // Lecture de l'état des boutons, pour changer la fréquence ou la phase du signal
   nButtonPush = read_LCD_buttons();

   if ( (nButtonPush == btnLEFT) || (nButtonPush == btnRIGHT) ) Menu1_Change(); // Changement de menu
   if ( (nButtonPush == btnUP) || (nButtonPush == btnDOWN) || (nButtonPush == btnSELECT) ) MenuTreat();  // Un bouton pressé, traitement
   }

// Test si un changement d'état du signal 1 est imminent
if ((lwTemps - lwTempsNext1 + 1000ul >= lwDemiPeriode1) & bEtat_enable) { 
  // Attente avant un changement d'état du signal 1 
  while (lwTemps - lwTempsNext1 < lwDemiPeriode1) { lwTemps = micros(); } // Attente 
  bEtat1 = 1 - bEtat1;
  digitalWrite( pinFreqP, bEtat1); 
  digitalWrite( pinFreqN, 1 - bEtat1); 

  // Prochain changement d'état, faisant vibrer le Haut-Parleur.
  lwTempsNext1 =  lwTempsNext1 + lwDemiPeriode1;
  }
} // loop
ex0140 blink
ex0140_Frequences_HP_Menu_LiquidCrystal.ino
Pour faire vibrer un H.P. a une fréquence précise, de quelques dizaines ou centaines de Hz.
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
Le transistor peut être n'importe quel transistor NPN de puissance, ou n'importe quel transistor MOSFEt de puissance de type N. Par exemple le transistor IRF520 correspond à celui du dessin.
D'autre type possibles : IRF3710 ; IRF740 ; BUK9535 ; 2N6107.
Dans le code, les pins 2 et 11 sont aussi utilisés en plus de la pin 3. Ceci n'est pas utile dans l'exemple ci-dessus, mais est utile si on utilise un pont en H, tel que le L298 (ou L293) qui permet d'inverser les polarités. Un exemple est donné en ex0380 et ex0381, mais sans le dessin.
L'exemple ex0385 donne une image du pont en H du L293. Il faut afficher son code pour voir l'image.


    - Suivant, ex0143   ;   Précédent, ex0140
ex0142_Menu_Do_Re_Mi_Fa_Sol.ino   TOP
Joue les notes : "Do Re Mi Fa Sol La Si Do".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
/*
ex0142_Menu_Do_Re_Mi_Fa_Sol.ino
Joue les notes : "Do Ré Mi Fa Sol La Si Do".

La fréquence de base est modifiable.

La touche Select permet d'enclancher ou arrêter la génération du signal sur les pin 2 et 3.

Utilise l'afficheur LCD 1602 avec 5 boutons, pour gérer un menu.

Connections :
LCD   Arduino (pin) ou tension
 1 - Vss = 0 V
 2 - Vcc = 5 V
 3 - V0 = Tension variable réglée par une résistance variable, pour la lumineusité de l'affichage
 4 - RS = pin 8 (Register Select) 
 5 - R/W = 0 V donc uniquement en Write
 6 - E = pin 9  Enable, mise à haut pour accepter les données.
 7 .. 10 = connecté à la commande de rétro-éclairage "back light"
11 - D4 = pin 4, données sur 4 bits 
12 - D5 = pin 5, données sur 4 bits 
13 - D6 = pin 6, données sur 4 bits 
14 - D7 = pin 7, données sur 4 bits 
15 - LED + = 220 Ohm - +5V
16 - LED - = 0V

Autres connexions :
pin  2 et 3 pour le signal
pin 13 pour indiquer si le HP est on ou off
pin  0, pin 1, utilisées pour la transmission par USB,
ADC  0 pour les lecture les boutons.

c.f. : http://www.arduino.cc/en/Tutorial/LiquidCrystal
c.f. : https://arduino-info.wikispaces.com/LCD-Pushbuttons
======================================================== */

// include the library code:
#include <LiquidCrystal.h>

// Déclaration de Constantes
#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

#define pinFreqP  2 // pour générer une fréquence
#define pinFreqN  3 // = état opposé à celui de pintFreqP lors du fonctionnement.
#define pinFreqOnOff 13 // pour enclencher ou arrêter le générateur de fréquences

// Nombre de menus
# define MENUMAX 4

int nn = 0;   
int adc_key_in = 0;
byte bButton = btnNONE; // Button pressed according to the value of adc_key_in
byte bButtonLast = btnNONE; // dernier bouton
byte bButtonCount = 0; // compte le nombre de fois que le même bouton est détecté à la suite.                         

// initialize the library with the numbers of the interface pins
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String strS = ""; 
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20]; // Pour conversion de nombre en un string.

int  nButtonPush = btnNONE; // Bouton pressé
byte bMenu1 = 4;  // indique le menu sélectionné
byte bMenu1_Last = 0;  // indique le dernier menu sélectionné

byte bEtat0 = 0; // Etat du signal 0,  LOW=0 ou HIGH=1
byte bEtat1 = 0; // Etat du signal 1,  LOW=0 ou HIGH=1
byte bEtat_enable = 0; // Etat de la pin "enable" du contrôle de l'Haut-Parleur

unsigned long lwFrequ1 = 261630; // Fréquence au millième de Herz du Do3 (PINs 2 et 3)
unsigned long lwTemps = 0; // temps en micro secondes
unsigned long lwTempsActionLast = 0; // temps en micro secondes de la dernière commande 
unsigned long lwTempsNext1 = 0; // Temps en micro secondes de la prochaine transition du signal 1 (PINs 2 et 3)
unsigned long lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période en micro-secondes du signal 1 (PINs 2 et 3)

unsigned long lwTempsSignal0 = 100000; // temps en micros-seconde d'un état du signal de la pin 13
unsigned long lwTempsLast0 = 0;  // temps de la dernière transision du signal 0 LED de la pin 13

unsigned long freqCalc = 0;
unsigned long modeleTempsNote = 250000;
unsigned long tempsNote = 0;
unsigned short ptrStep = 1;

void setup() {
//============  
// set up the LCD's number of columns and rows: 
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Do Re mi Fa ... ");
lcd.setCursor(0, 1);
lcd.print("ex0142 20181019 ");
delay(1200);
lcd.setCursor(0, 0);
lcd.print("                "); // efface le texte
lcd.setCursor(0, 1);
lcd.print("                ");

lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période du signal 1
lwTemps = micros();
lwTempsNext1   = lwTemps;

pinMode( pinFreqOnOff, OUTPUT); // 
pinMode( pinFreqN, OUTPUT);  // controle une borne de l'haut-parleur
pinMode( pinFreqP, OUTPUT);  // controle l'autre borne de l'haut-parleur

bEtat_enable = 0; // = LOW
digitalWrite( pinFreqOnOff, LOW);  // Arrêté
digitalWrite( pinFreqN, LOW);  // borne 1 à 0 V
digitalWrite( pinFreqP, LOW);  // borne 2 à 0 V

AfficheEtat();
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
// Il faut détecter 10 fois de suite le même bouton pour qu'on estime détecté le bon bouton pressé.
// L'avantage de cette manière de faire est que la lecture des boutons ne prend que
// le temps d'une lecture analogique, soit environ 100 micro secondes.
adc_key_in = analogRead(0);  // read the value from the sensor 
// La lecture des boutons sont centrée autour des valeurs  0, 144, 329, 504, 741
// J'ai ajouté environ 50 à ces valeurs pour la détection des boutons

if (adc_key_in > 790) { 
  // Aucun bouton pressé.
  bButtonLast = btnNONE;
  bButtonCount = 0;
  return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  }
else if (adc_key_in > 555) bButton = btnSELECT;
else if (adc_key_in > 380) bButton = btnLEFT; 
else if (adc_key_in > 195) bButton = btnDOWN; 
else if (adc_key_in >  55) bButton = btnUP; 
else                       bButton = btnRIGHT;
  
if (bButton == bButtonLast) {
  // Le même bouton a été détecté
  if (bButtonCount > 10) return bButton;   // Le même bouton a été détecté .. fois de suite, donc c'est le bon
  bButtonCount++;  // compte combien de fois de suite le même bouton est détecté.
  }
else {  
  bButtonLast = bButton;
  bButtonCount = 1;
  }

return btnNONE; // On est pas encore sûr que le bon bouton est bButton.
} // read_LCD_buttons

void AfficheEtat() {
//==================
// Affichage de la fréquence ou de la variation de fréquence, suivant le menu

// Affiche Fréquence du signal 1
if (bMenu1 != bMenu1_Last) {
  lcd.setCursor(0, 0);
       if (bMenu1 == 1) lcd.print("Frequ +- 0.10 Hz");
  else if (bMenu1 == 2) lcd.print("Frequ +-   1  Hz");
  else if (bMenu1 == 3) lcd.print("Frequ +-  10  Hz");
  else if (bMenu1 == 4) lcd.print("Frequ +- 100  Hz");
  }

dtostrf(lwFrequ1/1000.0, 8, 3, acStr);
strS = acStr;
strS = "Frequ.= " + strS;
lcd.setCursor(0, 1);
lcd.print(strS);
} // AfficheEtat

void MenuTreat() {
//================
// On a appuyé sur un bouton, traite l'action adéquat.

// Mémorise le temps de la dernière action utilisateur, pour pas en faire plusieurs lorsqu'on presse sur un bouton
lwTempsActionLast = micros();

if (bMenu1 == 1) {
  // Changement de fréquence du signal 1 de +-100 milli-Hz
  if (nButtonPush == btnUP)   lwFrequ1 += 100;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 100;
  }

if (bMenu1 == 2) {
  // Changement de fréquence du signal 1 de +-1 Hz
  if (nButtonPush == btnUP)   lwFrequ1 += 1000;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 1000;
  }

if (bMenu1 == 3) {
  // Changement de fréquence du signal 1 de +-10 Hz
  if (nButtonPush == btnUP)   lwFrequ1 += 10000;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 10000;
  }

if (bMenu1 == 4) {
  // Changement de fréquence du signal 1 de +-100 Hz
  if (nButtonPush == btnUP)   lwFrequ1 += 100000ul;
  if (nButtonPush == btnDOWN) lwFrequ1 -= 100000ul;
  }

if ( (1 <= bMenu1) && (bMenu1 <= MENUMAX) ) {
  if (lwFrequ1 <     1000)   lwFrequ1 =     1000; // Minimum = 1 Hertz
  if (lwFrequ1 > 15000000ul) lwFrequ1 =     1000; // Si "undeerflow", assure que la fréquence soit de 1 Hz.
  if (lwFrequ1 > 10000000ul) lwFrequ1 = 10000000ul; // Maximum = 10'000 Hertz. Bien avant, on est limité par la vitesse de la boucle "loop".
  
  lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période en micro-secondes du signal, sera changé à la fin de la mélodie
  }

// Le bouton "Select" active ou désactive le signal
if (nButtonPush == btnSELECT) {
  bEtat_enable = 1 - bEtat_enable;
  digitalWrite( pinFreqOnOff, bEtat_enable);  // on - off
  digitalWrite( pinFreqP, bEtat1 & bEtat_enable);       // off si signal désactivé
  digitalWrite( pinFreqN, (1 - bEtat1) & bEtat_enable); 
  }

ptrStep=0; // Pour démarrer avec un Do
defTemps(-360, 4); // Pause

AfficheEtat();
} // MenuTreat

void Menu1_Change() {
//===================
// Changement du Menu1
// Ne fait rien ici, mais gardé pour conserver la structure habituelle des menus.
lwTempsActionLast = micros();

bMenu1_Last = bMenu1; // Mémorise le dernier menu

if (nButtonPush == btnLEFT) {
  bMenu1 -= 1;
  if (bMenu1 == 0) bMenu1 = MENUMAX;  // boucle
  }

if (nButtonPush == btnRIGHT) {
  bMenu1 += 1;
  if (bMenu1 > MENUMAX) bMenu1 = 1;  // boucle
  }

AfficheEtat();
} // Menu1_Change

void defTemps(int nPow, int nDuration) {
//======================================
// Change la note et la durée et prépare le passage à la note suivante.
freqCalc = lwFrequ1 * pow(1.05946, nPow) ; 
tempsNote = lwTemps + modeleTempsNote*nDuration;
ptrStep += 1;
} // defTemps

void son() {
//==========  
// Test si un changement d'état du signal 1 est imminent
if ((lwTemps - lwTempsNext1 + 1000ul >= lwDemiPeriode1) & bEtat_enable) { 
  // Attente avant un changement d'état du signal 1 (stabiliser) 
  while (lwTemps - lwTempsNext1 < lwDemiPeriode1) { lwTemps = micros(); } // Attente 

  digitalWrite( pinFreqN, bEtat1); 
  bEtat1 = 1 - bEtat1;
  digitalWrite( pinFreqP, bEtat1); 

  // Prochain changement d'état, faisant vibrer le Haut-Parleur.
  lwTempsNext1 =  lwTempsNext1 + lwDemiPeriode1;
  }
} // son

void loop() {
//===========
// Génère un signal carré d'une fréquence sélectionnable.
//Serial.print(sensorValue, DEC);
//Serial.println();

lwTemps = micros();

// Ne lit l'état des boutons que si un bouton a été traité il y a plus de 0,2 secondes = 200000 [us].
if (lwTemps - lwTempsActionLast > 200000ul) {
  // Lecture de l'état des boutons, pour changer la fréquence ou la phase du signal
  nButtonPush = read_LCD_buttons();

  if ( (nButtonPush == btnLEFT) || (nButtonPush == btnRIGHT) ) Menu1_Change(); // Changement de menu
  if ( (nButtonPush == btnUP) || (nButtonPush == btnDOWN) || (nButtonPush == btnSELECT) ) MenuTreat(); // Un bouton pressé, traitement
  }

// Pour jouer la gamme.
if (lwTemps >= tempsNote) {
  switch (ptrStep) {
    case 1:
      lwTempsNext1 = lwTemps;  // Pour initialiser le générateur de fréquence.
      defTemps(0, 2); // Do
      break;      
    case 2:
      defTemps(2, 2); // Re
      break;
    case 3:
      defTemps(4, 2); // Mi
      break;
    case 4:
      defTemps(5, 2); // Fa
      break;
    case 5:
      defTemps(7, 2); // Sol
      break;
    case 6:
      defTemps(9, 2); // La
      break;
    case 7:
      defTemps(11, 2); // Si
      break;
    case 8:
      defTemps(12, 2); // Do
      break;
    case 9:
      defTemps(-360, 10); // Pause
      ptrStep=1; // Revient au départ.
      break;
     }
   
   // Pour debugging
  sprintf(acStr, "Step = %3d", ptrStep);
  strS = acStr;
  //lcd.setCursor(0, 0);  lcd.print(strS); 
  }

lwDemiPeriode1 = 500000000ul / freqCalc; // Demi période en micro-secondes du signal

son();
} // loop

// FIN
ex0140 blink
ex0142_Frequences_HP_Menu_LiquidCrystal.ino
Joue les notes : "Do Re Mi Fa Sol La Si Do".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
C'est le même circuit que celui de : "ex0140".


    - Suivant, ex0150   ;   Précédent, ex0142
ex0143_Menu_Jai_du_bon_tabac.ino   TOP
Joue la mélodie : "J'ai du bon tabac dans ma tabatière".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
Utilisation de tableaux, pour mémoriser la suite de notes à jouer.
Utilisation d'un pointeur sur le tableau contenant la mélodie désirée.
/*
ex0143_Menu_Jai_du_bon_tabac.ino

Joue la mélodie : J'ai du bon tabac dans ma tabatière.
Permet aussi de jouer la gamme et de jouer la mélodie de "Frère Jacques".

Utilise l'afficheur LCD 1602 avec 5 boutons pour gérer un menu.

Connections :
LCD   Arduino (pin) ou tension
 1 - Vss = 0 V
 2 - Vcc = 5 V
 3 - V0 = Tension variable réglée par une résistance variable, pour la lumineusité de l'affichage
 4 - RS = pin 8 (Register Select) 
 5 - R/W = 0 V donc uniquement en Write
 6 - E = pin 9  Enable, mise à haut pour accepter les données.
 7 .. 10 = connecté à la commande de rétro-éclairage "back light"
11 - D4 = pin 4, données sur 4 bits 
12 - D5 = pin 5, données sur 4 bits 
13 - D6 = pin 6, données sur 4 bits 
14 - D7 = pin 7, données sur 4 bits 
15 - LED + = 220 Ohm - +5V
16 - LED - = 0V

Autres connexions :
pin  2 et 3 pour le signal
pin 13 pour indiquer si le HP est on ou off
pin  0, pin 1, utilisées pour la transmission par USB,
ADC  0 pour les lecture les boutons.

c.f. : http://www.arduino.cc/en/Tutorial/LiquidCrystal
c.f. : https://arduino-info.wikispaces.com/LCD-Pushbuttons
======================================================== */

// include the library code:
#include <LiquidCrystal.h>

// Déclaration de Constantes
#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

#define pinFreqP  2 // pour générer une fréquence
#define pinFreqN  3 // = état opposé à celui de pintFreqP lors du fonctionnement.
#define pinFreqOnOff 13 // pour enclencher ou arrêter le générateur de fréquences

// Nombre de menus
# define MENUMAX 1

int nn = 0;   
int adc_key_in = 0;
byte bButton = btnNONE; // Button pressed according to the value of adc_key_in
byte bButtonLast = btnNONE; // dernier bouton
byte bButtonCount = 0; // compte le nombre de fois que le même bouton est détecté à la suite.                         

// initialize the library with the numbers of the interface pins
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String strS = ""; 
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20]; // Pour conversion de nombre en un string.

int  nButtonPush = btnNONE; // Bouton pressé
byte bMenu1 = 1;  // indique le menu sélectionné
byte bMenu1_Last = 0;  // indique le dernier menu sélectionné
                         // que lorsque adc_key_in a suffisemment changé.

byte bEtat1 = 0; // Etat du signal 1,  LOW=0 ou HIGH=1
byte bEtat_enable = 0; // Etat de la pin "enable" du contrôle de l'Haut-Parleur

unsigned long lwFrequ1 = 261630; // Fréquence au millième de Herz du Do3 (PINs 2 et 3)
unsigned long lwTemps = 0; // temps en micro secondes
unsigned long lwTempsActionLast = 0; // temps en micro secondes de la dernière commande 
unsigned long lwTempsNext1 = 0; // Temps en micro secondes de la prochaine transition du signal 1 (PINs 2 et 3)
unsigned long lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période en micro-secondes du signal 1 (PINs 2 et 3)

unsigned long lwTempsSignal0 = 100000; // temps en micros-seconde d'un état du signal de la pin 13
unsigned long lwTempsLast0 = 0;  // temps de la dernière transision du signal 0 LED de la pin 13

unsigned long freqCalc = 0;
unsigned long modeleTempsNote = 250000;
unsigned long tempsNote = 0;
unsigned short ptrStep = 1;

#define pause -360
#define sol2  -5
#define do3    0
#define re3    2
#define mi3    4
#define fa3    5
#define sol3   7
#define la3    9
#define si3   11
#define do4   12
#define re4   14

// La gamme
//int anNotes[] = {0,2, 2,2, 4,2, 5,2, 7,2, 9,2, 11,2, 12,2, 0,0}; // 0,0 marque la fin
int anNotes1[] = {do3,2, re3,2, mi3,2, fa3,2, sol3,2, la3,2, si3,2, do4,2, 0,0}; // 0,0 marque la fin

// Frère Jacques
int anNotes2[] = { do3,2, re3,2, mi3,2, do3,2, do3,2, re3,2, mi3,2, do3,2, 
                   mi3,2, fa3,2, sol3,4, mi3,2, fa3,2, sol3,4, 
                   sol3,1, la3,1, sol3,1, fa3,1, mi3,2, do3,2,
                   sol3,1, la3,1, sol3,1, fa3,1, mi3,2, do3,2,
                   do3,2, sol2,2, do3,4,
                   do3,2, sol2,2, do3,4,
                   0,0}; // 0,0 marque la fin

// J'ai du bon tabac  c.f. https://www.apprendrelaflute.com/j-ai-du-bon-tabac-dans-ma-tabatiere
int anNotes3[] = { sol3,2, la3,2, si3,2, sol3,2, la3,4, la3,2, si3,2,
                  do4,4, do4,4, si3,4, si3,4,
                  sol3,2, la3,2, si3,2, sol3,2, la3,4, la3,2, si3,2,
                  do4,4, re4,4, sol3,6, pause,2,
                  re4,4, re4,2, do4,2, si3,4, la3,2, si3,2,
                  do4,4, re4,4, la3,6, pause,2,
                  re4,4, re4,2, do4,2, si3,4, la3,2, si3,2,
                  do4,4, re4,4, la3,6, pause,2,
                  pause,8,
                  0,0}; // 0,0 marque la fin

int* panNotes = anNotes3; // Pointe sur la mélodie à jouer.
int nNumMelodie = 3;  // Numéro de la mélodie jouée.
int* apanNotes[] = {anNotes1, anNotes1, anNotes2, anNotes3}; // Tableau de pointeurs sur des tableaux de notes.

void setup() {
//============  
// set up the LCD's number of columns and rows: 
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("jai du bon tabac");
lcd.setCursor(0, 1);
lcd.print("ex0143 20200621 ");
delay(1200);
lcd.setCursor(0, 0);
lcd.print("                "); // efface le texte
lcd.setCursor(0, 1);
lcd.print("                ");

lwDemiPeriode1 = 500000000ul / lwFrequ1; // Demi période du signal 1
lwTemps = micros();
lwTempsNext1   = lwTemps;

//pinMode(13, OUTPUT); // clignote, pour indiquer que tout fonctionne correctement. (test)
pinMode( pinFreqOnOff, OUTPUT); // 
pinMode( pinFreqN, OUTPUT);  // controle une borne de l'haut-parleur
pinMode( pinFreqP, OUTPUT);  // controle l'autre borne de l'haut-parleur

bEtat_enable = 1; // = HIGH
digitalWrite( pinFreqOnOff, bEtat_enable);  // Indique si marche ou arrêt
digitalWrite( pinFreqN, LOW);  // borne 1 à 0 V
digitalWrite( pinFreqP, LOW);  // borne 2 à 0 V

AfficheEtat();
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
// Il faut détecter 10 fois de suite le même bouton pour qu'on estime détecté le bon bouton pressé.
// L'avantage de cette manière de faire est que la lecture des boutons ne prend que
// le temps d'une lecture analogique, soit environ 100 micro secondes.
adc_key_in = analogRead(0);  // read the value from the sensor 
// La lecture des boutons sont centrée autour des valeurs  0, 144, 329, 504, 741
// J'ai ajouté environ 50 à ces valeurs pour la détection des boutons

if (adc_key_in > 790) { 
  // Aucun bouton pressé.
  bButtonLast = btnNONE;
  bButtonCount = 0;
  return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  }
else if (adc_key_in > 555) bButton = btnSELECT;
else if (adc_key_in > 380) bButton = btnLEFT; 
else if (adc_key_in > 195) bButton = btnDOWN; 
else if (adc_key_in >  55) bButton = btnUP; 
else                       bButton = btnRIGHT;
  
if (bButton == bButtonLast) {
  // Le même bouton a été détecté
  if (bButtonCount > 10) return bButton;   // Le même bouton a été détecté .. fois de suite, donc c'est le bon
  bButtonCount++;  // compte combien de fois de suite le même bouton est détecté.
  }
else {  
  bButtonLast = bButton;
  bButtonCount = 1;
  }

return btnNONE; // On est pas encore sûr que le bon bouton est bButton.
} // read_LCD_buttons

void AfficheEtat() {
//==================
// Affichage de la fréquence ou de la variation de fréquence, suivant le menu

// Affiche la mélodie jouée
lcd.setCursor(0, 0);
lcd.print("Melodie :      ");

lcd.setCursor(0, 1);
if      (nNumMelodie == 1) strS = "La Gamme        ";
else if (nNumMelodie == 2) strS = "Frere Jacques   ";
else if (nNumMelodie == 3) strS = "Jai du bon tabac";
  
lcd.print(strS);
} // AfficheEtat

void MenuTreat() {
//================
// On a appuyé sur un bouton, traite l'action adéquat.

// Mémorise le temps de la dernière action utilisateur, pour pas en faire plusieurs lorsqu'on presse sur un bouton
lwTempsActionLast = micros();

if (bMenu1 == 1) {
  // Changement de mélodie
  if (nButtonPush == btnUP) {
    // Passage à la mélodie suivante
    nNumMelodie++;
    if (nNumMelodie > 3) nNumMelodie = 1;
    panNotes = apanNotes[nNumMelodie]; // pointe sur la mélodie à jouer.
    }
      
  if (nButtonPush == btnDOWN) {
    // Passage à la mélodie précédente
    nNumMelodie--;
    if (nNumMelodie <= 0) nNumMelodie = 3;
    panNotes = apanNotes[nNumMelodie]; // pointe sur la mélodie à jouer.
    }

  ptrStep = 0;     // Démarre depuis le début de la mélodie.
  defTemps(-360, 10); // Pause
  }

// Le bouton "Select" active ou désactive le signal
if (nButtonPush == btnSELECT) {
  bEtat_enable = 1 - bEtat_enable;    // on - off
  digitalWrite(pinFreqOnOff, bEtat_enable);
  digitalWrite( pinFreqP, bEtat1 & bEtat_enable);       // off si signal désactivé
  digitalWrite( pinFreqN, (1 - bEtat1) & bEtat_enable); 
  }

AfficheEtat();
} // MenuTreat

void Menu1_Change() {
//===================
// Changement du Menu1
// Structure habituelle des menus.
lwTempsActionLast = micros();

bMenu1_Last = bMenu1; // Mémorise le dernier menu

if (nButtonPush == btnLEFT) {
  bMenu1 -= 1;
  if (bMenu1 == 0) bMenu1 = MENUMAX;  // boucle
  }

if (nButtonPush == btnRIGHT) {
  bMenu1 += 1;
  if (bMenu1 > MENUMAX) bMenu1 = 1;  // boucle
  }

AfficheEtat();
} // Menu1_Change

void defTemps(int nPow, int nDuration) {
//======================================
// Change la note et la durée et prépare le passage à la note suivante.
lwTempsNext1 = lwTemps;  // Pour initialiser le générateur de fréquence.
freqCalc = lwFrequ1 * pow(1.05946, nPow) ; 
tempsNote = lwTemps + modeleTempsNote*nDuration;
ptrStep += 1;
} // defTemps

void son() {
//==========  
// Teste si un changement d'état du signal 1 est imminent.
if ((lwTemps - lwTempsNext1 + 1000ul >= lwDemiPeriode1) & bEtat_enable) { 
  // Attente avant un changement d'état du signal 1 (stabiliser) 
  while (lwTemps - lwTempsNext1 < lwDemiPeriode1) { lwTemps = micros(); } // Attente 

  digitalWrite( pinFreqN, bEtat1); 
  bEtat1 = 1 - bEtat1;
  digitalWrite( pinFreqP, bEtat1); 

  // Prochain changement d'état, faisant vibrer le Haut-Parleur.
  lwTempsNext1 =  lwTempsNext1 + lwDemiPeriode1;
  }
} // son

void loop() {
//===========
// Génère un signal carré d'une fréquence sélectionnable.
//  Serial.print(sensorValue, DEC);
//    Serial.println();

lwTemps = micros();


// Ne lit l'état des boutons que si un bouton a été traité il y a plus de 0,2 secondes = 200000 [us].
if (lwTemps - lwTempsActionLast > 200000ul) {
  // Lecture de l'état des boutons, pour changer la fréquence ou la phase du signal
  nButtonPush = read_LCD_buttons();

  if ( (nButtonPush == btnLEFT) || (nButtonPush == btnRIGHT) ) Menu1_Change(); // Changement de menu
  if ( (nButtonPush == btnUP) || (nButtonPush == btnDOWN) || (nButtonPush == btnSELECT) ) MenuTreat();  // Un bouton pressé, traitement
  }
  
if(tempsNote <= lwTemps) {
  defTemps(panNotes[2*ptrStep - 2], panNotes[2*ptrStep-1]);

  if (panNotes[2*ptrStep-3] == 0) {
    // Fin de la mélodie
    defTemps(-360, 10); // Pause
    ptrStep=1; // Revient au départ.
    }

   // Pour debugging
  sprintf(acStr, "Step = %3d", ptrStep);
  strS = acStr;
  lcd.setCursor(0, 0);   
  lcd.print(strS); 
  }
    
lwDemiPeriode1 = 500000000ul / freqCalc; // Demi période en micro-secondes du signal
  
son();
} // loop

// FIN
ex0140 blink
ex0143_Menu_Jai_du_bon_tabac.ino
Joue la mélodie : "J'ai du bon tabac dans ma tabatière".
Montre également l'utilisation d'un menu avec l'afficheur à cristaux liquide.
C'est le même circuit que celui de : "ex0140".


    - Suivant, ex0161   ;   Précédent, ex0143
ex0150_LED_Matrix.zip   TOP
Pour afficher des symboles sur des matrices de LED.
Cette fois le programme est assez complexe et comporte 5 fichiers.
Aucune image n'est présentée dans cet exemple. Il faut une ou des matrices de LED qui sont contrôlées par un chip MAX 7219.
Le code source est disponible dans le fichier .zip suivant. Il faut garder la structure du répertoire se trouvant dans ce fichier .zip.
En ouvrant le fichier "ex0150_LED_Matrix.ino", les 4 autres fichiers seront également ouverts, dans des onglets.
Il est possible de mettre ces fichiers dans une librairie, ce n'est pas forcément un avantage, surtout lors d'un développement.
Le fichier .zip contenant les 5 fichiers du programme.


    - Suivant, ex0220   ;   Précédent, ex0150
ex0161_Tachimetre_Stroboscope_LiquidCrystal.ino   TOP
Tachimètre infrarouge et stroboscope adapté à la fréquence mesurée par le Tachimètre.
Connecté à un émetteur - récepteur infrarouge, permet de mesurer la vitesse de rotation d'un hand spinner ou autre toupie. Le branchement du détecteur infrarouge se fait sur l'entrée analogique A1.
En branchant une LED puissante sur la pin 3, on obtient également un stroboscope.
Le fichier "ex0161_Tachimetre_Stroboscope_LiquidCrystal.ino" contenant le programme.


    - Suivant, ex0380   ;   Précédent, ex0161
ex0220_ultrasonic_sensor_HC_SR04.ino   TOP
Émetteur - récepteur ultrason, pour mesurer des distances.
/*
* ex0220_ultrasonic_sensor_HC_SR04.ino
* Ultrasonic Sensor HC-SR04 and Arduino Tutorial* 
*
* Crated by Dejan Nedelkovski,
* www.HowToMechatronics.com
*
* c.f. http://howtomechatronics.com/tutorials/arduino/ultrasonic-sensor-hc-sr04/
*/

// defines pins numbers
const int trigPin = 12;
const int echoPin = 11;

// defines variables
long duration; // durée en micro-secondes
int distance;  // distance en centimètres

void setup() {
//============
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
} // setup

void loop() {
//===========  
// Envoie le signal de début de mesure sur le "trigPin"
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH); // Met le "trigPin" à l'état haut durant 10 micro-secondes.
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

// Lecture sur "l'echoPin" du temps d'aller-retour, en microseconds
duration = pulseIn(echoPin, HIGH);

// Calcule de la distance entre le sonnar et l'objet qui a réfléchi l'impulsion sonor
distance= duration*0.340/2;  // 0.340 [mm / micro-secondes] est la vitesse du son dans l'air

// Affiche le résultat
Serial.print("temps [micro-secondes] = ");
Serial.print(duration);
Serial.print("  Distance [mm] : ");
Serial.println(distance);

delay(1000); // Attente
} // loop


/*
Version pour l'afficheur LCD
    #include <LiquidCrystal.h> // includes the LiquidCrystal Library
    LiquidCrystal lcd(1, 2, 4, 5, 6, 7); // Creates an LCD object. Parameters: (rs, enable, d4, d5, d6, d7)
    const int trigPin = 12;
    const int echoPin = 11;
    long duration;
    int distanceCm, distanceInch;
    void setup() {
    lcd.begin(16,2); // Initializes the interface to the LCD screen, and specifies the dimensions (width and height) of the display
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    }
    void loop() {
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);
    distanceCm= duration*0.034/2;
    distanceInch = duration*0.0133/2;
    lcd.setCursor(0,0); // Sets the location at which subsequent text written to the LCD will be displayed
    lcd.print("Distance: "); // Prints string "Distance" on the LCD
    lcd.print(distanceCm); // Prints the distance value from the sensor
    lcd.print(" cm");
    delay(10);
    lcd.setCursor(0,1);
    lcd.print("Distance: ");
    lcd.print(distanceInch);
    lcd.print(" inch");
    delay(10);
    }
*/
ex0220 blink
ex0220_ultrasonic_sensor_HC_SR04.ino


    - Suivant, ex0381   ;   Précédent, ex0220
ex380_moteur_pas_a_pas.ino   TOP
Un premier exemple de pilote de moteur pas à pas, utilisant la librairie standard.
Il est conseillé de prendre l'exemple suivant, le ex381_moteur_pas_a_pas, qui est meilleur.
/*
 ex380_moteur_pas_a_pas.ino
 Stepper Motor Control - speed control

 This program drives a unipolar or bipolar stepper motor.
 The motor is attached to digital pins 8 - 11 of the Arduino.
 A potentiometer is connected to analog input 0.

 The motor will rotate in a clockwise direction. The higher the potentiometer value,
 the faster the motor speed. Because setSpeed() sets the delay between steps,
 you may notice the motor is less responsive to changes in the sensor value at
 low speeds.

 Created 30 Nov. 2009
 Modified 28 Oct 2010
 by Tom Igoe

 */

#include <Stepper.h>

const int stepsPerRevolution = 32;  // change this to fit the number of steps per revolution
// for your motor

#define pinIN1  8  // IN1 on the ULN2003 driver 1
#define pinIN2  9  // IN2 on the ULN2003 driver 1
#define pinIN3 10  // IN3 on the ULN2003 driver 1
#define pinIN4 11  // IN4 on the ULN2003 driver 1


// initialize the stepper library on pins 8 through 11:
//Stepper myStepper(stepsPerRevolution, 10, 11, 9, 8);  // 11, 10, 9, 8  pas bon
//Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);  // Tourne dans le sens des aiguilles d'une montre
//Stepper myStepper(stepsPerRevolution, 9, 10, 11, 8);  // Tourne dans l'autre sens (sens trigonométrique), mais pas bien
//Stepper myStepper(stepsPerRevolution, 10, 11, 8, 9);  // Tourne dans le sens des aiguilles d'une montre
//Stepper myStepper(stepsPerRevolution, 11, 8, 9, 10);  // Tourne dans l'autre sens (sens trigonométrique), mais pas bien
//Stepper myStepper(stepsPerRevolution, 11, 9, 10, 8); // Tourne dans le sens trigonométrique, bien

//Stepper myStepper(stepsPerRevolution, pinIN4, pinIN2, pinIN3, pinIN1); // Tourne dans le sens trigonométrique, bien
Stepper myStepper(stepsPerRevolution, pinIN1, pinIN3, pinIN2, pinIN4); // Tourne dans le sens des aiguilles d'une montre, bien

int stepCount = 0;  // number of steps the motor has taken

void setup() {
//============
// nothing to do inside the setup
} // setup

void loop() {
//===========
// read the sensor value:
int sensorReading = analogRead(A0);
// map it to a range from 0 to 100:
int motorSpeed = map(sensorReading, 0, 1023, 0, 100);

motorSpeed = 10;

// set the motor speed:
if (motorSpeed > 0) {
  myStepper.setSpeed(motorSpeed);
  // step 1/16 of a revolution:
  myStepper.step(stepsPerRevolution / 16);
  }
} // loop
ex0ex380_moteur_pas_a_pas.ino


    - Suivant, ex0385   ;   Précédent, ex0380
ex381_moteur_pas_a_pas.ino   TOP
Une meilleure version de pilote de moteur pas à pas, utilisant la librairie "AccelStepper", qu'il faut télécharger du site AccelStepper.
Plus précisément, il faut télécharger le fichier : AccelStepper-?.??. Les ? changeront avec le temps.
Voici une bonne référence (en anglais).
/*
 ex381_moteur_pas_a_pas.ino
Pilote de moteur pas à pas (Stepper motor)

Tiré du site Web : http://42bots.com/tutorials/28byj-48-stepper-motor-with-uln2003-driver-and-arduino-uno/
La librairie utilisée ici est meilleure que la librairie standard.
J'ai téléchargé la librairie "AccelStepper.h" du site : http://www.airspayce.com/mikem/arduino/AccelStepper/
Précisément de : http://www.airspayce.com/mikem/arduino/AccelStepper/AccelStepper-1.57.zip
Je l'ai installé en faisant : Croquis > Inclure un librairie > Ajouter la librairie .ZIP ...
J'ai sélectionné le fichier : "AccelStepper-1.57.zip" que j'ai téléchargé de l'adresse indiquée ci-dessus.
J'ai changé les n° de pin pour avoir la bonne correspondance.
Compilé + Téléverser, cela a immédiatement fonctionné.

Le moteur accélère, puis décélère et repard dans l'autre sens de manière identique.
C'est la librairie qui se charge de faire tout le travail.

***********************************************************/

#include <AccelStepper.h>
#define HALFSTEP 8  // c.f. AccelStepper.h
// 8 signifie qu'il y a 4 fils et que l'on utilise les demis pas.

#define FULL4WIRE 4  // c.f. AccelStepper.h
// 4 signifie qu'il y a 4 fils et que l'on n'utilise PAS les demis pas.


// Motor pin definitions
#define motorPin1   8     // IN1 on the ULN2003 driver 1
#define motorPin2   9     // IN2 on the ULN2003 driver 1
#define motorPin3  10     // IN3 on the ULN2003 driver 1
#define motorPin4  11     // IN4 on the ULN2003 driver 1

// Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
//AccelStepper stepper1(FULL4WIRE, motorPin1, motorPin3, motorPin2, motorPin4);

void setup() {
//============
stepper1.setMaxSpeed(1000.0);
stepper1.setAcceleration(100.0);
stepper1.setSpeed(200);
stepper1.moveTo(20000);
} // setup

void loop() {
//===========
//Change direction when the stepper reaches the target position
if (stepper1.distanceToGo() == 0) {
  stepper1.moveTo(-stepper1.currentPosition());
  }
stepper1.run();
} // loop
Pas d'image associée, le branchement étant très simple et décrit dans le site : une bonne référence (en anglais).
ex0ex381_moteur_pas_a_pas.ino


    - Fin, ex9999   ;   Précédent, ex0381
ex0385_moteur_pas_a_pas_LiquidCrystal.ino   TOP
Utilisation d'un circuit L293 pour piloter un moteur pas à pas bipolaire. (Moteur 28BYJ-48)
/*
ex0385_moteur_pas_a_pas_LiquidCrystal.ino
Avec l'afficheur à cristaux liquide et 5 boutons de commande.

Le but est d'utiliser un chip L293 pour piloter un moteur pas à pas bipolaire (28B>J-48).
Il manque beaucoup de fonctionnalités, telles que :
° Une rampe d'accélération
° un changement de sens de rotation
° aller à une position donnée et s'arrêter

Connections :
LCD   Arduino (pin) ou tension
 1 - Vss = 0 V
 2 - Vcc = 5 V
 3 - V0 = Tension variable réglée par une résistance variable, pour la lumineusité de l'affichage
 4 - RS = pin 7 (Register Select) 
 5 - R/W = 0 V donc uniquement en Write
 6 - E = pin 6  Enable, mise à haut pour accepter les données.
 7 .. 10 = connecté à la commande de rétro-éclairage "back light"
11 - D4 = pin 5, données sur 4 bits 
12 - D5 = pin 4, données sur 4 bits 
13 - D6 = pin 3, données sur 4 bits 
14 - D7 = pin 2, données sur 4 bits 
15 - LED + = 220 Ohm - +5V
16 - LED - = 0V

c.f. : http://www.arduino.cc/en/Tutorial/LiquidCrystal
c.f. : https://arduino-info.wikispaces.com/LCD-Pushbuttons

Pin qui restent libre et utilisables : 13, 12, 11, 3, 2, 0, 1
pin 0, pin 1, utilisé pour la transmission par USB,
======================================================== */

// include the library code:
#include <LiquidCrystal.h>

/*-----( Declare Constants )-----*/
#define pinFreqP  3 // pour générer une fréquence
#define pinFreqOnOff 11 // pour enclencher ou arrêter le générateur de fréquences

#define btnNONE   0
#define btnSELECT 1
#define btnLEFT   2
#define btnDOWN   3
#define btnUP     4
#define btnRIGHT  5

int nn = 0;   
int adc_key_in = 0;
byte bButton = btnNONE; // Button pressed according to the value of adc_key_in
byte bButtonLast = btnNONE; // Last button
byte bButtonCount = 0; // compte le nombre de fois que le même boutton est détecté à la suite.

// initialize the library with the numbers of the interface pins
//LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
  LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
String strS = ""; 
// c.f. : https://www.arduino.cc/en/Reference/StringObject

char acStr[20]; // Pour conversion de nombre en un string.

int  nButtonPush = btnNONE; // Bouton pressé
byte bMenu1 = 1;  // indique le menu sélectionné
byte bMenu1_Last = 0;  // indique le dernier menu sélectionné
                         // que lorsque adc_key_in a suffisemment changé.
String strCode = ""; // pour indiquer l'état du code

unsigned long lwTempsNow = 0; // temps en micro secondes
unsigned long lwTempsStart = 0; // temps au départ
unsigned long lwTempsAffiche = 0; // temps du dernier affichage
unsigned long lwTempsActionLast = 0; // temps en micro secondes de la dernière commande 

// Les 4 pins de contrôle du moteur pas à pas bipolaire
#define pinO1  2
#define pinO2  3
#define pinO3 11
#define pinO4 12

int nCpt = 0; // Compteur pour le moteur pas à pas, compte le 4 étapes d'un pas

byte bTourne = 0; // 0 == ne tourne pas, 1 == Full steps, 2 == HALF steps
unsigned long lwTempsNextStep = 0; // temps pour le prochain pas
unsigned long lwTempsDeltaStep = 20000; // temps entre deux pas

void setup() {
//============  
// set up the LCD's number of columns and rows: 
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.setCursor(0, 0);
lcd.print("Moteur pas a pas");
lcd.setCursor(0, 1);
lcd.print("Base sur un L293");
delay(2000);
lcd.setCursor(0, 0);
lcd.print("                "); // efface le texte
lcd.setCursor(0, 1);
lcd.print("                "); // efface le texte
//lcd.autoscroll();

lwTempsNow = micros();
lwTempsStart = lwTempsNow;

pinMode(pinO1, OUTPUT);
pinMode(pinO2, OUTPUT);
pinMode(pinO3, OUTPUT);
pinMode(pinO4, OUTPUT);

digitalWrite(pinO1, LOW);
digitalWrite(pinO2, LOW);
digitalWrite(pinO3, LOW);
digitalWrite(pinO4, LOW);

AfficheEtat();
delay(1000);
} // setup

int read_LCD_buttons() {
// ======================
// Lecture du bouton appuié
// Il faut détecter 10 fois de suite le même bouton pour qu'on estime détecté le bon bouton pressé.
// L'avantage de cette manière de faire est que la lecture des boutons ne prend que
// le temps d'une lecture analogique, soit environ 100 micro secondes.
adc_key_in = analogRead(0);  // read the value from the sensor 
// La lecture des boutons sont centrée autour des valeurs  0, 144, 329, 504, 741
// J'ai ajouté environ 50 à ces valeurs pour la détection des boutons

if (adc_key_in > 790) { 
  // Aucun bouton pressé.
  bButtonLast = btnNONE;
  bButtonCount = 0;
  return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  }
else if (adc_key_in > 555) bButton = btnSELECT;
else if (adc_key_in > 380) bButton = btnLEFT; 
else if (adc_key_in > 195) bButton = btnDOWN; 
else if (adc_key_in >  55) bButton = btnUP; 
else                       bButton = btnRIGHT;
  
if (bButton == bButtonLast) {
  // Le même bouton a été détecté
  if (bButtonCount > 10) return bButton;   // Le même bouton a été détecté .. fois de suite, donc c'est le bon
  bButtonCount++;  // compte combien de fois de suite le même bouton est détecté.
  }
else {  
  bButtonLast = bButton;
  bButtonCount = 1;
  }

return btnNONE; // On est pas encore sûr que le bon bouton est bButton.
} // read_LCD_buttons

void AfficheEtat() {
//==================
// Affichage de l'état du menu sélectionné
if (bMenu1 == bMenu1_Last) return; // rien à faire

if (bMenu1 == 1) {
  strS = "Mode de rotation :";
  lcd.setCursor(0, 0);
  lcd.print(strS);
  
  if      (bTourne == 0) strS = "  STOP          ";
  else if (bTourne == 1) strS = "  FULL steps    ";
  else if (bTourne == 2) strS = "  HALF steps    ";
  lcd.setCursor(0, 1);
  lcd.print(strS);
  }
else if (bMenu1 == 2) {
  strS = "Delta steps (s):";
  lcd.setCursor(0, 0);
  lcd.print(strS);
  
  sprintf(acStr, "delta-T=%8ld", lwTempsDeltaStep);   strS = acStr;
  lcd.setCursor(0, 1);
  lcd.print(strS);
  }
else if (bMenu1 <= 5) {
  // sprintf(acStr, "T = %7ld ", lwTempsNow - lwTempsStart);
  strS = "";
  dtostrf( (lwTempsNow - lwTempsStart)/1000000.0, 8, 1, acStr); // temps au dixième de seconde
  strS = strS + acStr;
  lcd.setCursor(0, 0);
  lcd.print(strS);
  
  //  dtostrf(lwFrequ1/1000.0, 8, 3, acStr);  
  sprintf(acStr, "Tourne=%2d", bTourne);   strS = acStr;
  if (bTourne == 0) strS = strS + "  STOP  ";
  else              strS = strS + "       ";
  lcd.setCursor(0, 1);
  lcd.print(strS);
  }

} // AfficheEtat

void MenuTreat() {
//================
// On a appuyé sur un bouton, traite l'action adéquat.

// Mémorise le temps de la dernière action utilisateur, pour pas en faire plusieurs lorsqu'on presse sur un bouton
lwTempsActionLast = micros();

if (bMenu1 == 1) {
  // Arrêt du moteur ou changement de entre HALF step et FULL step
  if ( (nButtonPush == btnUP) || (nButtonPush == btnDOWN) ) {
    // Départ du chronomètre = départ des mesures
    lwTempsStart =   lwTempsNow;
    lwTempsAffiche = lwTempsNow;
    lwTempsNextStep = lwTempsNow; 
    if (nButtonPush == btnUP)   { bTourne++; if (bTourne >   2) bTourne = 0; }
    if (nButtonPush == btnDOWN) { bTourne--; if (bTourne > 250) bTourne = 2; } // 0 - 1 = 255
    if (bTourne == 0) {
      // Arrêt la rotation
      nCpt = 0;
      digitalWrite(pinO1, LOW);
      digitalWrite(pinO2, LOW);
      digitalWrite(pinO3, LOW);
      digitalWrite(pinO4, LOW);
      }
    else if (bTourne == 1) {
      // Utilise les pas entiers
      nCpt = 0;
      digitalWrite(pinO1, HIGH);
      digitalWrite(pinO2, LOW);
      digitalWrite(pinO3, LOW);
      digitalWrite(pinO4, HIGH);
      }
    else if (bTourne == 2) {
      // Utilise les demi-pas
      nCpt = 0;
      digitalWrite(pinO1, HIGH);
      digitalWrite(pinO2, LOW);
      digitalWrite(pinO3, LOW);
      digitalWrite(pinO4, LOW);
      }
    }
  } // bMenu1 == 1

else if (bMenu1 == 2) {
  // Change la vitesse de rotation
  if (nButtonPush == btnUP) {
    // Accélère
    lwTempsDeltaStep -= 1000;
    if (lwTempsDeltaStep < 1000) lwTempsDeltaStep = 1000;
    }
  if (nButtonPush == btnDOWN) {
    // Ralenti
    lwTempsDeltaStep += 1000;
    }
  }

else if ((1 <= bMenu1) && (bMenu1 <= 5)) {
  //
  }
  
AfficheEtat();
} // MenuTreat

void Menu1_Change() {
//===================
// Changement du Menu1
lwTempsActionLast = micros();

bMenu1_Last = bMenu1; // Mémorise le dernier menu

if (nButtonPush == btnLEFT) {
   bMenu1 -= 1;
   if (bMenu1 == 0) bMenu1 = 2;  // boucle
  }

if (nButtonPush == btnRIGHT) {
   bMenu1 += 1;
   if (bMenu1 > 2) bMenu1 = 1;  // boucle
  }

AfficheEtat();
} // Menu1_Change

void loop() {
//===========
// Génère un signal carré d'une fréquence sélectionnable.
//  Serial.print(sensorValue, DEC);
//    Serial.println();

lwTempsNow = micros();

// Ne lit l'état des boutons que si un bouton a été traité il y a plus de 0,2 secondes = 200000 [us].
// Et si un nouveau pas moteur n'est pas imminant.
if ( (lwTempsNow - lwTempsActionLast >> 200000ul) && (lwTempsNow + 1000ul - lwTempsNextStep < lwTempsDeltaStep) ) {
   // Lecture de l'état des boutons, pour changer la fréquence ou la phase du signal
   nButtonPush = read_LCD_buttons();

   if ( (nButtonPush == btnLEFT) || (nButtonPush == btnRIGHT) ) Menu1_Change(); // Changement de menu
   if ( (nButtonPush == btnUP) || (nButtonPush == btnDOWN) || (nButtonPush == btnSELECT) ) MenuTreat();  // Un bouton pressé, traitement
   }

//nADvalue = analogRead(A1); // Lecture de la tension sur le port analogique A0
                           // La tension varie entre 0 et 5 Volts, correspondant
                           // aux nombre     entre 0 et 1023.

if (bTourne == 0) lwTempsNextStep = lwTempsNow;

if ( (bTourne > 0) && (lwTempsNow - lwTempsNextStep > lwTempsDeltaStep) ) {
  lwTempsNextStep += lwTempsDeltaStep;
  
  if (bTourne == 1) {
    // tourne par pas entier, les deux bobines sont toujours sous tension.
    if (nCpt == 0) {  // 1001
      digitalWrite(pinO3, LOW);
      digitalWrite(pinO1, HIGH);
      }
    else if (nCpt == 1) { // 0011
      digitalWrite(pinO4, LOW);
      digitalWrite(pinO2, HIGH);
      }
    else if (nCpt == 2) { // 0110
      digitalWrite(pinO1, LOW);
      digitalWrite(pinO3, HIGH);
      }
    else if (nCpt == 3) { // 1100
      digitalWrite(pinO2, LOW);
      digitalWrite(pinO4, HIGH);
      }
    nCpt++;  if (nCpt >= 4) nCpt = 0; // boucle de 0 à 3
    }
    
  if (bTourne == 2) {
    // tourne par demi-pas, une fois sur deux, une bobine est hors tension.
    if      (nCpt == 0) { // 0001
      digitalWrite(pinO4, LOW);
      }
    else if (nCpt == 1) { // 0011
      digitalWrite(pinO2, HIGH);
      }
    else if (nCpt == 2) { // 0010
      digitalWrite(pinO1, LOW);
      }
    else if (nCpt == 3) { // 0110
      digitalWrite(pinO3, HIGH);
      }
    else if (nCpt == 4) { // 0100
      digitalWrite(pinO2, LOW);
      }
    else if (nCpt == 5) { // 1100
      digitalWrite(pinO4, HIGH);
      }
    else if (nCpt == 6) { // 1000
      digitalWrite(pinO3, LOW);
      }
    else if (nCpt == 7) { // 1001
      digitalWrite(pinO1, HIGH);
      }
    nCpt++;  if (nCpt >= 8) nCpt = 0; // boucle de 0 à 7
    }
  }

if (lwTempsNow - lwTempsAffiche > 1000000ul) {
   // Affiche les mesures toutes les secondes
   AfficheEtat();
   lwTempsAffiche = lwTempsNow;
   }
} // loop
ex0020 blink
ex0385_moteur_pas_a_pas__LiquidCrystal.ino


                                Précédent, ex0385
TOP

Plan du Site : Home   arrow   Microcontroleur   arrow   code_exemples.html ( = http://www.juggling.ch/gisin/microcontroleur/code_exemples.html )


Page mise à jour le 25 juin 2020 par Bernard Gisin     ( Envoyer un e-mail )
Hébergement par : www.infomaniak.ch