Menu HTML / Javascript : Aperçu

Blog du réseau du Mesnil-sur-Jorg

mardi 23 juillet 2024
      Membre de Train d'enfer 95

Arduino : Décodeur DCC pour aiguillages à solénoïdes


20240623_070457.jpg

Dernière réalisation arduino : un décodeur DCC pour aiguillages à bobines.

  • Arduino Nano
  •  Deux ULN2803A pour passer la puissance.
  • Un 74HC595 pour alimenter les leds bicolores de positionnement sur le TCO. 
  • Gère 4 aiguillages qui peuvent être commandés soit en DCC, soit par 4 boutons poussoirs sur le TCO.
  • Adresse DCC de départ règlable par boutons poussoirs (stockée en EEprom).
  • Dernières positions des aiguillages stockées en EEprom.
  • Alimentation en 15 volts

    Principe de base Locoduino (https://www.locoduino.org/spip.php?article142).
    Code peronnel.

      20240623_070451.jpg

2024-06-25.png

 

2024-06-25

 

2024-06-25

 

2024-06-25

 

Voici le code 

 


/*
    ***********************************************
    * Décodeur DCC pour 4 aiguillages à bobines   *
    *              version 20240621               *
    *       Les BP sont montés en PULL_UP         *
    *            et gérés par Bounce2             *
    *   sauf ceux connectés à  A6 et A7           *
    * qui sont des sorties uniquement analogiques *
    *                                             *
    *              Arduino Nano                   *
    ***********************************************

      
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !            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é. Merci de m'informer de toute modification du code ce qui     !
  ! me permettra de continuer à apprendre.                                  !
  !                                                                         !
  ! auteur Philippe GUENET - philippe@wgnt-train.fr - https://wgnt-train.fr !
  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  le 20/06/2024 => reformulation du calcul de l'adresse DCC.
*/

/* PCB "Arduino Gestion 4 aiguillage bobines par ULN2803A.dip"
Les E/S des  deux ULN2803A sont connectés en paire pour passer plus d'intensité pour les bobines.

On utilise un 74HC595 pour gérer les leds témoins du TCO.

/! Sur certains modèles, A6 et A7 sont exclusivement analogiques. Donc on les emploiera exclusivement dans ce mode. /!
/! Le code ci-après est fait pour des résistances de tirage de 1 Ko montées en PULLUP sur A6 et A7. 
La valeur 300 peut être ajustée dans le code ligne 88./!

Pour la lecture / écriture en eeprom, les valeurs stockées étant sur 1 octet, on pourrait le faire aux adresses 0, 1, 2 et 3.
mais par précaution, on le fera aux adresses 10, 20, 30 et 40. 

La valeur de l'adresse DCC de départ sera stockée sur l'adresse 50.

L'initialisation se fait pour une adresse DCC de départ de 100 mais pourra être ajustée avec les boutons poussoirs sur A6 et A7
et enregistrée en EEprom par le poussoir sur A5.

La durée de l'impulsion est configurée à 180 mS après essais avec des aiguillages Jouef, mais peut être ajustée dans le code ligne 86.

On peut utiliser autant de cartes que l'on veut. Il suffit d'ajuster la ligne 52. Bien évidement, l'adresse DCC de départ doit
être la même pour toutes les cartes. C'est le proramme qui se charge d'attribuer l'adresse DCC des aiguillages gérés par chacune
des cartes.

En fonction de votre configuration, il faudra remplacer les " " par des < > pour l'inclusion des bibliothèques lignes 53, 54 et 101
*/
 
  #include  "EEPROM.h"                                                                                    // Inclure la bibliothèque EEPROM.h
  #include  "Bounce2.h"                                                                                     // Inclure la bibliothèque Bounce2h
  #define numCarte 1
  
  //#define Sprog3ON                                                                                        // A décommenter si utilisation de la Sprog3const int Nb_Aiguillages = 4;
  
  const int Nb_Aiguillages = 4;
  const int pinPoussoir[Nb_Aiguillages] = {A0, A1, A2, A3};
  const int pinDirectAiguillages[Nb_Aiguillages] = {3, 5, 7, 9};
  const int pinDevieAiguillages[Nb_Aiguillages] = {4, 6, 8, 13};
  const int pinPoussoirValid = A5;
  const int pinPoussoirPlus = A6;
  const int pinPoussoirMoins = A7;

  
  enum EtatDirection{ DIRECT = 1, DEVIE = 2 };
  struct aiguillage {
    int adresseDCC;
    int pinDirect;
    int pinDevie;
    EtatDirection DernierePosition;
  };
  aiguillage Aiguillage[Nb_Aiguillages];

  const uint32_t dureeAntiRebond = 50;
  Bounce BPclavier[Nb_Aiguillages] = Bounce();
  //Bounce2::Button BP_Valid = Bounce2::Button();
  Bounce BP_Valid = Bounce();
  unsigned long dernierAppel_BP_Plus = 0;  // Dernière fois que l'état du bouton Plus a changé
  unsigned long dernierAppel_BP_Moins = 0; // Dernière fois que l'état du bouton Moins a changé
  int dernierEtat_BP_Plus = HIGH;
  int dernierEtat_BP_Moins = HIGH;
  
  const uint32_t dureeImpulsion = 180ul;
  uint32_t tempsDebutImpulsion = 0;
  const int limiteAnalogique = 300;

  int CompteurLoop = 0;

  /* =========== GESTION DU 74HC595 ================ */                                    
  const int data_Pin = 12;                    //entrée data (pin 14 sur le 75HC595)        
  const int verrou_Pin = 11;                  //horloge en sortie (pin 12 sur le 75HC595)         
  const int horloge_Pin = 10;                 //decalage (pin 11 sur le 75HC595                                                                              
  #define numOfRegisterPins 8
  boolean Registres[numOfRegisterPins];
  /* =============================================== */

  /* POUR LA DETECTION DCC */
  #include "DCC_Decoder.h"                                                                                                                                                
  #define pinInterruptionDCC 2                                                                              // pin détection DCC
  int adresseDCCDepart = 100 + (Nb_Aiguillages * (numCarte - 1));                                           // de 100 à 115 pour la carte 1, de 116 à 131 pour la carte 2                                       
  int eepromAdresseDCCDepart = 50;                                                                   // adresse mémoire où est enregistrée la valeur de adressedepart.
  /* ================================== */
 
void setup() {
  //Serial.begin(38400);
  //Serial.println(F("Initialisation ... "));
  BP_Valid.attach(pinPoussoirValid, INPUT_PULLUP);
  BP_Valid.interval(dureeAntiRebond);
  
  /* Initialisation du 74HC595 pour la gestion des leds du TCO */
  pinMode(data_Pin, OUTPUT);
  pinMode(verrou_Pin, OUTPUT);
  pinMode(horloge_Pin, OUTPUT);  
  clearRegisters();            //Reset tous les pins du 74HC595
  /* ======================================================== */

  /* Lire la valeur de l'adresse de départ du décodeur DCC */
  adresseDCCDepart = (EEPROM.read(eepromAdresseDCCDepart) << 8) | (EEPROM.read(eepromAdresseDCCDepart + 1) & 0xFF);
  //Serial.print(F("Adresse DCC de départ = "));Serial.println(adresseDCCDepart);
  
  if (adresseDCCDepart <= 0){
    adresseDCCDepart = 100 + (Nb_Aiguillages * (numCarte - 1));
    EEPROM.update(eepromAdresseDCCDepart, adresseDCCDepart >> 8);        // Octet de poids fort
    EEPROM.update(eepromAdresseDCCDepart + 1, adresseDCCDepart & 0xFF);  // Octet de poids faible
  } // Fin de if (adresseDCCDepart <= 0)
  
  for (int i = 0; i < Nb_Aiguillages; i++) {
    /* Attribution de l'adresse DCC pour chaque aiguillage */
    Aiguillage[i].adresseDCC = adresseDCCDepart +  i;
    //Serial.print(F("Adresse DCC aiguillage ")); Serial.print(i); Serial.print(F(" = "));Serial.println(Aiguillage[i].adresseDCC);
    /* =================================================== */
    
    /* Pour les boutons poussoirs */
    BPclavier[i].attach(pinPoussoir[i], INPUT_PULLUP);
    BPclavier[i].interval(dureeAntiRebond);
    /* ========================== */

    /* Configuration des pins des aiguillages */
    Aiguillage[i].pinDirect = pinDirectAiguillages[i];
    Aiguillage[i].pinDevie = pinDevieAiguillages[i];
    pinMode(Aiguillage[i].pinDirect, OUTPUT);
    pinMode(Aiguillage[i].pinDevie, OUTPUT);
    /* ====================================== */
    
    /* Lecture de la dernière position depuis l'EEPROM */
    byte valeurStockee = (EEPROM.read((i + 1) * 10) << 8) | (EEPROM.read(((i + 1) * 10) + 1) & 0xFF);
    if (valeurStockee == DIRECT || valeurStockee == DEVIE) {
      // Vérification la validité de l'état initial de l'aiguillage
      Aiguillage[i].DernierePosition = static_cast(valeurStockee);
    } else {
      // Valeur invalide, on positionne à DIRECT par déaut
      Aiguillage[i].DernierePosition = DIRECT;
      EEPROM.update((i + 1) * 10, static_cast(Aiguillage[i].DernierePosition) >> 8);          // Octet de poids fort
      EEPROM.update(((i + 1) * 10) + 1, static_cast(Aiguillage[i].DernierePosition) & 0xFF);  // Octet de poids faible
    } // Fin de if (valeurStockee == DIRECT || valeurStockee == DEVIE)
    /* ============================================== */
    
    mettreAJourAiguillage(i);   
  } // Fin de for (int i = 0; i < Nb_Aiguillages; i++)
 
  /* configuration DCC */
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);  
  DCC.SetupDecoder( 0x00, 0x00, digitalPinToInterrupt(pinInterruptionDCC));
  /* ================= */
} // Fin de setup()

void loop() {
  DCC.loop();
  BPclavier[CompteurLoop].update();
  BP_Valid.update();
  
  if (BPclavier[CompteurLoop].changed() && BPclavier[CompteurLoop].fell()){
    /* Bouton appuyé, basculer l'état de l'aiguillage */
    Aiguillage[CompteurLoop].DernierePosition = (Aiguillage[CompteurLoop].DernierePosition == DIRECT) ? DEVIE : DIRECT;   
    /* Mettre à jour physiquement l'aiguillage et gérer les leds*/
    mettreAJourAiguillage(CompteurLoop);
  } // Fin de if (BPclavier[CompteurLoop].changed() && BPclavier[CompteurLoop].fell())
  
  if (analogRead(pinPoussoirPlus) < limiteAnalogique) {
    if ((millis() - dernierAppel_BP_Plus) > dureeAntiRebond) {
      // Si le bouton Plus est stable depuis suffisamment de temps, on change l'état
      if (dernierEtat_BP_Plus == HIGH) {
        adresseDCCDepart += 1; 
        if (adresseDCCDepart >= 254) {adresseDCCDepart = 1;} 
        //Serial.print(F("Adresse DCC de depart : ")); Serial.println(adresseDCCDepart);
      } // Fin de if (dernierEtat_BP_Plus == HIGH)
      dernierEtat_BP_Plus = LOW;
    } // Fin de if ((millis() - dernierAppel_BP_Plus) > dureeAntiRebond)
    dernierAppel_BP_Plus = millis();
  } else {
    dernierEtat_BP_Plus = HIGH;
  } // Fin de if (analogRead(pinPoussoirPlus) < limiteAnalogique) 

  if (analogRead(pinPoussoirMoins) < limiteAnalogique) {
    if ((millis() - dernierAppel_BP_Moins) > dureeAntiRebond) {
      // Si le bouton Plus est stable depuis suffisamment de temps, on change l'état
      if (dernierEtat_BP_Moins == HIGH) {
        adresseDCCDepart -= 1; 
        if (adresseDCCDepart <= 0) {adresseDCCDepart = 254;}
        //Serial.print(F("Adresse DCC de depart : ")); Serial.println(adresseDCCDepart);
      } // Fin de if (dernierEtat_BP_Moins == HIGH)
      dernierEtat_BP_Moins = LOW;
    } // Fin de if ((millis() - dernierAppel_BP_Moins) > dureeAntiRebond)
    dernierAppel_BP_Moins = millis();
  } else {
    dernierEtat_BP_Moins = HIGH;
  } // Fin de if (analogRead(pinPoussoirMoins) < limiteAnalogique) 
  
  if (BP_Valid.changed() && BP_Valid.fell()){
    EEPROM.update(eepromAdresseDCCDepart, adresseDCCDepart >> 8);        // Octet de poids fort
    EEPROM.update(eepromAdresseDCCDepart + 1, adresseDCCDepart & 0xFF);  // Octet de poids faible 
    //Serial.print(F("Adresse DCC de depart : ")); Serial.print(adresseDCCDepart); Serial.println(F(" enregistree."));
  } // Fin de if (BP_Valid.changed() && BP_Valid.fell())
  
  CompteurLoop += 1; if (CompteurLoop >= Nb_Aiguillages) {CompteurLoop = 0;}
} // Fin de loop

void mettreAJourAiguillage(int indiceAiguillage) {
  //Serial.print(F("Aiguillage : "));Serial.print(indiceAiguillage); Serial.print(F(" - "));
  switch(Aiguillage[indiceAiguillage].DernierePosition) {
    case DIRECT:      
      //Serial.println(F("DIRECT"));
      digitalWrite(Aiguillage[indiceAiguillage].pinDirect, HIGH);
      delay(dureeImpulsion);
      digitalWrite(Aiguillage[indiceAiguillage].pinDirect, LOW);
      
      /* allumage des leds correspondantes */
      ecritRegistre((indiceAiguillage * 2), HIGH);
      ecritRegistre((indiceAiguillage * 2) + 1, LOW);
      /* ==================================*/
      break;
  
    case DEVIE:    
      //Serial.println(F("DEVIE"));   
      digitalWrite(Aiguillage[indiceAiguillage].pinDevie, HIGH);
      delay(dureeImpulsion);
      digitalWrite(Aiguillage[indiceAiguillage].pinDevie, LOW);
      /* allumage des leds correspondantes */
      ecritRegistre((indiceAiguillage * 2), LOW);
      ecritRegistre((indiceAiguillage * 2) + 1, HIGH); 
      /* ==================================*/ 
      break;
  } // Fin de switch(Aiguillage[indiceAiguillage].dernierEtat)

  // Sauvegarder le nouvel état dans l'EEPROM
  EEPROM.update((indiceAiguillage + 1) * 10, static_cast(Aiguillage[indiceAiguillage].DernierePosition) >> 8); // Octet de poids fort
  EEPROM.update(((indiceAiguillage + 1) * 10) + 1, static_cast(Aiguillage[indiceAiguillage].DernierePosition) & 0xFF); // Octet de poids faible
} // Fin de procédure mettreAJourAiguillage()

void clearRegisters(){  
  /* Place tous les pins du 74HC595 à l'état "OFF" */
  for (int i = numOfRegisterPins - 1; i >=  0; i--){
    Registres[i] = LOW;
  } // Fin de for
} // Fin de procédure clearRegisters()

void ecritRegistre(int index, int value){
  /* Enregistrer et afficher les valeurs dans le registre. A n'executer que APRES que toutes les valeurs aient été programmées. */
  digitalWrite(verrou_Pin, LOW);
    
  int i = numOfRegisterPins;
  Registres[index] = value;
  while( i-- ){
    digitalWrite(horloge_Pin, LOW);
    digitalWrite(data_Pin, Registres[i]);
    digitalWrite(horloge_Pin, HIGH);
  } // Fin de while
    
  digitalWrite(verrou_Pin, HIGH);
} // Fin de procédure ecritRegistre(int index, int value)

void BasicAccDecoderPacket_Handler(int adresseDecode, boolean activate, byte data) {  
  Serial.println(F("Appel ISR OK ")); // Debug
  
  #ifndef Sprog3ON
  /* Les lignes suivantes ne sont pas utilisées avec la centrale Sprog3 ligne 57 commentée */  
    adresseDecode -= 1; 
    adresseDecode *= 4; 
    adresseDecode += 1; 
    adresseDecode += (data & 0x06) >> 1;    // DCC address decoding 
    /* ============================================ */
  #endif

  /* A décommenter pour la z21 seulement si la norme RCN 213 n'est pas activée dans la centrale */
  //adresseDecode += 4;  
  /* ============================================================================ */
  
  //Serial.print(F("Adresse : "));Serial.print(adresseDecode); Serial.print(F(" / ")); Serial.println(adresseDCCDepart);
  
  if ((adresseDecode >= adresseDCCDepart) && (adresseDecode <= adresseDCCDepart + Nb_Aiguillages)){
    //Serial.print(F("Adresse decodee entre ")); Serial.print(adresseDCCDepart); 
    //Serial.print(F(" et ")); Serial.println (adresseDCCDepart + Nb_Aiguillages);
    /* Basculer l'état de l'aiguillage */
    Aiguillage[adresseDecode - adresseDCCDepart].DernierePosition = (Aiguillage[adresseDecode - adresseDCCDepart].DernierePosition == DIRECT) ? DEVIE : DIRECT;   
    /* Mettre à jour physiquement l'aiguillage et gérer les leds*/
    mettreAJourAiguillage(adresseDecode - adresseDCCDepart);  
  } // Fin de if ((adresseDecode >= adresseDCCDepart) && (adresseDecode <= adresseDCCDepart + Nb_Aiguillages)) 
} // Fin de procédure BasicAccDecoderPacket_Handler(int adresseDecode, boolean activate, byte data)

Publié le : Dimanche 23 juin 2024 @ 07:39:08
Article du Jour
Il n'y a pas encore d'article du jour.
Lettre d'information

Recevez par mail les nouveautés du site.

Chat Box
Activité du Site

Pages vues depuis 15/01/2020 : 499 318

  • Nb. de membres 7
  • Nb. d'articles 120
  • Nb. de forums 0
  • Nb. de sujets 45
  • Nb. de critiques 0

Top 5  Statistiques


Plus de contenu