/*
***********************************************
* Gestion de 16 aiguillages arduino Mega 2560 *
* version 20240819 *
* utlisation du pullup interne pour les BP *
***********************************************
Version commune corrigée pour adaptation aux nouveaux PCB avec utilisation du pullup à la place du pulldown
Arduino Clavier digital_20230715_pullup.dip
Arduino Gestion 16 aiguillages par Mega_2560_pullup.dip
Ecran LCD par I2C
4 modules supplémentaires 74HC595 pour alimenter 32 leds bicolores.
1 entrée Infra Rouge pour commande à distance des réglages.
1 entrée DCC pour de futurs développements
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! Ce code est distribué gratuitement sous licence !
! Creativ Commons CC-BY-NC-ND 3.0 !
! !
! Cette licence permet à d'autres utilisateurs d'utiliser ce code !
! à des fins non commerciales, dans la mesure où le nom de l'auteur est !
! mentionné. Toute modification du code devra être soumise à !
! l'autorisation expresse de l'auteur. !
! Tests sur https://wokwi.com/projects/402136129056063489 !
! auteur Philippe GUENET - [email protected] - https://wgnt-train.fr !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/!\ A VERIFIER /!\
##### les interruptions Mega2560 R3 ##### (corrigées)
Pin #2 = interruption #0
Pin #3 = interruption #1
Pin #18 = interruption #5
Pin #19 = interruption #4
Pin #20 = interruption #3
Pin #21 = interruption #2
/!\ A VERIFIER /!\
Réveil carte Mega par interruption sur D2 (clavier)
Detection IR et réveil carte Mega par interruption sur D18
Selection Mode et réveil carte Mega par interruption sur D19
LOW to trigger the interrupt whenever the pin is low,
CHANGE to trigger the interrupt whenever the pin changes value
RISING to trigger when the pin goes from low to high,
FALLING for when the pin goes from high to low.
HIGH to trigger the interrupt whenever the pin is high.
#############################
le 11/11/2024 => reprise sans IR pour amélioration détection DCC
le 13/11/2024 => tout semble OK. On va réintroduire l'Infra Rouge pour le mode REGLAGE.
*/
/*
exemple de gestion par millis()
int Tempo
unsigned long departTempo = millis();
if(((millis() - departTempo) > Tempo) && (servoAiguillage[ServoEnCours].attached())) servoAiguillage[ServoEnCours].detach();
*/
String Version = "MAJ / DCC-20241113";
#define numCarte 1
/* A décommenter si utilisation de la Sprog3 */
//#define Sprog3ON
/* ========================================= */
/* A décommenter si utilisation d'une z21 dont la norme RCN 213 n'est pas activée */
//#define Z21_RCN213_OFF
/* ============================================================================== */
#include <Wire.h>
#include <EEPROM.h> // bibliothèque pour gérer la mise en mémoire
#include <Bounce2.h>
//#include <TimerFreeTone.h> // pin, fréquence, durée.
/* LES CONNECTEURS */
const int pinLedPM = A5; // led activation point milieu
const int pinLedTemoin = A6; // led report clavier fonctionnement et mise en veille
const int pinBuzzer = A7; // buzzer sur A7
const int pinBPPlus = 4;
const int pinBPValidationReglage = 5; // BP de validation des réglages sur D5
const int pinBPMoins = 6;
const int pinSelecteurMode = 7; // switch de choix mode Commande / réveil sur D19 (interruption matérielle INT2)
// pins D10, D11, D12 réservés pour la gestion des 4 74HC595
const int pinBPPointMilieu = 14; // positionne tous les aiguillages à leur point milieu.
const int pinLedvalRalenti = 15; // led témoin de la valeur du ralenti
const int pinBPvalRalenti = 16; // BP de réglage de la vitesse de déplacement des aiguillages
const int pinSelecteurDirection = 17; // switch de sélection de la butée (Direct/devie) en cours de réglage sur D17
const int pinDetectionIR = 18; // détection IR sur D18 (interruption matérielle INT3)
const int pinInterruptionClavier = 19; // détection des touches du clavier / réveil sur D2 (interruption matérielle INT4)
//pin 20 et 21 réservés SDA/SCL
//pins 22 à 37 réservés pour les 16 BP du clavier // les BP sont connectés du pin 22 au pin 37
//pins 38 à 53 réservés pour les 16 servos // les servos sont connectés du pin 38 au pin 53
/* =============== */
/* LES VARIABLES POUR LES SERVOS */
const int Nb_Aiguillages = 16;
const int pinDepartServo = 38;
const int angleMini = 1150; // 544 pris pour 600 // Ces 2 valeurs peuvent être ajustées en fonction des moteurs d'aiguillages utilisés
const int angleMaxi = 1850; // 2400 // celles paramétrées ici sont en rapport avec nos mouteurs "maison"
byte valRalenti = 3; // peux prendre les valeurs de 1 à 5
int pasReglage = 10; // incrémentation des angles pour les réglages
struct aiguillage {
int adresseDCC;
int adresseVisuel;
int angleDirect;
int angleDevie;
int angleIntermediaire;
int angleCible;
int DernierePosition;
bool selectionServo;
int sens;
uint32_t departRalenti;
uint32_t chronoRalenti;
uint32_t departDetache;
bool flagAppel;
};
aiguillage Aiguillage[Nb_Aiguillages];
/* pour gérer les servos */
#include <Servo.h>
Servo servoAiguillage[Nb_Aiguillages];
/* ===================== */
/* pour gérer un écran LCD 2004
* l'adresse de l'écran peut être déterminée à l'aide
* du script "Scanner I2C"
*/
#include <LiquidCrystal_I2C.h> // bibliothèque pour gérer écran LCD 2004
LiquidCrystal_I2C lcd(0x27, 20, 4);
//LiquidCrystal_I2C lcd(0x3F, 20, 4);
/* ============================ */
/* POUR LA MISE EN VEILLE */
//réveil par interruption sur D2, D18 et D19
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/interrupt.h>
enum etatCarte { ACTIF, VEILLE, REVEIL };
volatile etatCarte etatActuel = ACTIF;
uint32_t departChronoExecution = 0ul;
uint32_t dureeInactivite = 300000ul; // mise en veille au bout de 5 minutes d'inactivité
/* ====================== */
/* POUR LE CLAVIER NUMERIQUE */
Bounce clavierBP[Nb_Aiguillages] = Bounce();
Bounce SelecteurMode = Bounce();
Bounce SelecteurDirection = Bounce();
Bounce BPvalRalenti = Bounce();
Bounce2::Button BP_Plus = Bounce2::Button();
Bounce2::Button BP_Moins = Bounce2::Button();
Bounce BPValidationReglage = Bounce();
Bounce BPPointMilieu = Bounce();
const int dureeAntiRebond = 20;
const int pinDepartBP = 22;
bool etatLedRalenti = LOW;
bool etatLedPM = LOW;
uint32_t precedentMillis = 0;
/* ======================== */
/* LES VARIABLES POUR LES REGLAGES */
bool etatSelecteurMode;
bool etatSelecteurDirection;
bool etatSelecteurPointMilieu;
bool flagPointMilieu = false;
/* =============================== */
/* POUR LE BP DE VALIDATION */
uint32_t debutPressionBP = 0;
uint32_t finPressionBP = 0;
uint32_t dureeAppui = 0;
const uint32_t limitePressionCourteBP = 2000; // pression courte si - de 2 secondes
const uint32_t limitePressionLongueBP = 6000; // pression longue si + de 6 secondes
enum EtatBouton {INIT, PRESSE, RELACHE, SORTIE};
EtatBouton etatValidation = INIT;
/* ====================================== */
/* POUR LA DETECTION IR */
//#include <IRremote.hpp>
//bool flagDizaine = false;
//uint32_t precedentChronoDetection = 0;
//const uint32_t detectionDelai = 200;
enum EtatInfraRouge {
NUL,
ANGLE_PLUS,
ANGLE_MOINS,
VALIDATION,
ABANDON
};
EtatInfraRouge etatInfraRouge = NUL;
/* =================== */
/* POUR LA DETECTION DCC */
//#include "DCC_Decoder.h" // Sur Mega 2560 INT0 = pin 21 => à tester avec pin 2 => INT4
const int pinInterruptionDCC = 2; // pin détection DCC
const int pinInterruptionACK = 3;
int etatSortieDCC = -1;
int adresseDCCDepart = 1 + (Nb_Aiguillages * (numCarte - 1));
/* ===================== */
/* LES DRAPEAUX D'AFFICHAGE */
bool Z = 0; // flag affichage mode COMMANDE
bool Y = 0; // flag affichage mode REGLAGE
bool X = 0; // flag affichage butée droite (angle max)
bool W = 0; // flag affichage butée gauche (angle min))
bool V = 0; // flag desactivation interruptions D2 et D3 en mode REGLAGE
bool U = 0; // flag affichage suite mode REGLAGE
bool T = 0; // flag reglage valeur butées
bool R; // flag affichage direction en cours
/* ======================== */
/* =========== GESTION DES QUATRE 74HC595 EN SERIE ================ */
const int horloge_Pin = 10;
const int verrou_Pin = 11;
const int data_Pin = 12;
const int pinDepartLed = 0;
#define numOfRegisterPins 32
boolean Registres[numOfRegisterPins];
/* ================================================================= */
void setup() {
Serial.begin(38400);
Serial.print(F("Adresse DCC de depart = ")); Serial.println(adresseDCCDepart);
/* Affichage message accueil pendant l'initialisation */
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0); lcd.print(Version);
lcd.setCursor(0,1); lcd.print(" Gestion des ");
lcd.setCursor(0,2); lcd.print("aiguillages ");lcd.print((Nb_Aiguillages * (numCarte - 1)) + 1);
lcd.print(" a "); lcd.print((Nb_Aiguillages * (numCarte - 1)) + Nb_Aiguillages);
lcd.setCursor(0,3); lcd.print(" Initialisation ...");
/* =================================================== */
/* Initialisation des pins E/S */
pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH);
pinMode(pinSelecteurMode, INPUT_PULLUP);
pinMode(pinSelecteurDirection, INPUT_PULLUP);
pinMode(pinLedvalRalenti, OUTPUT); digitalWrite(pinLedvalRalenti, LOW);
pinMode(pinLedTemoin, OUTPUT); analogWrite(pinLedTemoin, 130);
pinMode(pinLedPM, OUTPUT); digitalWrite(pinLedPM, LOW);
pinMode(pinBuzzer, OUTPUT);
pinMode(pinInterruptionDCC, INPUT_PULLUP);
/* ========================== */
/* Initialisation des BP avec la bibliothèque Bounce2 */
BPvalRalenti.attach(pinBPvalRalenti, INPUT_PULLUP);
BPvalRalenti.interval(dureeAntiRebond);
BP_Plus.attach(pinBPPlus, INPUT_PULLUP);
BP_Plus.interval(dureeAntiRebond);
BP_Plus.setPressedState(LOW);
BP_Moins.attach(pinBPMoins, INPUT_PULLUP);
BP_Moins.interval(dureeAntiRebond);
BP_Moins.setPressedState(LOW);
BPValidationReglage.attach(pinBPValidationReglage, INPUT_PULLUP);
BPValidationReglage.interval(dureeAntiRebond);
BPPointMilieu.attach(pinBPPointMilieu, INPUT_PULLUP);
BPPointMilieu.interval(dureeAntiRebond);
SelecteurMode.attach(pinSelecteurMode, INPUT_PULLUP);
SelecteurMode.interval(dureeAntiRebond);
SelecteurDirection.attach(pinSelecteurDirection, INPUT_PULLUP);
SelecteurDirection.interval(dureeAntiRebond);
/* ================================================= */
/* Initialisation des quatre 74HC595 pour la gestion des leds du TCO */
pinMode(data_Pin, OUTPUT);
pinMode(verrou_Pin, OUTPUT);
pinMode(horloge_Pin, OUTPUT);
//Reset tous les pins du 74HC595
razRegistres();
delay(500);
lcd.clear();
for (int J = 0; J < Nb_Aiguillages; J++){
Aiguillage[J].flagAppel = false;
/* Initialisation des adresses DCC */
Aiguillage[J].adresseDCC = adresseDCCDepart + J;
/* Initialisation des pins des servos */
pinMode(pinDepartServo + J, OUTPUT); // pour les servos à partir de 38
/* Initialisation des pins du clavier */
int pinBP;
if (J % 2 == 0) {
pinBP = (Nb_Aiguillages - J - 2) / 2 * 2;
} else {
pinBP = (Nb_Aiguillages - J + 1) / 2 * 2 - 1;
} // Fin de if (J % 2 == 0)
clavierBP[J].attach(pinDepartBP + pinBP, INPUT_PULLUP);
clavierBP[J].interval(dureeAntiRebond);
/* Lecture des données en EEProm */
lectureEEProm(J);
/* Positionnement des servos en fonction de la lecture de l'EEProm */
servoAiguillage[J].writeMicroseconds(Aiguillage[J].DernierePosition);
if (!servoAiguillage[J].attached()) {servoAiguillage[J].attach(pinDepartServo + J);}
delay(100);
servoAiguillage[J].writeMicroseconds(Aiguillage[J].DernierePosition);
delay(200);
Aiguillage[J].selectionServo = false;
/* on détache les servos */
if (servoAiguillage[J].attached()) {servoAiguillage[J].detach();}
delay(100);
/* Mise à jour des leds du TCO */
ecritRegistres((J * 2), (Aiguillage[J].DernierePosition == Aiguillage[J].angleDirect) ? HIGH : LOW);
ecritRegistres((J * 2) + 1, (Aiguillage[J].DernierePosition == Aiguillage[J].angleDirect) ? LOW : HIGH);
} // Fin de for (int J = 0; J < Nb_Aiguillages; J++)
/* Message de fin d'initialisation */
lcd.clear();
lcd.setCursor(0,0); lcd.print(" Gestion des ");
lcd.setCursor(1,1); lcd.print("aiguillages ");lcd.print(1 + (Nb_Aiguillages * (numCarte - 1))); lcd.print(" a "); lcd.print(Nb_Aiguillages + (Nb_Aiguillages * (numCarte - 1)));
lcd.setCursor(0,2); lcd.print(" Ralenti regle a "); lcd.print(valRalenti); lcd.print(" ");
lcd.setCursor(0,3); lcd.print(" P R E T ! ! ");
visualisationRalenti();
//Serial.print(Version); Serial.println(F(" P R E T !"));
/* =============================== */
/* on lit l'état du mode actuel */
delay(100);
etatSelecteurMode = SelecteurMode.read();
etatSelecteurDirection = SelecteurDirection.read();
delay(100);
/* ============================ */
delay(1000);
lcd.clear();
} // Fin de setup()
void loop() {
static int CompteurLoop;
/* on se sert de la boucle du loop */
CompteurLoop++; if (CompteurLoop == Nb_Aiguillages) {CompteurLoop = 0;}
/* ========================================= */
switch (etatActuel) {
case ACTIF:
// Si le temps d'inactivité atteint la limite contenue dans la constant "dureeInactivite" => on passe en veille
if (millis() - departChronoExecution > dureeInactivite) {
// On passe l'état actuel de la carte à "VEILLE"
etatActuel = VEILLE;
} // Fin de if (millis() - departChronoExecution > dureeInactivite)
break;
case VEILLE:
// On éteint les leds témoins
analogWrite(pinLedTemoin, 0);
digitalWrite(LED_BUILTIN, LOW);
// On éteint l'écran LCD
lcd.noBacklight();
lcd.noDisplay();
// initialisation des interruptions pour le réveil
attachInterrupt(digitalPinToInterrupt(pinInterruptionClavier), detectInterrupt, LOW);
//attachInterrupt(digitalPinToInterrupt(pinDetectionIR), detectInterrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(pinSelecteurMode), detectInterrupt, FALLING);
//attachInterrupt(digitalPinToInterrupt(pinInterruptionDCC), detectInterrupt, CHANGE);
// On met la carte en veille
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable(); // Activer le mode veille
sleep_mode(); // Entrer en mode veille
/* Le microcontrôleur est maintenant en veille jusqu'à ce qu'une interruption le réveille
.... zzzzzzzz ....
L'exécution reprend ici après le réveil. */
break;
case REVEIL :
/* Le réveil se fait via l'ISR qui change l'état à REVEIL */
// L'exécution reprend ici après le réveil
// on désactive le mode veille après le réveil
sleep_disable();
// On détache les interruptions
detachInterrupt(digitalPinToInterrupt(pinInterruptionClavier));
detachInterrupt(digitalPinToInterrupt(pinSelecteurMode));
// On allume les leds témoins
analogWrite(pinLedTemoin, 130);
digitalWrite(LED_BUILTIN, HIGH);
// On allume l'écran LCD
lcd.backlight();
lcd.display();
// On réinitialise le chrono d'activité
etatActuel = ACTIF;
departChronoExecution = millis();
break;
} // Fin de switch (etatActuel)
SelecteurMode.update();
if (SelecteurMode.changed()){
etatSelecteurMode = SelecteurMode.read();
} // Fin de if (SelecteurMode.changed())
clavierBP[CompteurLoop].update(); // on surveille les BP du clavier digital
if (clavierBP[CompteurLoop].fell()){
Clavier(CompteurLoop);
} // Fin de if (clavierBP[CompteurLoop].fell())
if (etatSelecteurMode == LOW){
//**********************************************
// Sélecteur choix MODE à droite => mode REGLAGE
//**********************************************
if (Y == 0){
/* On exécute ceci une seule fois. */
Y = 1;
dureeInactivite = 600000ul;
departChronoExecution = millis();
initMessagesModeReglage();
} // Fin de if (Y == 0)
/* Si appui sur le BP Point Milieu ou si appui sur la touche "MUTE" de la télécommande on met tous les aiguillages au point milieu. */
BPPointMilieu.update();
if ((BPPointMilieu.fell()||(etatSelecteurPointMilieu == HIGH)) &&(flagPointMilieu == false)) {
etatSelecteurPointMilieu = LOW;
PointMilieu();
} // Fin de if (BPPointMilieu.changed())
/*====================================================== */
if (Aiguillage[CompteurLoop].selectionServo == true) {
/* Si un bouton poussoir a été appuyé ou une touche numérique de la télécommande appuyée */
if (V == 0) {
/* On exécute ceci une seule fois. */
V = 1;
/* On attache le servo en cours. */
if (!servoAiguillage[CompteurLoop].attached()) {servoAiguillage[CompteurLoop].attach(pinDepartServo + CompteurLoop);}
/* Calcul de l'angle du Point Milieu pour le servo sélectionné en arrondissant à la dizaine */
Aiguillage[CompteurLoop].angleIntermediaire = (Aiguillage[CompteurLoop].angleDirect + Aiguillage[CompteurLoop].angleDevie) / 2;
Aiguillage[CompteurLoop].angleIntermediaire = ((Aiguillage[CompteurLoop].angleIntermediaire + 5) / 10) * 10;
/* On positionne le servo en cours à son point milieu pour un éventuel réglage mécanique. */
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
lcd.setCursor(4,3); lcd.print("Depart : ");
lcd.setCursor(12,3);lcd.print(Aiguillage[CompteurLoop].angleIntermediaire);
/* on initialise l'état du bouton de validation */
etatValidation = INIT;
} // Fin de if (V == 0)
do {
BP_Plus.update();
BP_Moins.update();
BPValidationReglage.update();
SelecteurMode.update();
SelecteurDirection.update();
/* On annule le réglage en cours par changement de Mode */
if (SelecteurMode.changed()) {
etatSelecteurMode = SelecteurMode.read();
if (etatSelecteurMode == HIGH){
//si on repasse en mode commande, on force la sortie de la boucle => annulation de l'opération en cours et on recommence
annulationReglage(CompteurLoop);
break;
} // Fin de if (etatselecteurMode == HIGH)
} // Fin de if ((SelecteurMode.changed())
/* ==================================================== */
if (SelecteurDirection.changed()){
etatSelecteurDirection = SelecteurDirection.read();
} // Fin de if (SelecteurDirection.changed())
afficheChoixDirection(CompteurLoop);
/* On teste l'appui sur le bouton de réglage angle +
ou l'appui sur la touche angle+ de la télécommande */
if (BP_Plus.isPressed()){
do {
Aiguillage[CompteurLoop].angleIntermediaire += pasReglage;
if (Aiguillage[CompteurLoop].angleIntermediaire > angleMaxi){
Aiguillage[CompteurLoop].angleIntermediaire = angleMaxi;
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
break;
} // Fin de if (Aiguillage[CompteurLoop].angleIntermediaire > angleMaxi)
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
lcd.setCursor(4,3); lcd.print("Valeur : ");
lcd.setCursor(12,3);lcd.print(Aiguillage[CompteurLoop].angleIntermediaire);
delay(200);
BP_Plus.update();
} while (BP_Plus.isPressed());
} // Fin de if (BP_Plus.isPressed())
/* ==================================================== */
/* On teste l'appui sur le bouton de réglage angle -
ou l'appui sur la touche angle- de la télécommande */
if (BP_Moins.isPressed()){
do {
Aiguillage[CompteurLoop].angleIntermediaire -= pasReglage;
if (Aiguillage[CompteurLoop].angleIntermediaire < angleMini){
Aiguillage[CompteurLoop].angleIntermediaire = angleMini;
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
break;
} // Fin de if (Aiguillage[CompteurLoop].angleIntermediaire > angleMaxi)
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
lcd.setCursor(4,3); lcd.print("Valeur : ");
lcd.setCursor(12,3);lcd.print(Aiguillage[CompteurLoop].angleIntermediaire);
delay(200);
BP_Moins.update();
} while (BP_Moins.isPressed());
} // Fin de if (BP_Moins.isPressed())
/* ==================================================== */
switch (etatValidation) {
case INIT:
/* On détecte si le bouton de validation est appuyé */
if (BPValidationReglage.fell()) {
debutPressionBP = millis();
//Serial.print("Appui : "); Serial.println(debutPressionBP);
etatValidation = PRESSE;
} // Fin de if (BPValidationReglage.fell())
break;
/* ================================================ */
case PRESSE:
/* On détecte quand le bouton de validation est relâché */
if (BPValidationReglage.rose()) {
finPressionBP = millis();
//Serial.print("Relache : "); Serial.println(finPressionBP);
dureeAppui = finPressionBP - debutPressionBP;
//Serial.print("Duree : ");Serial.println(dureeAppui);
etatValidation = RELACHE;
} // Fin de if (BPValidationReglage.rose())
break;
/* ==================================================== */
case RELACHE:
/* On traite en fonction de la durée d'appui et on sort de la boucle do*/
if (dureeAppui <= limitePressionCourteBP) {
//pression courte => validation
validationReglage(CompteurLoop, etatSelecteurDirection, Aiguillage[CompteurLoop].angleIntermediaire);
} else if (dureeAppui >= limitePressionLongueBP) {
// pression longue => RAZ des valeurs des servos aux angleMaxi et angleMini. Positionnement au Point Milieu.
anglesRAZ(CompteurLoop);
} else if (dureeAppui > limitePressionCourteBP && dureeAppui < limitePressionLongueBP) {
//pression moyenne => annulation de l'opération en cours et on recommence
annulationReglage(CompteurLoop);
} // Fin de if (dureeAppui <= limitePressionCourteBP)
etatValidation = SORTIE;
break;
/* =================================================================== */
case SORTIE:
break;
default:
etatValidation = INIT;
break;
} // Fin de switch (etatValidation)
} while (etatValidation != SORTIE); // Fin de do
} // Fin de if (Aiguillage[CompteurLoop].selectionServo == true)
} else if (etatSelecteurMode == HIGH){
//***********************************************
// Sélecteur choix MODE à gauche => mode COMMANDE
//***********************************************
if (Z == 0){
/* On exécute ceci une seule fois. */
Z = 1;
dureeInactivite = 300000ul;
departChronoExecution = millis();
initMessagesModeCommande();
/* On ne va pas se servir de l'IR le mode commande, donc on désactive la réception IR et on teste les trames DCC */
//IrReceiver.disableIRIn();
/* configuration DCC */
//DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
//DCC.SetupDecoder( 0x00, 0x00, digitalPinToInterrupt(pinInterruptionDCC));
/* ================= */
} // Fin de if (Z == 0)
/* on teste les trames DCC */
//DCC.loop();
/* ======================= */
BPvalRalenti.update(); // on surveille le BP de réglage du ralenti
if (BPvalRalenti.changed()) {reglageRalenti();}
if (Aiguillage[CompteurLoop].selectionServo == true) {
// Exécuter l’affichage une seule fois si R == 0
if (R == 0) {
R = 1;
// Définir l’angle cible et le message à afficher en fonction de DernierePosition
if (etatSortieDCC == -1){
Aiguillage[CompteurLoop].angleCible = (Aiguillage[CompteurLoop].DernierePosition == Aiguillage[CompteurLoop].angleDirect) ? Aiguillage[CompteurLoop].angleDevie : Aiguillage[CompteurLoop].angleDirect;
} else {
Aiguillage[CompteurLoop].angleCible = (etatSortieDCC == 0) ? Aiguillage[CompteurLoop].angleDevie : Aiguillage[CompteurLoop].angleDirect;
} // Fin de if (etatSortieDCC == -1)
// on attache le servomoteur correspondant s'il n'est pas déjà attaché
if (!servoAiguillage[CompteurLoop].attached()) {servoAiguillage[CompteurLoop].attach(pinDepartServo + CompteurLoop);}
String message = (Aiguillage[CompteurLoop].DernierePosition == Aiguillage[CompteurLoop].angleDirect) ? " vers devie ... " : " vers direct ... ";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Aiguillage ");
lcd.setCursor(11, 0);
lcd.print((Nb_Aiguillages * (numCarte - 1)) + CompteurLoop + 1);
lcd.print("/DCC ");
lcd.print(Aiguillage[CompteurLoop].adresseDCC);
lcd.setCursor(0, 1);
lcd.print(message);
} // Fin de if (R == 0)
ChangerPosition(CompteurLoop, Aiguillage[CompteurLoop].angleCible);
} // Fin de if (selection[CompteurLoop] == true)
/* on teste les trames DCC */
//DCC.loop();
/* ======================= */
} // Fin de if (etatSelecteurMode == LOW)
} // Fin de loop()
void BasicAccDecoderPacket_Handler(int adresseDecode, boolean activate, byte data) {
Serial.println(F("Appel ISR OK ")); tone(pinBuzzer,2000,100); // Debug
#ifndef Sprog3ON
/* N'est pas utilisé pour les tests avec une centrale Sprog3 */
adresseDecode -= 1;
adresseDecode *= 4;
adresseDecode += 1;
adresseDecode += (data & 0x06) >> 1; // DCC address decoding
/* ========================================================= */
#ifdef Z21_RCN213_OFF
/* Est utilisé pour une centrale z21 dont la norme RCN 213 n'est pas activée.*/
adresseDecode += 4;
/* ========================================================================= */
#endif
#endif
//Serial.print(F("Adresse decodee : "));Serial.print(adresseDecode); Serial.print(F(" / ")); Serial.println(adresseDCCDepart + Nb_Aiguillages - 1);
if ((adresseDecode >= adresseDCCDepart) && (adresseDecode <= adresseDCCDepart + Nb_Aiguillages - 1)){
Serial.print(F("Adresse decodee entre ")); Serial.print(adresseDCCDepart);
Serial.print(F(" et ")); Serial.println (adresseDCCDepart + Nb_Aiguillages - 1);
Serial.print(F(" Servo = ")); Serial.println(adresseDecode - adresseDCCDepart);
Aiguillage[adresseDecode - adresseDCCDepart].selectionServo = true;
etatSortieDCC = (data & 0x01) ? 1 : 0;
Serial.print(F("Etat : "));Serial.println(etatSortieDCC);
} // Fin de if ((adresseDecode >= adresseDCCDepart) && (adresseDecode <= adresseDCCDepart + Nb_Aiguillages))
} // Fin de procédure BasicAccDecoderPacket_Handler(int adresseDecode, boolean activate, byte data
void detectInterrupt(){
/* ISR appelé par interruption sur D18 et D19 pour sortir de veille et par le code DCC. */
if (etatActuel == VEILLE) {etatActuel = REVEIL; }
} // Fin de procédure detectInterrupt()
int lectureEEProm(int I){
/*
* byte 200 => valRalenti
*
* byte 10-11 => angleDirect aiguillage 0
* byte 12-13 => angleDevie aiguillage 0
* byte 14-15 => DernierPosition aiguillage 0
*
* byte 20-21 => angleDirect aiguillage 1
* byte 22-23 => angleDevie aiguillage 1
* byte 24-25 => DernierPosition aiguillage 1
*
* byte 160-161 => angleDirect aiguillage 15
* byte 162-163 => angleDevie aiguillage 15
* byte 164-165 => DernierPosition aiguillage 15
*/
if (I == 0) {
valRalenti = EEPROM.read(200);
if ((valRalenti < 1) || (valRalenti > 5)) {
valRalenti = 1;
EEPROM.update(200, valRalenti);
} // Fin de if ((valRalenti < 1) || (valRalenti > 5))
} // Fin de if (I == 0)
Aiguillage[I].angleDirect = EEPROM.read(I * 10) | ((int)EEPROM.read((I * 10) + 1)) << 8; // lecture des 2 ints pour int angleDirect[]
if (Aiguillage[I].angleDirect > angleMaxi || Aiguillage[I].angleDirect < angleMini){ // si incohérence de valeur ou initialisation (=255)
Aiguillage[I].angleDirect = angleMini; // on enregistre la limite pour angleMin
EEPROM.update((I * 10), Aiguillage[I].angleDirect & 0xFF); // écrit le premier int de la valeur int
EEPROM.update((I * 10) + 1, Aiguillage[I].angleDirect >> 8); // écrit le second int de la valeur int
} // Fin de if (Aiguillage[I].angleDirect > angleMaxi || Aiguillage[I].angleDirect < angleMini)
Aiguillage[I].angleDevie = EEPROM.read((I * 10) + 2) | ((int)EEPROM.read((I * 10) + 3)) << 8; // lecture des 2 ints pour int angleMax[]
if (Aiguillage[I].angleDevie > angleMaxi || Aiguillage[I].angleDevie < angleMini){ // si incohérence de valeur ou initialisation (=255)
Aiguillage[I].angleDevie = angleMaxi; // on enregistre la limite pour angleMax
EEPROM.update((I * 10) + 2, Aiguillage[I].angleDevie & 0xFF); // écrit le premier int de la valeur int
EEPROM.update((I * 10) + 3, Aiguillage[I].angleDevie >> 8); // écrit le second int de la valeur int
} // Fin de if (Aiguillage[I].angleDevie > angleMaxi || Aiguillage[I].angleDevie < angleMini)
Aiguillage[I].DernierePosition = EEPROM.read((I * 10) + 4) | ((int)EEPROM.read((I * 10) + 5)) << 8;
if (Aiguillage[I].DernierePosition != Aiguillage[I].angleDevie && Aiguillage[I].DernierePosition != Aiguillage[I].angleDirect){
Aiguillage[I].DernierePosition = (Aiguillage[I].angleDirect + Aiguillage[I].angleDevie) / 2; // si incohérence de valeur on se met au point milieu
EEPROM.update((I * 10) + 4, Aiguillage[I].DernierePosition & 0xFF); // écrit le premier int de la valeur int
EEPROM.update((I * 10) + 5, Aiguillage[I].DernierePosition >> 8); // écrit le second int de la valeur int
} // Fin de if (Aiguillage[I].DernierePosition < limitAngleMin || servoAiguillage[I].DernierePositionServo > limitAngleMax)
lcd.setCursor(0,0); lcd.print("Aiguillage: ");lcd.setCursor(13,0); lcd.print((Nb_Aiguillages * (numCarte - 1)) + 1 + I);
lcd.setCursor(15,0);lcd.print("/");lcd.print(Aiguillage[I].adresseDCC);
lcd.setCursor(0,1); lcd.print("Angle direct: ");lcd.setCursor(13,1);lcd.print(Aiguillage[I].angleDirect);
lcd.setCursor(0,2); lcd.print("Angle devie : ");lcd.setCursor(13,2);lcd.print(Aiguillage[I].angleDevie);
lcd.setCursor(0,3); lcd.print("Angle actuel: ");
if (Aiguillage[I].DernierePosition == Aiguillage[I].angleDirect){
lcd.setCursor(13,3);lcd.print("DIRECT");
} else {
lcd.setCursor(13,3);lcd.print("DEVIE ");
}
Aiguillage[I].angleIntermediaire = Aiguillage[I].DernierePosition;
Aiguillage[I].sens = 1;
} // Fin de procédure lectureEEProm()
void Clavier(int numServoEnCours){
departChronoExecution = millis(); // Réinitialisation de la tempo de veille
// Serial.println(F("Clavier OK"));
Aiguillage[numServoEnCours].selectionServo = true;
} // Fin de procédure Clavier()
void initMessagesModeReglage(){
tone(pinBuzzer,2000,300);
//Serial.println(F("Mode Reglage"));
lcd.clear();
lcd.setCursor(0,0); lcd.print("MODE REGLAGE:Pret!");
lcd.setCursor(0,1); lcd.print("Selection aiguillage");
lcd.setCursor(0,2); lcd.print("en appuyant le pous-");
lcd.setCursor(0,3); lcd.print("-soir correspondant.");
Z = 0; // RAZ flag affichage choix COMMANDE
W = 0; U = 0; T = 0; //CompteurLoop = 0;
} // Fin de procedure initMessagesModeReglage()
void afficheChoixDirection(int numServoEnCours) {
if ((etatSelecteurDirection == HIGH && W == 0) || (etatSelecteurDirection == LOW && U == 0)) {
// Met à jour les drapeaux en fonction de la direction choisie
W = (etatSelecteurDirection == HIGH) ? 1 : 0;
U = (etatSelecteurDirection == LOW) ? 1 : 0;
// Efface l'affichage et affiche le message correspondant
lcd.clear();
lcd.setCursor(4, 0); lcd.print((etatSelecteurDirection == HIGH) ? "Angle direct" : "Angle devie");
lcd.setCursor(4, 1); lcd.print("aiguillage ");
lcd.print((Nb_Aiguillages * (numCarte - 1)) + numServoEnCours + 1);
lcd.setCursor(0, 2); lcd.print("en cours de reglage!");
lcd.setCursor(4, 3); lcd.print("Depart : ");
lcd.setCursor(12, 3); lcd.print(Aiguillage[numServoEnCours].angleIntermediaire);
}
} // Fin de procédure afficheChoixDirection()
int validationReglage(int numServoEnCours, bool valDirection, int valReglage) {
/* pression courte => validation */
Serial.println("Validation");
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
if (valDirection == HIGH) {
lcd.clear();
lcd.setCursor(0,0); lcd.print(" Angle direct pour ");
lcd.setCursor(0,1); lcd.print(" aiguillage ");lcd.print((Nb_Aiguillages * (numCarte - 1)) + numServoEnCours + 1);
lcd.setCursor(0,2); lcd.print(" enregistre a ");lcd.print(valReglage);
Aiguillage[numServoEnCours].angleDirect = valReglage;
EEPROM.update((numServoEnCours * 10), Aiguillage[numServoEnCours].angleDirect & 0xFF);
EEPROM.update((numServoEnCours * 10) + 1, Aiguillage[numServoEnCours].angleDirect >> 8);
} else {
lcd.clear();
lcd.setCursor(0,0);lcd.print(" Angle devie pour");
lcd.setCursor(0,1);lcd.print(" aiguillage ");lcd.print((Nb_Aiguillages * (numCarte - 1)) + numServoEnCours + 1);
lcd.setCursor(0,2);lcd.print(" enregistre a ");lcd.print(valReglage);
Aiguillage[numServoEnCours].angleDevie = valReglage;
EEPROM.update((numServoEnCours * 10) + 2, Aiguillage[numServoEnCours].angleDevie & 0xFF);
EEPROM.update((numServoEnCours * 10) + 3, Aiguillage[numServoEnCours].angleDevie >> 8);
} // Fin de if (valDirection == 0)
Aiguillage[numServoEnCours].angleIntermediaire = valReglage;
Aiguillage[numServoEnCours].DernierePosition = valReglage;
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
delay(400);
tone(pinBuzzer,2500,100); delay(100); tone(pinBuzzer,2000,1000);
/* nouveau reglage */
lcd.setCursor(0,3);lcd.print(" Nouveau reglage ");
Aiguillage[numServoEnCours].selectionServo = false;
debutPressionBP = 0; finPressionBP = 0; dureeAppui = 0;
Z = 0; Y = 0; X = 0; W = 0; V = 0; U = 0; T = 0;
} // Fin de procédure validationReglage(int numServoEnCours, bool valDirection, int valReglage)
void annulationReglage(int numServoEnCours) {
/* pression moyenne => annulation */
Serial.println("Annulation");
for (int buz = 0; buz < 3; buz++){
tone(pinBuzzer,3000,50); delay(50);
} // Fin de for
lcd.clear();
lcd.setCursor(0,1);lcd.print(" O P E R A T I O N ");
lcd.setCursor(0,2);lcd.print(" A N N U L E E ! ! ");
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].DernierePosition);
delay(2500);
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();} // on "débranche" le servo
delay(50);
Aiguillage[numServoEnCours].selectionServo = false;
debutPressionBP = 0; finPressionBP = 0; dureeAppui = 0;
Z = 0; Y = 0; X = 0; W = 0; V = 0; U = 0; T = 0;
} // Fin de procédure annulationReglage(int numServoEnCours, bool valDirection, int valReglage)
void anglesRAZ(int numServoEnCours){
/* pression longue => RAZ */
Serial.println("RAZ");
for (int buz = 0; buz < 5; buz++){
tone(pinBuzzer,3000,50); delay(50);
} // Fin de for
Aiguillage[numServoEnCours].angleDirect = angleMaxi;
Aiguillage[numServoEnCours].angleDevie = angleMini;
Aiguillage[numServoEnCours].angleIntermediaire = (angleMaxi + angleMini) / 2;
Aiguillage[numServoEnCours].DernierePosition = Aiguillage[numServoEnCours].angleIntermediaire;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].DernierePosition);
delay(250);
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();} // on "débranche" le servo
delay(50);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Angle direct / devie");
lcd.setCursor(0,1); lcd.print(" aiguillage ");lcd.print(numServoEnCours + 17);
lcd.setCursor(0,2); lcd.print("initialise a ");lcd.print(Aiguillage[numServoEnCours].angleDirect); lcd.print("/"); lcd.print(Aiguillage[numServoEnCours].angleDevie);
lcd.setCursor(0,3); lcd.print(" Position a ");lcd.print(Aiguillage[numServoEnCours].DernierePosition);
EEPROM.update((numServoEnCours * 10), Aiguillage[numServoEnCours].angleDirect & 0xFF); EEPROM.update((numServoEnCours * 10) + 1, Aiguillage[numServoEnCours].angleDirect >> 8);
EEPROM.update((numServoEnCours * 10) + 2, Aiguillage[numServoEnCours].angleDevie & 0xFF); EEPROM.update((numServoEnCours * 10) + 3, Aiguillage[numServoEnCours].angleDevie >> 8);
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF); EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
delay(400);
/* nouveau reglage */
lcd.setCursor(0,3);lcd.print(" Nouveau reglage ");
Aiguillage[numServoEnCours].selectionServo = false;
Z = 0; Y = 0; X = 0; W = 0; V = 0; U = 0; T = 0;
} // Fin de procédure anglesRAZ()
void initMessagesModeCommande(){
tone(pinBuzzer,2500,100);
//Serial.println(F("Mode Commande"));
lcd.clear(); lcd.setCursor(0,0);
lcd.print("MODE COMMANDE:Pret!");
lcd.setCursor(0,1);
lcd.print("Selection aiguillage");
lcd.setCursor(0,2);
lcd.print("en appuyant le pous-");
lcd.setCursor(0,3);
lcd.print("-soir correspondant.");
Y = 0; // RAZ flag affichage choix REGLAGE
W = 0; U = 0; T = 0; // CompteurLoop = 0;
} // Fin de procédure initMessagesModeCommande()
void ChangerPosition(int numServoEnCours, int angleCible) {
if (!Aiguillage[numServoEnCours].flagAppel){
Aiguillage[numServoEnCours].flagAppel = true;
// Détermine le sens du mouvement
Aiguillage[numServoEnCours].sens = (Aiguillage[numServoEnCours].DernierePosition > angleCible) ? -1 : 1;
// Initialisation de l'angle intermédiaire à la dernière position au premier appel
Aiguillage[numServoEnCours].angleIntermediaire = Aiguillage[numServoEnCours].DernierePosition;
} // Fin de if (!Aiguillage[numServoEnCours].flagAppel)
Aiguillage[numServoEnCours].departRalenti = millis();
// Intervalle entre chaque mouvement au format millis
uint32_t intervalle = valRalenti * 4;
// Vérifie si le délai entre chaque mouvement est écoulé
if (Aiguillage[numServoEnCours].departRalenti - Aiguillage[numServoEnCours].chronoRalenti >= intervalle) {
Aiguillage[numServoEnCours].chronoRalenti = Aiguillage[numServoEnCours].departRalenti; // Met à jour le dernier temps pour ce servo
// Vérifie si l'angle cible est atteint
if (Aiguillage[numServoEnCours].angleIntermediaire == angleCible) {
// Détache le servomoteur
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
// Met à jour les paramètres et l'état de l'aiguillage
Aiguillage[numServoEnCours].selectionServo = false;
Aiguillage[numServoEnCours].DernierePosition = angleCible;
R = 0; etatSortieDCC = -1; Aiguillage[numServoEnCours].flagAppel = false;
// Met à jour les LEDs en fonction de l'angle cible
int etatLed = (angleCible == Aiguillage[numServoEnCours].angleDevie) ? 0 : 1;
ecritRegistres((numServoEnCours * 2), etatLed);
ecritRegistres((numServoEnCours * 2) + 1, !etatLed);
// Enregistre la dernière position en mémoire
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
lcd.setCursor(0, 1);
lcd.print((angleCible == Aiguillage[numServoEnCours].angleDevie) ? "DEVIE !!! : " : "DIRECT !!! : ");
lcd.print(angleCible);
// Affiche le message générique
lcd.setCursor(0, 2); lcd.print("Autre choix avec le");
lcd.setCursor(1, 3); lcd.print("BP correspondant.");
} else {
// Incrémente ou décrémente l'angle intermédiaire
Aiguillage[numServoEnCours].angleIntermediaire += Aiguillage[numServoEnCours].sens;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].angleIntermediaire);
} // Fin de if (Aiguillage[numServoEnCours].angleIntermediaire == angleCible)
} // if (Aiguillage[numServoEnCours].departRalenti - Aiguillage[numServoEnCours].chronoRalenti >= intervalle)
} // ChangerPosition(int numServoEnCours, int angleCible)
void PointMilieu(){
if (flagPointMilieu == false){
flagPointMilieu = true;
tone(pinBuzzer,5000,500);
digitalWrite(pinLedPM, HIGH);
lcd.clear();
lcd.setCursor(0,0); lcd.print("Mise au Point Milieu");
lcd.setCursor(5,1); lcd.print(" ");
lcd.setCursor(0,2); lcd.print(" pour aiguillage ");
for (int J = 0; J < Nb_Aiguillages; J++){
servoAiguillage[J].writeMicroseconds((angleMaxi + angleMini) / 2);
if (!servoAiguillage[J].attached()) {servoAiguillage[J].attach(pinDepartServo + J);}
delay(50);
servoAiguillage[J].writeMicroseconds((Aiguillage[J].angleDirect + Aiguillage[J].angleDevie) / 2);
lcd.setCursor(10,3); lcd.print((Nb_Aiguillages * (numCarte - 1)) + 1 + J);
delay(400);
if (servoAiguillage[J].attached()) {servoAiguillage[J].detach();}
} // Fin de for (int J = 0; J < Nb_Aiguillages; J++)
lcd.setCursor(0,0); lcd.print(" Mode Point Milieu ");
lcd.setCursor(5,1); lcd.print("A C T I F !");
lcd.setCursor(0,2); lcd.print("pour un centrage des");
lcd.setCursor(5,3); lcd.print("aiguillages");
do {
BPPointMilieu.update();
uint32_t actuelMillis = millis();
if (actuelMillis - precedentMillis >= 250) {
precedentMillis = actuelMillis;
etatLedPM =! etatLedPM;
digitalWrite(pinLedPM, etatLedPM);
} // Fin de if (actuelMillis - precedentMillis >= 250)
BPPointMilieu.update();
if ((BPPointMilieu.fell()||(etatSelecteurPointMilieu == HIGH)) &&(flagPointMilieu == true)) {
etatSelecteurPointMilieu = LOW;
flagPointMilieu = false;
digitalWrite(pinLedPM, HIGH);
lcd.setCursor(0,0); lcd.print(" Retour position ");
lcd.setCursor(5,1); lcd.print(" Initiale! ");
lcd.setCursor(0,2); lcd.print(" pour aiguillage ");
lcd.setCursor(0,3); lcd.print(" ");
for (int J = 0; J < Nb_Aiguillages; J++){
servoAiguillage[J].writeMicroseconds(Aiguillage[J].DernierePosition);
if (!servoAiguillage[J].attached()) {servoAiguillage[J].attach(pinDepartServo + J);}
delay(50);
servoAiguillage[J].writeMicroseconds(Aiguillage[J].DernierePosition);
delay(400);
lcd.setCursor(10,3); lcd.print((Nb_Aiguillages * (numCarte - 1)) + 1 + J);
if (servoAiguillage[J].attached()) {servoAiguillage[J].detach();}
} // Fin de for (int J = 0; J < Nb_Aiguillages; J++)
tone(pinBuzzer,5000,500);
digitalWrite(pinLedPM, LOW);
Y = 0; Z = 0;
break;
} // Fin de if ((BPPointMilieu.fell()||(etatSelecteurPointMilieu == LOW)) &&(flagPointMilieu == true))
} // Fin de do
while(1);
} //Fin de if (flagPointMilieu == false)
} // Fin procédure PointMilieu()
void reglageRalenti(){
if (BPvalRalenti.fell()) {
valRalenti += 1; if(valRalenti > 5) valRalenti = 1;
} else if (BPvalRalenti.rose()){
EEPROM.update(200, valRalenti);
valRalenti = EEPROM.read(200);
visualisationRalenti();
} // Fin de if (BP_ralenti.fell())
} // Fin de procédure reglageRalenti
void visualisationRalenti(){
/* visualisation de la valeur de valRalenti */
for (byte J = 0; J < valRalenti; J += 1){
digitalWrite(pinLedvalRalenti, HIGH);
tone(pinBuzzer,5000,50);
delay(200);
digitalWrite(pinLedvalRalenti, LOW);
delay(300);
} // Fin de for (byte J = 0; J < valRalenti; J += 1)
/* ======================================== */
} // Fin de procedure visualisationRalenti()
void razRegistres() {
// Place tous les pins du 74HC595 à l'état "OFF"
for (int i = 0; i < numOfRegisterPins; i++) {
Registres[i] = LOW;
}
// Met à jour les registres avec les valeurs initialisées
majRegistres();
} // Fin de void razRegistres()
void ecritRegistres(int index, int value) {
// Enregistrer la valeur dans le registre
Registres[index] = value;
// Met à jour les registres avec la nouvelle valeur
majRegistres();
} // Fin de ecritRegistres(int index, int value)
void majRegistres() {
// Mettre à jour et afficher les valeurs dans le registre
digitalWrite(verrou_Pin, LOW);
for (int i = numOfRegisterPins - 1; i >= 0; i--) {
digitalWrite(horloge_Pin, LOW);
digitalWrite(data_Pin, Registres[i]);
digitalWrite(horloge_Pin, HIGH);
}
digitalWrite(verrou_Pin, HIGH);
} // Fin de majRegistres()
Sélection Direction
Direct/Devie
Sélection Mode
Commande/Réglage
Réglage Ralenti
(mode Commande)
Mise au Point Milieu
(mode Réglage)
Angle +
(mode Réglage)
Angle -
(mode Réglage)
Validation réglage
(mode Réglage)
Aiguillage 1
Aiguillage 2
Aiguillage 16
BP 1
BP 2
BP 16
DIRECT
DEVIE
Témoins
Aiguillage 1
Témoins
Aiguillage 2
Témoins
Aiguillage 16