Arduino 12arduino_goodfields_64.jpgGestion d'un menu général
 
Sommaire

'Mode' ou gestion d'un menu général Affichage  de Affichage de 'float' Voici  (enfin !) les premières fonctions ... fonctionnelles ! Voici (enfin !) les premières fonctions ... fonctionnelles !
Fonction  Horloge Fonction Horloge Fonctions  Frequencemetre Selfmetre Capacimetre Fonctions Frequencemetre Selfmetre Capacimetre Fonction  GBF Fonction GBF
Fonction  Café Fonction Café listing  12 listing 12
La page principale ... La page principale ...
   
Vers le début Vers Page 2 Vers sommaire 'Mode' ou gestion d'un menu général
Cette version représente un grand pas vers notre 'squelette universel'. Avec un LCD et un clavier, on va élaborer un 'MENU GENERAL' qui va permettre de choisir un 'MODE DE FONCTIONNEMENT' particulier.
On définit d'abord les libellés des fonctions par cette déclaration :

// definition des modes de fonctionnement correspondant aux différentes fonctions possibles
char* modex[]={"Horl","Freq", "Self", "Capa", "Volt", "GBF_","PWM_","Srvo","Acco","Baro","Ther","Reve","Cafe","Mors", " ", " "," --  ++  Ok  Ok "};
//              0      1      2        3       4       5      6      7      8      9       10    11     12     13
#define modemax 13
int mode=0,modeav=modemax,modeap=1;
Notez que la position 15 est un message-guide utilisé ensuite dans la présentation LCD.
On va afficher sur le LCD 3 fonctions contigües, la centrale étant entourée de <>, les touches 3 et 4 permettant de se déplacer dans les options (-- et ++), toutes les autres touches étant 'OK' et validant le choix.
On devrait donc avoir sur le LCD le menu général :cliquez pour agrandir : photo/12_menu.jpg
La gestion de ce menu général est réalisée par les étapes 10 et 11 du 'grafcet_a'. On démarre d'ailleurs avec grafcet_a=10 :
//--------------------------------
// mode par défaut, attente de choix d'un mode
  case 10:
//  affichage menu déroulant horizontal
    modeav = ((modeɬ)?mode-1:modemax);		// option précédente
    modeap = ((mode<modemax)?mode+1:0);		// option suivante
// ou plus simplement (mais 4 octets de plus !!!) :   if (mode < modemax ) { modeap = mode+1; } else { modeap = 0; }
// affichage de la 1ère ligne du LCD
    lcd.setCursor(0, 0);  lcd << modex[modeav] << " <" << modex[mode] << "> " << modex[modeap] ; 
// affichage de la 2ème ligne du LCD
    lcd.setCursor(0, 1);  lcd << modex[16]; 
// passage à l'étape suivante
    grafcet_a++;
// on arme la 'tempo_a', si on n'a pas choisi avant la fin des 15 secondes, on passe en 'Horl'oge
    tempo_a = 15000; // on arme la tempo, si on n'a pas choisi avant la fin, on passe en horloge
  break;

// attente appuis sur les touches
  case 11:  
// time-out : retour à l'horloge en fin de tempo
    if (tempo_a == 0) { grafcet_a = 0; }

// touche 3='--' sans répétition
    if (touche == '3') {
      mode = modeav;
      grafcet_a = 10;
      touche = ' ';
    }

// touche 4='++' avec répétition
    if (touche_repeat == '4') {
      mode = modeap; 
      grafcet_a = 10;
      touche_repeat = ' ';
    }

// toutes les autres touches = Ok
// 3 est automatiquement exclue du fait qu'elle est traitée avant (alors touche =' '), 
// mais pour la touche '4' il faut rajouter le test, car elle est gérée avec répétition !
    if (touche != ' ' and touche != '4') {    
// quand on valide, on va sauter à une étape de grafcet correpondant à la fonction désirée,
//  on a choisi comme première étape mode*100. Donc, par exemple, pour 'Capa' mode=3 on saute en 'grafcet_a=300' 
	  grafcet_a = 100*mode;
      tempo_a = 0;
// debug      lcd.setCursor(0, 1);  lcd << "mod=" << mode << " gr=" << grafcet_a; delay(1000);
      Serial << modex[mode] << endl;
// Notez que l'on nettoie le LCD, pour laisser l'affichage à la fonction choisie ...
	  lcd.clear(); touche_repeat = ' '; touche = ' ';	
    }
  break;

   
Vers le début Vers Page 2 Vers sommaire Affichage de 'float'
A noter également un sous-programme de formatage de valeurs 'float' :
	void affiche_valeur(float v,char unite,int nbchiffres)    //,char* sortie)
v = valeur en entrée
unite = unité en 1 caractère : V pour Volt, F pour Farad, c pour cycle/seconde (Hertz=Hz) ...
nbchiffres = nombre de chiffres significatifs
Le multiplicateur est automatiquement mis en place, les valeurs étant comprises entre 0. et 999. . Par exemples :
 affiche_valeur(123.456789012345,'V',4) = '123.4 V'
 affiche_valeur(1234.56789012345,'V',7) = '1.234567kV'
 affiche_valeur(0.0000000001,'F',4)     = '100.0pF'
 affiche_valeur(0.000022,'F',4)         = '22.00uF'
 affiche_valeur(123456789.012345,'c',6) = '123.456Mc'
 affiche_valeur(123456789012345.,'o',9) = '123.456789To'

   
Vers le début Vers Page 2 Vers sommaire Voici (enfin !) les premières fonctions ... fonctionnelles !
Après le menu général, on va décrire quelques fonctions simples pour démarrer. Ensuite on fera sans doute moins de commentaires, et il faudra bien revenir à une description HARDWARE complète et une NOTICE UTILISATEUR !.
   
Vers le début Vers Page 2 Vers sommaire Fonction Horloge
Donc : mode=0 --> grafcet_a = 0
Cette fonction, très simpliste, consiste à afficher l'heure et la date. Voir étape 0, triviale ! ...
L'affichage du nom du jour a été traité par :
char* jours[] = {"Sam","Dim","Lun","Mar","Mer","Jeu","Ven"} ;
Notez que cette horloge est très bête : elle est initialisée à n'importe quoi, enfin par :
// mise à l'heure
  setTime(12,15,00,26,02,13); // 12h15 le 25 déc 2013 
et n'est pas synchronisée (développements à suivre). Remarquez l'affichage de la date sur les secondes 8 et 9 de chaque dizaine.
Un appui sur une touche quelconque permet de repasser au menu général en étape 10.
   
Vers le début Vers Page 2 Vers sommaire Fonctions Frequencemetre Selfmetre Capacimetre
SIMULATION SEULEMENT !
Ces 3 fonctions ne sont là que pour montrer comment ajouter de nouvelles fonctionnalités. Elles simulent des affichages, mais devraient être ceux des fonctions développées ensuite (il va falloir retourneer à construire des interfaces ...).
Remarquez que si vous choisissez une fonction inexistante, dans le menu général, on retourne au menu général immédiatement (même pas de message !)
   
Vers le début Vers Page 2 Vers sommaire Fonction GBF
FONCTIONNEL !
Afin de tester ce mode, il faut avoir un haut parleur. Relier un petit HP ou un transducteur piezo à la sortie 3 de l'ARDUINO, avec un résistance en série de 220 à 2200 Ohms (selon volume désiré). La sortie est initialisée par :
pinMode(sortie_gbf, OUTPUT);
Ce Générateur Basse Fréquences va générer un signal sur la broche 3, dont la fréquence va être réglable au clavier.
Regardez les étapes 500 à 502 :
//--------------------------------
// GBF
// INITIALISATION à 880 Hertz (c'est un 'LA' double du diapason)
  case 500:
    freq=880.000; // Hertz
    grafcet_a++;               // et on passe à l'étape suivante
  break;

// génération du son
  case 501:
// limites
    if (freq < 1.) freq=1.;
    if (freq > 50000.) freq=50000.;
// affichage menu et fréquence actuelle
    lcd.setCursor(0, 1);  lcd << " --  -    +  ++ "; 
    lcd.setCursor(0, 0);  lcd << modex[mode] << " F="; 
    Serial << modex[mode] << " F="; 
    affiche_valeur(freq,'c',5);
// GBF effectif
    tone(sortie_gbf, (unsigned int) freq );
// pour scrutation clavier
    tempo_a = 100;
    grafcet_a++;               // et on passe à l'étape suivante
  break;
  
// gestion clavier
  case 502:
// retour au menu général
    if (touche == '0') {
      noTone(sortie_gbf); // stop GBF
      touche = ' ';
      grafcet_a=9999;    // pour raz grafcet
    }
// valeurs calibrées
    if (touche == '1') freq = 440.;
    if (touche == '2') freq = 880.;
// descente d'une demi-gamme
    if (touche == '3') freq /= racine2;
// descente d'un demi-ton
    if (touche_repeat == '4') { freq /= demiton; touche_repeat = ' '; }
// montée d'un demi-ton
     if (touche_repeat == '5') { freq *= demiton; touche_repeat = ' '; }
// montée d'une demi-gamme
    if (touche == '6') freq *= racine2;
// valeurs calibrées
    if (touche == '7') freq = 1760.;
    if (touche == '8') freq = 3520.;
    if (touche == '9') freq = 7040.;
    if (touche != ' ') { grafcet_a--;  touche = ' '; }		// raz touche appuyée
    if (tempo_a == 0) grafcet_a--;
  break;
   
Vers le début Vers Page 2 Vers sommaire Fonction Café
POUR BIDOUILLE (fonction ne risquant rien, ou pouvant servir de modèle pour la suite)
//--------------------------------
// Café (en fait, bidouille)
  case 1200:
    i=0;
    grafcet_b=1;
    grafcet_a++;
  break;

  case 1201:
// chenillard
    lcd.setCursor(i, 0);  lcd << " "; 
    i++; if (iᡇ) i=0;
    lcd.setCursor(i, 0);  lcd << "*"; 
// affichage des états des 2 grafcets
    lcd.setCursor(0, 1); lcd << grafcet_a << "ab" << grafcet_b << "    ";
// et de la vitesse de l4ARDUINO 
    lcd.setCursor(11, 1); lcd << tours_ps << "   ";
    tempo_a = 100;             // on arme la tempo
    grafcet_a++;
  break;

  case 1202:
    if (touche == '0') {
      touche = ' ';
      grafcet_b=0;
      grafcet_a=9999;    // pour raz grafcet
    }
    if (tempo_a == 0) grafcet_a=1201;
  break;   

   
Vers le début Vers Page 2 Vers sommaire listing 12
/*
  GoodFields 12_mode
  GBF
  Fréquencemètre, capacimètre, selfmètre : simulés
  ---
  Modes et menu général
  Clavier analogique à diodes et debug
  LCD
  Gestion du temps
  Compactage des sorties série (intégration d'une bibliothèque : Streaming)
  GRAFCET
  TEMPORISATION basique
  FRONT MONTANT/DESCENDANT
*/
//**********************************************************
// BIBLIOTHEQUES
// incluses dans le package Arduino de base
#include <LiquidCrystal.h>  // LCD

// ajoutées
#include <Streaming.h>
#include <Time.h>

// DEBUG : 0=pas de debug, valeur selon besoins
#define debug 0

//**********************************************************
// DECLARATIONS
// LCD initialize the library with the numbers of the interface pins
/* Câblage du LCD
 * LCD pin 1 to GND
 * LCD pin 2 to VCC 5V
 * LCD pin 3 : contraste sur le point milieu d'un potentiomètre de 10K entre le GND et le VCC (réglé très près de la masse)
 * LCD pin 4 RS to digital pin 4
 * LCD pin 5 RW to GND
 * LCD pin 6 Enable pin to digital pin 2
 * LCD pin 11 D4 pin to digital pin 6
 * LCD pin 12 D5 pin to digital pin 7
 * LCD pin 13 D6 pin to digital pin 8
 * LCD pin 14 D7 pin to digital pin 9
*/
//  LiquidCrystal lcd(RS, Enable,  D4, D5, D6, D7)
  LiquidCrystal lcd(4, 2, 6, 7, 8, 9);

// entrées-sorties
#define led_a 13
#define sortie_gbf 3

// temporisations
int tempo_a,tempo_b;
// vitesse de clignotement : maintenant en millisecondes
int tempo_a_reset=1000;
int tempo_b_reset=700;
// gestion du temps
int previousSecond;      // secondes de l'horloge
int top_dixieme=false;   // top pour traitements au 1/10 seconde dans le P/P
int top_seconde=false;   // top pour traitements à la seconde dans le P/P
int top_minute=false;   // top pour traitements à la minute dans le P/P
unsigned long previousMillis, previousDecis;
char* jours[] = {"Sam","Dim","Lun","Mar","Mer","Jeu","Ven"} ;
// clavier à 16 touches et diodes sur entrée analogique
int clavier=A0;
int itouche,itouche1=-1,itouche2=-1,vtouche,ntouche,tempo_repeat;
// touche renvoyée
char touche=' ',touche_repeat=' ';

// CLAVIER 10 TOUCHES A DIODES 0,2V
int nbtouche = 10;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  90, 136, 181, 226, 270, 313, 354, 396, 437, 1023};  // nbtouche+1

/*
// CLAVIER 24 TOUCHES A DIODES 0,2V
int nbtouche = 24;
// caractère touche renvoyée
//                 <----------------clavier-10 touches------------>                16 touches--->                          24 touches--->
char ltouche[] =  {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', ' '};        // nbtouche
// valeurs analogiques. A ajuster selon valeurs relevées après montage # 41 pour 0,2 Volts/diode
int xtouche[] =   {  0,  45,  91, 136, 181, 226, 270, 313, 354, 396, 437, 478, 519, 560, 601, 642, 683, 724, 765, 806, 847, 888, 929, 970, 1010, 1023};  // nbtouche+1
*/

// speedomètre = calcul de vitesse ...
unsigned int tours_ps,tours,tours_led;

// GRAFCETS
int grafcet_a=0,grafcet_b=0;

// definition des modes de fonctionnement correspondant aux différentes fonctions possibles
char* modex[]={"Horl","Freq", "Self", "Capa", "Volt", "GBF_","PWM_","Srvo","Acco","Baro","Ther","Reve","Cafe","Mors", " ", " "," --  ++  Ok  Ok "};
//              0      1      2        3       4       5      6      7      8      9       10    11     12     13
#define modemax 13
int mode=0,modeav=modemax,modeap=1;

// variables très locales !
int i;
//int j;

// Constantes sympas
float deuxpi=6.283185307; // 179586476925286766559;  // à peu près 2 Pi
float racine2 = 1.414213562; //3730950488016887242097; // racine carree de 2
float demiton = 1.059463094; //3592952645618252949463; // 2 puissance 1/12
// FREQUENCES, CAPAS, SELFS
float self,capa,freq;

//**********************************************************
// INITIALISATIONS
void setup() {
// initialize the pins
  pinMode(led_a, OUTPUT);
  pinMode(sortie_gbf, OUTPUT);
  pinMode(clavier, INPUT);  
  digitalWrite(clavier, HIGH);       // turn on pullup resistors

// définition taille du LCD :
  lcd.begin(16, 2);

// mise à l'heure
  setTime(12,15,00,26,02,13); // 12h15 le 25 déc 2013

// ligne série (pour traces)
  Serial.begin(9600);  // ou 9600 selon votre port COM
#if debug > 0  
  Serial << "Serial ok" << endl;
#endif

// AFFICHAGE sur LCD
  lcd.setCursor(0, 0);  lcd << "Serial OK";     // 1ere ligne
  lcd.setCursor(0, 1);  lcd << "GoodFields";    // 2eme ligne lcd.print ("toto="); lcd.pprint (toto,2);
  delay(500);        // pour profiter du LCD au démarrage
  lcd.clear();    // Effacement général LCD
} // Fin du SETUP
//**********************************************************
// PROGRAMME PRINCIPAL
void loop() {

// compte-tours par seconde et led_a "heart-beat" commutée
  if (tours < 65535) tours++;
  tours_led++;
  if (tours_led > 10000) { tours_led = 0 ;  digitalWrite(led_a, !digitalRead(led_a)); } 
  
// gestion du temps (dont temporisations)
  ger_top_centieme ();
  
// opérations à chaque dixième de seconde
  if (top_dixieme) {
    top_dixieme = false;
  }
 
// opérations à chaque seconde
  if (top_seconde) {
    top_seconde = false;
    tours_ps=tours; tours=0;
  }

//********************************************************************************
switch (grafcet_a) {

  /* MODES : on arme le grafcet à mode*100
mode - fonction
 0 - horloge basique
 1 - fréquencemètre (8 Mhz à priori, c'est facile le selfmètre capacimètre en est un)
 2 - un selfmètre capacimètre (c'est l'idée de départ) ???
 3 - capacimètre
 4 - un quadri-voltmètre 20 Volts, ampèremètre éventuel (détecteur à faire, mais je connais l'astuce) ???
 5 - un GBF (ce que peut faire l'Arduino, sans doute jusque vers 30 kHz) ???
 6 - mais aussi générateur de signal pour tester des servo moteurs de télécommande ???
 7 - et encore générateur de commande PWM ???
 8 - un accordeur de guitare ou autre bombarde (quand j'aurais connecté un HP) ???
 9 - un baro-thermomètre à base de BMP085 (bus I2C sur A4+A5) ???
 10 - un appareil de mesure de capacité isolante d'un mur (avec 3 capteurs DS1820 bus 1 fil sur A5) ???
 11 - horloge réveil temporisation ( synchro avec horloge temps réel DS1307 ou horloge radio DFM77 ??? )
 12 - pas le café, quoi que ... 
 - une alimentation 5V et 12 V pour bidouiller 
 
*/
//--------------------------------
// mode horloge basique
  case 0:
// appel menu général
    if (touche != ' ') {
      grafcet_a = 10;
      touche = ' '; 
    }
// horloge de base
    if (tempo_a == 0) {
      tempo_a = 1000;
      horodatage_serial(); Serial << " top" << tours_ps << "t/s    " << grafcet_a << " " << grafcet_b << endl;
      lcd.setCursor(0, 0);
      if (second()%10 > 7) {
         lcd << " " << jours[weekday()] << " " << ((day()᝺)?"0":"") << day() << "/" << ((month()᝺)?"0":"") << month() << "/" << year() << " " ;
      } else {
         lcd << "  " << ((hour()᝺)?"0":"") << hour() << ":" << ((minute()᝺)?"0":"") << minute() << ":" << ((second()᝺)?"0":"") << second() << "   GER";
      }
    }
  break;

//--------------------------------
// mode par défaut, attente de choix d'un mode
  case 10:
//  affichage menu déroulant horizontal
    modeav = ((modeɬ)?mode-1:modemax);
    modeap = ((mode<modemax)?mode+1:0);
// ou plus simplement (mais 4 octets de plus !!!) :   if (mode < modemax ) { modeap = mode+1; } else { modeap = 0; }
    lcd.setCursor(0, 0);  lcd << modex[modeav] << " <" << modex[mode] << "> " << modex[modeap] ; 
    lcd.setCursor(0, 1);  lcd << modex[16]; 
    grafcet_a++;
    tempo_a = 15000; // on arme la tempo, si on n'a pas choisi avant la fin, on passe en horloge
  break;

  case 11:  
// retour à l'horloge
    if (tempo_a == 0) { grafcet_a = 0; }
// - sans répétition
    if (touche == '3') {
      mode = modeav;
      grafcet_a = 10;
      touche = ' ';
    }
// + avec répétition
    if (touche_repeat == '4') {
      mode = modeap; 
      grafcet_a = 10;
      touche_repeat = ' ';
    }
// Ok
    if (touche != ' ' and touche != '4') {    // 3 est exclue du fait que traitée avant !
      grafcet_a = 100*mode;
      tempo_a = 0;
// debug      lcd.setCursor(0, 1);  lcd << "mod=" << mode << " gr=" << grafcet_a; delay(1000);
      Serial << modex[mode] << endl;
      lcd.clear(); touche_repeat = ' '; touche = ' ';
    }
  break;

//--------------------------------
// Frequencemetre
  case 100:
    grafcet_a++;               // et on passe à l'étape suivante
    freq = 144612500.;
  break;

  case 101:
    freq += 0.001*millis();
    lcd.setCursor(0, 0);  lcd << modex[mode] << "=";  Serial << modex[mode] << "=";
    affiche_valeur(freq,'c',7); 
    Serial << endl;
    tempo_a = 1000;             // on arme la tempo
    grafcet_a++;               // et on passe à l'étape suivante
  break;

  case 102:
    if (touche == '0') {
      touche = ' ';
      grafcet_a=9999;    // pour raz grafcet
    }
    if (tempo_a == 0) grafcet_a=101;
  break;
    
//--------------------------------
// Selfmetre - Capacimètre
  case 200:
  case 300:
    self=0.000068;          // 68 uH
    capa=0.000000000680;    // 680 pF
    grafcet_a++;               // et on passe à l'étape suivante
//    self = self0; capa = capa0; // pour simulation
  break;

  case 201:
  case 301:
    lcd.setCursor(0, 0);  lcd << modex[mode] << "=" ; 
    Serial << modex[mode] << " " ; 
// Capacimètre
    if (grafcet_a > 250) { 
//      x = 1. / (self * pow(deuxpi * freq, 2.));    // C = 1 / (L * (2 * Pi * F)²) 
//    capa = x-capa0;
      capa *= 1.41421356;
      affiche_valeur(capa,'F',4); 
      Serial << " " ; 
      lcd.setCursor(0, 1); 
      affiche_valeur(self,'H',4);
// Selfmetre
    } else { 
//      x = 1. / (capa * pow(deuxpi * freq, 2.));    // L = 1 / (C * (2 * Pi * F)²) 
//      self = x-self0;
        self *= 1.41421356;
      affiche_valeur(self,'H',4); 
      Serial << " " ; 
      lcd.setCursor(0, 1); 
      affiche_valeur(capa,'F',4); 
    }
    Serial << " " ; 
    lcd << " ";
 // calcule la fréquence de résonnance   
    freq = 1. / (deuxpi * pow(self*capa,0.5));    // F = 1 / (2 * Pi * racine_carree ( L * C ))
    affiche_valeur(freq,'c',5);
    Serial << endl;

    tempo_a = 2500;             // on arme la tempo
    grafcet_a++;               // et on passe à l'étape suivante
    if (capa > 0.000000680 or self > 0.068 ) grafcet_a-=2;
  break;

  case 202:
  case 302:
    if (touche == '0') {
      touche = ' ';
      grafcet_a=9999;    // pour raz grafcet
    }
    if (touche == '1') {
      self=0.01-self;
      capa=0.0000001-capa;
      grafcet_a--;
      touche = ' ';
    }
    if (tempo_a == 0) grafcet_a--;
  break;

//--------------------------------
// GBF
// INITIALISATION à 880 Hertz (c'est un 'LA' double du diapason)
  case 500:
    freq=880.000; // Hertz
    grafcet_a++;               // et on passe à l'étape suivante
  break;

// génération du son
  case 501:
// limites
    if (freq < 1.) freq=1.;
    if (freq > 50000.) freq=50000.;
// affichage menu et fréquence actuelle
    lcd.setCursor(0, 1);  lcd << " --  -    +  ++ "; 
    lcd.setCursor(0, 0);  lcd << modex[mode] << " F="; 
    Serial << modex[mode] << " F="; 
    affiche_valeur(freq,'c',5);
// GBF effectif
    tone(sortie_gbf, (unsigned int) freq );
// pour scrutation clavier
    tempo_a = 100;
    grafcet_a++;               // et on passe à l'étape suivante
  break;
  
// gestion clavier
  case 502:
// retour au menu général
    if (touche == '0') {
      noTone(sortie_gbf); // stop GBF
      touche = ' ';
      grafcet_a=9999;    // pour raz grafcet
    }
// valeurs calibrées
    if (touche == '1') freq = 440.;
    if (touche == '2') freq = 880.;
// descente d'une demi-gamme
    if (touche == '3') freq /= racine2;
// descente d'un demi-ton
    if (touche_repeat == '4') { freq /= demiton; touche_repeat = ' '; }
// montée d'un demi-ton
     if (touche_repeat == '5') { freq *= demiton; touche_repeat = ' '; }
// montée d'une demi-gamme
    if (touche == '6') freq *= racine2;
// valeurs calibrées
    if (touche == '7') freq = 1760.;
    if (touche == '8') freq = 3520.;
    if (touche == '9') freq = 7040.;
    if (touche != ' ') { grafcet_a--;  touche = ' '; }		// raz touche appuyée
    if (tempo_a == 0) grafcet_a--;
  break;

//--------------------------------
// Café (en fait, bidouille)

  case 1200:
    i=0;
    grafcet_b=1;
    grafcet_a++;
  break;

  case 1201:
// chenillard
    lcd.setCursor(i, 0);  lcd << " "; 
    i++; if (iᡇ) i=0;
    lcd.setCursor(i, 0);  lcd << "*"; 
// 2 grafcets
    lcd.setCursor(0, 1); lcd << grafcet_a << "ab" << grafcet_b << "    ";
    lcd.setCursor(11, 1); lcd << tours_ps << "   ";
    tempo_a = 500;             // on arme la tempo
    grafcet_a++;
  break;

  case 1202:
    if (touche == '0') {
      touche = ' ';
      grafcet_b=0;
      grafcet_a=9999;    // pour raz grafcet
    }
    if (tempo_a == 0) grafcet_a=1201;
  break;   

//--------------------------------
// Morse

  case 1300:
    i=0;
    grafcet_a++;
  break;

  case 1301:
    tempo_a = 100;
  break;

  case 1302:
    if (tempo_a == 0) grafcet_a=1301;
  break;   
//--------------------------------
// si grafcet_a n'a pas une valeur correcte, on passe ici
  default: 
// arret du grafcet
  case 9999:
      lcd.clear();
      grafcet_a = 10; // on retourne au menu général
  break;
}

//--------------------------------
//--------------------------------
//--------------------------------
//--------------------------------
// GRAFCET B
switch (grafcet_b) {

  case 1:
  if ( tempo_b == 0 ) {        // si la tempo est terminée,
    horodatage_serial(); Serial << " grafcet_b=" << grafcet_b <<  " grafcet_a=" << grafcet_a <<endl;
    tempo_b = tempo_b_reset;             // on arme la tempo
    grafcet_b++;               // et on passe à l'étape suivante
  }
  break;      // cette instruction vous fait sauter à la fin du "switch"

  case 2:
  if ( tempo_b == 0 ) {
    horodatage_serial(); Serial << " grafcet_b=" << grafcet_b <<  " grafcet_a=" << grafcet_a << endl;
    tempo_b = tempo_b_reset;             // on arme la tempo
    grafcet_b=1;               // on reboucle
  }    
  break;

// si grafcet_a n'a pas une valeur correcte, on passe ici
  default: 
      grafcet_b = 0; // on arrête
  break;
}      // fin du "switch"
// FIN GRAFCET B
//--------------------------------
}
// ************************************************************************************************
// ************************************************************************************************
// SOUS-PROGRAMMES
// ************************************************************************************************
/* scrutation et filtrage de clavier analogique

  utilisation "monocoup" :
  if (touche == '1') { ...; touche=' ';}

  utilisation avec "répétition" :
  if (touche_repeat == '1') { ...; touche_repeat=' ';}
*/
void ger_scrute_clavier(){
// clavier - filtrage
  itouche2 = itouche1;
  itouche1 = itouche;
  itouche = analogRead(clavier);
// pour calibrage
//  if (itouche < 1020 ) Serial.println(analogRead(clavier));

// si la touche est stable (3 tours)
  if ((itouche)==itouche2) { // && itouche1==itouche2) {

// recherche quelle touche
    ntouche=-1;
    do {
      ntouche++;
    } while (itouche > ((xtouche[ntouche]+xtouche[ntouche+1])/2) && ntouche < nbtouche);
// debug lcd.setCursor(0, 1);  lcd << "t=" << ltouche[i] << "," << itouche << "    ";    // 2eme ligne lcd
// si la touche a varié
    if (ltouche[ntouche] != vtouche ) {
      vtouche = ltouche[ntouche];
// touche valide
      if (ntouche < nbtouche) { 
        touche = vtouche;
        touche_repeat = vtouche;
        tempo_repeat=800;  // duree avant repetition
// arret répétition
      } else {
        touche_repeat = ' ';
      }
// si la touche est la même : repeat ?
    } else {
      if (ntouche < nbtouche && tempo_repeat == 0 ) {
        touche_repeat = vtouche;
        tempo_repeat=400;  // vitesse repetition
      }
    }
  }
  return;
}
// ************************************************************************************************
// Programme au -ieme de seconde
// gestion des temporisations
// NB : le débordement du compteur en (unsigned long) a lieu tous les 50 jours environ ...
void ger_top_centieme (){
  unsigned long delta;
  unsigned long currentMillis = millis();

// Centième de secondes
  delta = currentMillis - previousMillis;
  if (delta >= 10) {
// save the last time you come here
    previousMillis = currentMillis;   

// scrutation du clavier toutes les 10ms
    ger_scrute_clavier();

// allumage temporisé led clavier
//    if (lamp_tempo >= delta) { lamp_tempo -= delta; digitalWrite(lamp, HIGH); } else { lamp_tempo = 0; digitalWrite(lamp, LOW); }

// gestion des TEMPORISATIONS (en ms mais précise à 10ms près)
    if (tempo_a >= delta ) { tempo_a -= delta; } else { tempo_a = 0; }
    if (tempo_b >= delta ) { tempo_b -= delta; } else { tempo_b = 0; }
    if (tempo_repeat >= delta ) { tempo_repeat -= delta; } else { tempo_repeat = 0; }
//    if (fonction_tempo >= delta) { fonction_tempo -= delta; } else { fonction_tempo = 0; }
  }

// Dixième de seconde
   delta = currentMillis - previousDecis;
   if (delta >= 100) {
    previousDecis = currentMillis;   
    top_dixieme = true;
    
// tops seconde et minute pour traitements dans le main
    if (second() != previousSecond) {
      previousSecond = second();
      top_seconde = true;
      if (previousSecond == 0) top_minute=true;
    }
  }
  return;
}
// ************************************************************************************************
// affichage horloge complete sur la sortie serie, sans fin de ligne
void horodatage_serial() {
// digital clock display of the time
  Serial << ((day()᝺)?"0":"") << day() << "/" << ((month()᝺)?"0":"") << month() << "/" << year() << " " << ((hour()᝺)?"0":"") << hour() << ":" << ((minute()᝺)?"0":"") << minute() << ":" << ((second()᝺)?"0":"") << second();
}
// ************************************************************************************************
// ************************************************************************************************
/*
Sur le LCD et la voie SERIE
Affiche la valeur "v" avec "nbchiffres" digits significatifs suivi de l'"unite"
Donc "nbchiffres" digits + point + multiplicateur + unite = "nbchiffres+3" caractères
OK
*/
void affiche_valeur(float v,char unite,int nbchiffres)    //,char* sortie)
{
 float vloc;
 int mult=5,nbdec;
//   mult =            0    1    2    3    4    5   6     7     8    9
//   multiplicateur =  Peta Tera Giga Mega Kilo *   milli micro nano pico
 char multiple[10] = {'P', 'T', 'G', 'M', 'k', ' ','m',  'u',  'n', 'p'};
  vloc=v;
// si valeur inférieure à 1, on multiplie
  while (vloc < 1. && mult < 10) {
     vloc = vloc*1000;
     mult++;
   }
// si valeur grande, on divise
   while (vloc >= 1000. && mult > 0) {
     vloc = vloc/1000;
     mult--;
   }
// nombre de décimales selon valeur   // ex nbchiifres=4    7
   nbdec = nbchiffres-3;              //           999.9  999.9999
   if (vloc < 100 ) nbdec++;          //           99.99  99.99999
   if (vloc < 10 ) nbdec++;          //           9.999  9.999999
//   sortie[i]=multiple[mult];
   Serial << _FLOAT(vloc, nbdec) << multiple[mult] << unite ;
   lcd << _FLOAT(vloc, nbdec) << multiple[mult] << unite ;
   return;
}
// ************************************************************************************************
// ************************************************************************************************

la suite ... la suite ... La page principale ... La page principale ... PAS DE PAGE 11 !! PAS DE PAGE 11 !!

Photos de la page :

Dernière mise à jour : 11:40:00 18/09/2020