/*
***********************************************
* Gestion de 16 aiguillages arduino Mega 2560 *
* version 20240918 *
* 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 14/07/2023 => reprise proto sur gros bugs
le 15/07/2023 => sélecteurs MODE et BUTTEE en PULLUP => OK
=> BP ralenti en PULLUP + led ralenti => OK
=> essais avec les BP du clavier en PULLUP => OK
Il faut modifier le montage des diodes du clavier (interruption) (voir https://www.tinkercad.com/things/5Sh7bMLF3vD)
le 16/07/2023 => tous les boutons semblent fonctionner en mode PULLUP => OK
le 17/07/2023 => procédure point milieu => OK
le 18/07/2023 => mise en veille & réveil par interruption clavier => OK (/!\ ATTENTION AUX INTERRUPTIONS IR ET DCC /!\)
le 19/07/2023 => leds témoins => OK
le 21/07/2023 => IR & réveil par interruption IR => OK
le 23/07/2023 => sortie du mode réglage par modification du sélecteur ne fonctionne pas => à voir
=> tests de la gestion de mise en veille sans LowPower.h => OK mais ne change rien par rapport aux interruptions sur d2 et D3
le 25/07/2023 => reprise de la procédure de validation => à tester.
le 27/07/2023 => suppression de la variable ServoEnCours remplacée par (numBoutonPoussoir - 1) => tout semble OK
le 27/07/2023 => inversion des pins IR et sélecteur Mode.
le 04/08/2023 => reprise totale de la lecture des BP du clavier. On ne passe plus par l'interruption sur D19 qui ne sert plus qu'à réveiller l'arduino. => OK
=> test avec fell() au lieu de changed()+read() => OK
le 05/08/2023 => connexion du sélecteur Mode à l'interruption 19 au travers d'une diode (comme les BP) pour réveiller l'arduino => tout semble OK
=> suppression de le variable numBoutonPoussoir => tout semble OK
=> déactivation de l'IR pendant les mouvements des servos => à vérifier ce que ca donne avec l'appel ses mouvemenst par IR
=> réveil par IR => OK
le 06/08/2023 => tests du sélecteur sur D19 => NOK. Essais en mettant le clavier sur D2 (LOW) et le sélecteur sur D19 (CHANGE) => Tout semble OK.
le 17/08/2023 => modification de la mise en veille. Changement de bibliothèques
le 28/09/2023 => suppression de la déclaration du pin IR et DCC dans le setup
=> interrupt Clavier sur D19 au lieu de D2
=> SelectMode sur D7
le 16/10/2023 => modification de l'attribution des pins du Mega aux claviers (pin 22 = BP 15, pin 23 = BP 16, pin 24 = BP 13, pin 25 = BP 14, etc ...)
dans la boucle du setup nouvelle boucle pour l'attribution des pins aux BP => remplace la ligne 314
le 28/01/2024 => réinitialsation des servos => mise au point milieu.
modification des valeurs de butées Mini et Maxi
le 05/02/2024 => mettre BP_Plus et BP_Moins dans une boucle => essais avec la bibliothèque Adafruit_Debounce.h => abandonné.
le 01/03/2024 => bug incompréhensible. Si initialisation du système en mode réglage, la procédure anglesRAZ() est appellée des le choix
de l'aiguillage bien que les conditions sur la duree d'appui de soient pas remplies. J'ai donc ajouté une condition
supplémentaire bidon => c'est pas beau mais ca semble fonctionner.
le 21/03/2024 => mise en place du DCC. Il semble qu'il y ait des interférences logicielles avec la détection IR donc essais en supprimant
tout ce qui concerne l'IR
le 29/03/2024 => OK sans l'Infra-Rouge
le 27/05/2024 => reprise de la mise en veille. Tests du réveil par DCC.=> NOOK
le 08/06/2024 => Ajout de l'infra rouge pour la partie réglage.
=> 09/06/2024 > Procédure Point Milieu OK
=> 11/12/2024 > Abandon, Validation, Direction semblent OK
=> 16/06/2024 > Angle + et Angle - semblent OK
le 20/06/2024 => reformulation du calcul de l'adresse DCC.
le 06/08/2024 => la fonction de réglage de la vitesse de déplacement des aiguilles ne fonctionne plus????? On teste sur WOKWI.
le 07/08/2024 => modification de la gestion de 74HC595
le 19/09/2024 => reprise du développement pour une utilisation d'une télécommande TV
*/
String Version = "Tests.IR/DCC-20240918";
#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
/* ============================================================================== */
/* A decommenter si changement d'état des aiguillages par bascule */
//#define DCC_Switch
/* ============================================================= */
#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 = 5; // incrémentation des angles pour les réglages
struct aiguillage {
int adresseDCC;
int angleDirect;
int angleDevie;
int angleIntermediaire;
int DernierePosition;
bool selectionServo;
int sens;
};
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;
uint32_t finPressionBP;
uint32_t dureeAppui;
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 etatBouton = 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
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 R1; bool R2; // flag affichage direction en cours
/* ======================== */
/* =========== GESTION DES QUATRE 74HC595 EN SERIE ================ */
const int horloge_Pin = 10; // Pin de l'horloge (SH)
const int verrou_Pin = 11; // Pin de verrouillage (ST)
const int data_Pin = 12; // Pin de donnée (DS)
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(1500);
lcd.clear();
for (int J = 0; J < Nb_Aiguillages; J++){
/* 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;
}
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;
/* 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);
/* on détache les servos */
if (servoAiguillage[J].attached()) {servoAiguillage[J].detach();}
} // 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 */
etatSelecteurMode = SelecteurMode.read();
etatSelecteurDirection = SelecteurDirection.read();
/* ============================ */
delay(2000);
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;}
/* ========================================= */
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 */
etatBouton = 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);
/* si appui sur la touche "C" de la télécommande */
if (etatInfraRouge == ABANDON){
// => annulation de l'opération en cours et on recommence
etatInfraRouge = NUL;
annulationReglage(CompteurLoop);
break; break; // /!\ il s'agit bien d'un double break
} // Fin de if (etatInfraRouge == ABANDON)
/* =========================================== */
/* 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() || etatInfraRouge == ANGLE_PLUS){
do {
if (!IrReceiver.decode() && etatInfraRouge == ANGLE_PLUS) {
/* S'il n'y a plus d'appui sur la télécommande on passe etatInfraRouge à NUL ce qui arrête le mouvement du servomoteur */
etatInfraRouge = NUL;
IrReceiver.resume();
} // Fin de if (!IrReceiver.decode() && etatInfraRouge == ANGLE_PLUS)
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(300);
BP_Plus.update();
} while (BP_Plus.isPressed());
} // Fin if (BP_Plus.isPressed() || etatInfraRouge == ANGLE_PLUS){
/* ==================================================== */
/* 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() || etatInfraRouge == ANGLE_MOINS){
do {
if (!IrReceiver.decode() && etatInfraRouge == ANGLE_MOINS) {
/* S'il n'y a plus d'appui sur la télécommande on passe etatInfraRouge à NUL ce qui arrête le mouvement du servomoteur */
etatInfraRouge = NUL;
IrReceiver.resume();
} // Fin de if (!IrReceiver.decode() && etatInfraRouge == ANGLE_MOINS)
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 < angleMini)
servoAiguillage[CompteurLoop].writeMicroseconds(Aiguillage[CompteurLoop].angleIntermediaire);
lcd.setCursor(4,3); lcd.print("Valeur : ");
lcd.setCursor(12,3);lcd.print(Aiguillage[CompteurLoop].angleIntermediaire);
delay(300);
BP_Moins.update();
} while (BP_Moins.isPressed());
} // Fin deif (BP_Moins.isPressed() || etatInfraRouge == ANGLE_MOINS){
/* ==================================================== */
switch (etatBouton) {
case INIT:
/* On détecte si le bouton de validation est appuyé */
if (BPValidationReglage.fell()) {
debutPressionBP = millis();
Serial.print("Appui : "); Serial.println(debutPressionBP);
etatBouton = 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);
etatBouton = 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)
etatBouton = SORTIE;
break;
/* =================================================================== */
case SORTIE:
break;
default:
etatBouton = INIT;
break;
} // Fin de switch (etatBouton)
} while (etatBouton != 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) {
/* On attache le servomoteur correspondant */
if (!servoAiguillage[CompteurLoop].attached()) {servoAiguillage[CompteurLoop].attach(pinDepartServo + CompteurLoop);}
Aiguillage[CompteurLoop].sens = (Aiguillage[CompteurLoop].angleDirect > Aiguillage[CompteurLoop].angleDevie) ? -1 : 1;
if (Aiguillage[CompteurLoop].DernierePosition == Aiguillage[CompteurLoop].angleDirect){
if(R1 == 0){
/* On exécute ceci une seule fois. */
R1 = 1;
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(" vers devie ... ");
} // Fin de if (R1 == 0)
DirectToDevie(CompteurLoop);
} else {
if(R2 == 0){
/* On exécute ceci une seule fois. */
R2 = 1;
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(" vers direct ... ");
} // Fin de if (R2 == 0)
DevieToDirect(CompteurLoop);
} // Fin de if (Aiguillage[CompteurLoop].DernierePosition == Aiguillage[CompteurLoop].angleDirect)
} // 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)){
int numServoEnCours = adresseDecode - adresseDCCDepart;
if (!servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].attach(pinDepartServo + (numServoEnCours));}
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(numServoEnCours);
#ifdef DCC_Switch
/* METHODE AVEC BASCULE DIRECT/DEVIE */
Serial.println(F(" Methode par bascule. "));
Aiguillage[numServoEnCours].selectionServo = true;
numServoEnCours = 0;
/* ================================= */
#else
/* METHODE AVEC FONCTIONS */
Serial.println(F(" Methode par fonction. "));
boolean etatSortie = (data & 0x01) ? 1 : 0;
Serial.print(F("Etat : "));Serial.println(etatSortie);
Aiguillage[numServoEnCours].sens = (Aiguillage[numServoEnCours].angleDirect > Aiguillage[numServoEnCours].angleDevie) ? -1 : 1;
if (etatSortie == 1&& (Aiguillage[numServoEnCours].DernierePosition == Aiguillage[numServoEnCours].angleDirect)){
// si etatSortie = 1 et que l'aiguillage concerné est en position DIRECTE, on passe en position DEVIE
lcd.clear();
lcd.setCursor(0,0);lcd.print("Aiguillage ");
lcd.setCursor(11,0);lcd.print(numServoEnCours + 1);
lcd.print("/DCC "); lcd.print(Aiguillage[numServoEnCours].adresseDCC);
lcd.setCursor(0,1);lcd.print(" vers DEVIE ... ");
do {
Aiguillage[numServoEnCours].angleIntermediaire += Aiguillage[numServoEnCours].sens;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].angleIntermediaire);
delay(valRalenti * 2);
if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDevie){
/* On détache le servomoteur correspondant */
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
Aiguillage[numServoEnCours].DernierePosition = Aiguillage[numServoEnCours].angleDevie;
/* allumage des leds correspondantes */
ecritRegistres((numServoEnCours * 2), LOW);
ecritRegistres((numServoEnCours * 2) + 1, HIGH);
/* ==================================*/
/* message de fin */
lcd.setCursor(0,1);lcd.print("DEVIE !!! : ");lcd.print(Aiguillage[numServoEnCours].angleDevie);
lcd.setCursor(0,2);lcd.print("Autre choix avec le");
lcd.setCursor(1,3);lcd.print("BP correspondant.");
/* ============== */
/* mise em mémoire de la dernière position */
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
/* ======================================= */
numServoEnCours = 0;
break;
} // Fin de if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDevie)
} while(1);
} else if (!etatSortie && (Aiguillage[numServoEnCours].DernierePosition == Aiguillage[numServoEnCours].angleDevie)){
// si etatSortie = 0 et que l'aiguillage concerné est en position DEVIE, on passe en position DIRECT
lcd.clear();
lcd.setCursor(0,0);lcd.print("Aiguillage ");
lcd.setCursor(11,0);lcd.print(numServoEnCours + 1);
lcd.print("/DCC "); lcd.print(Aiguillage[numServoEnCours].adresseDCC);
lcd.setCursor(0,1);lcd.print(" vers DIRECT ... ");
do {
Aiguillage[numServoEnCours].angleIntermediaire -= Aiguillage[numServoEnCours].sens;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].angleIntermediaire);
delay(valRalenti * 2);
if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDirect){
/* On détache le servomoteur correspondant */
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
Aiguillage[numServoEnCours].DernierePosition = Aiguillage[numServoEnCours].angleDirect;
/* allumage des leds correspondantes */
ecritRegistres((numServoEnCours * 2), HIGH);
ecritRegistres((numServoEnCours * 2) + 1, LOW);
/* ================================= */
/* message de fin */
lcd.setCursor(0,1);lcd.print("DIRECT !!! : ");lcd.print(Aiguillage[numServoEnCours].angleDirect);
lcd.setCursor(0,2);lcd.print("Autre choix avec le");
lcd.setCursor(1,3);lcd.print("BP correspondant.");
/* ============== */
/* mise em mémoire de la dernière position */
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
/* ======================================= */
numServoEnCours = 0;
break;
} // Fin de if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDirect)
} while(1);
} // Fin de if (etatSortie == 1&& (Aiguillage[numServoEnCours].DernierePosition == Aiguillage[numServoEnCours].angleDirect))
/* ====================== */
#endif
} // 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){
// etatSelecteurDirection = LOW => bouton à gauche => position angleDirect
// etatSelecteurDirection = HIGH => bouton à droite => position angleDevie
if (etatSelecteurDirection == HIGH) {
if (W == 0){
/* On exécute une seule fois */
W = 1;
U = 0;
lcd.clear();
lcd.setCursor(4,0); lcd.print("Angle direct");
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 if (W == 0)
} else if (etatSelecteurDirection == LOW) {
if (U == 0){
/* On exécute une seule fois */
U = 1;
W = 0;
lcd.clear();
lcd.setCursor(4,0); lcd.print("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 if (U == 0)
} // Fin de if (etatSelecteurDirection == HIGH)
}// Fin de procédure afficheChoixDirection()
int validationReglage(int numServoEnCours, bool valDirection, int valReglage) {
/* pression courte => 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) {
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){
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;
debutPressionBP = 0; finPressionBP = 0; dureeAppui = 0;
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 DirectToDevie(int numServoEnCours){
//Serial.print(F("DirectToDevie pour ")); Serial.println(numServoEnCours);
Aiguillage[numServoEnCours].angleIntermediaire += Aiguillage[numServoEnCours].sens;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].angleIntermediaire);
delay(valRalenti * 2);
if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDevie){
/* On détache le servomoteur correspondant */
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
Aiguillage[numServoEnCours].selectionServo = false;
Aiguillage[numServoEnCours].DernierePosition = Aiguillage[numServoEnCours].angleDevie;
/* allumage des leds correspondantes */
ecritRegistres((numServoEnCours * 2), LOW);
ecritRegistres((numServoEnCours * 2) + 1, HIGH);
/* ==================================*/
/* messages */
R1 = 0;
lcd.setCursor(0,1);lcd.print("DEVIE !!! : ");lcd.print(Aiguillage[numServoEnCours].angleDevie);
lcd.setCursor(0,2);lcd.print("Autre choix avec le");
lcd.setCursor(1,3);lcd.print("BP correspondant.");
/* ======== */
/* mise em mémoire de la dernière position */
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
/* ======================================= */
} // Fin de if (angleIntermediaire[numServoEnCours] == angleDevie[numServoEnCours])
} // Fin de procédure DirectToDevie
void DevieToDirect(int numServoEnCours) {
//Serial.print(F("DevieToDirect pour ")); Serial.println(numServoEnCours);
Aiguillage[numServoEnCours].angleIntermediaire -= Aiguillage[numServoEnCours].sens;
servoAiguillage[numServoEnCours].writeMicroseconds(Aiguillage[numServoEnCours].angleIntermediaire);
delay(valRalenti * 2);
if (Aiguillage[numServoEnCours].angleIntermediaire == Aiguillage[numServoEnCours].angleDirect){
/* On détache le servomoteur correspondant */
if (servoAiguillage[numServoEnCours].attached()) {servoAiguillage[numServoEnCours].detach();}
Aiguillage[numServoEnCours].selectionServo = false; // on annule la sélection du servo
Aiguillage[numServoEnCours].DernierePosition = Aiguillage[numServoEnCours].angleDirect;
/* allumage des leds correspondantes */
ecritRegistres((numServoEnCours * 2), HIGH);
ecritRegistres((numServoEnCours * 2) + 1, LOW);
/* ================================= */
/* messages */
R2 = 0;
lcd.setCursor(0,1);lcd.print("DIRECT !!! : ");lcd.print(Aiguillage[numServoEnCours].angleDirect);
lcd.setCursor(0,2);lcd.print("Autre choix avec le");
lcd.setCursor(1,3);lcd.print("BP correspondant.");
/* ======== */
/* mise em mémoire de la dernière position */
EEPROM.update((numServoEnCours * 10) + 4, Aiguillage[numServoEnCours].DernierePosition & 0xFF);
EEPROM.update((numServoEnCours * 10) + 5, Aiguillage[numServoEnCours].DernierePosition >> 8);
/* ======================================= */
} // Fin de if (angleIntermediaire[numServoEnCours] == Aiguillage[numServoEnCours].angleDirect)
} // Fin de procédure DevieToDirect
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();
if ((IrReceiver.decode()) && (IrReceiver.decode() != -1)) {
decodeSignalIR();
} // Fin de if ((IrReceiver.decode()) && (IrReceiver.decode() != -1))
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()
void decodeSignalIR(){
//Serial.println(F("Decodeur IR "));
int numBoutonPoussoir = 0;
IrReceiver.disableIRIn();
if (millis() - precedentChronoDetection >= detectionDelai) {
switch(IrReceiver.decodedIRData.decodedRawData){
case 0x1040:
case 0x1840:
// touche 0
if (flagDizaine == false){
flagDizaine = true;
} else {
flagDizaine = false;
numBoutonPoussoir = 10;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
}
break;
case 0x1041:
case 0x1841:
// touche 1
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 11;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 1;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1042:
case 0x1842:
// touche 2
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 12;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 2 ;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1043:
case 0x1843:
// touche 3
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 13;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 3;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1044:
case 0x1844:
// touche 4
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 14;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 4;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1045:
case 0x1845:
// touche 5
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 15;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 5;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1046:
case 0x1846:
// touche 6
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 16;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 6;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1047:
case 0x1847:
// touche 7
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 17;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 7;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1048:
case 0x1848:
// touche 8
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 18;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 8;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1049:
case 0x1849:
// touche 9
if (flagDizaine == true){
flagDizaine = false;
numBoutonPoussoir = 19;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} else {
numBoutonPoussoir = 9;
Aiguillage[numBoutonPoussoir - 1].selectionServo = true;
//Serial.print(F("Aiguillage "));Serial.println(numBoutonPoussoir);
} // Fin de if (flagDizaine == true)
if (!servoAiguillage[numBoutonPoussoir - 1].attached()) {servoAiguillage[numBoutonPoussoir - 1].attach(pinDepartServo + numBoutonPoussoir - 1);}
tone(pinBuzzer,4000,50);
IrReceiver.resume();
delay(200);
numBoutonPoussoir = 0;
break;
case 0x1055:
case 0x1855:
// touche flèche gauche mode commande
etatSelecteurMode = HIGH;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x1056:
case 0x1856:
// touche flèche droite mode réglage
etatSelecteurMode = LOW;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x1054:
case 0x1854:
// touche flèche haut angle direct
etatSelecteurDirection = HIGH;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x1053:
case 0x1853:
// touche flèche bas angle devié
etatSelecteurDirection = LOW;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x1050:
case 0x1850:
// touche volume +
etatInfraRouge = ANGLE_PLUS;
//tone(pinBuzzer,6000,50);
//IrReceiver.resume();
//delay(200);
break;
case 0x1051:
case 0x1851:
// touche volume -
etatInfraRouge = ANGLE_MOINS;
//tone(pinBuzzer,6000,50);
//IrReceiver.resume();
//delay(200);
break;
case 0x1075:
case 0x1875:
// touche OK (Validation)
etatInfraRouge = VALIDATION;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x1065:
case 0x1865:
// touche C (Abandon)
etatInfraRouge = ABANDON;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
case 0x104D:
case 0x184D:
// touche mute (Point Milieu)
etatSelecteurPointMilieu = HIGH;
tone(pinBuzzer,6000,50);
IrReceiver.resume();
delay(200);
break;
default:
etatInfraRouge == NUL;
Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);
IrReceiver.resume();
delay(200);
} // Fin de switch(results.value)
IrReceiver.resume();
delay(200);
precedentChronoDetection = millis();
} // Fin de if (millis() - precedentChronoDetection >= detectionDelai)
IrReceiver.enableIRIn();
} // Fin de procedure decodeSignalIR()