Parlons Arduino > Vos projets

RailCom: Générateur de CutOut

(1/14) > >>

lebelge2:
Bonjour.
Certaines centrales DCC notamment les DIY ne sont pas compatibles RailCom car ne génèrent pas le CutOut.
Ce petit montage à base, seulement d’un Arduino Uno, Nano ou Micro s’insère entre la centrale et le Booster.
Il génère le CutOut  afin de la rendre compatible RailCom.
Testé sur un Booster L298N et L6203.
Si dessous, le code et le schéma.
Bien à vous.


--- Code: ---// RailCom: Programme pour insérer un CutOut dans les trames DCC.  Arduino Uno, Nano, Micro.
// Testé avec Bridge Driver L6203 et L298N
// V.1.0.   24-04-24
// lebelge2@yahoo.fr

volatile uint8_t dccrecState;
volatile uint8_t tempByte;
#define WAIT_PREAMBLE    0
#define WAIT_START_BIT   1
#define WAIT_DATA        2
#define WAIT_END_BIT     3
#define MaxDccSize 6                         // DCC messages can have a length upto this valu
#define PinIn1 3                             // Entrée signalDcc sans CutOut
#define PinOut1 4                            // Sortie signal DCC avec CutOut
#define PinOut2 5                            // Sortie signal DCC inversé avec CutOut

class DccMessage {
  public:
    volatile uint8_t size;
    volatile uint8_t data[MaxDccSize];        // The contents of the last dcc message received
} dccMessage;

struct {
  uint8_t bitCount;                           // Count number of preamble bits / if we have a byte
  volatile uint8_t tempMessage[MaxDccSize];   // Once we have a byte, we store it in the temp message
  volatile uint8_t tempMessageSize;           // Here we keep track of the size, including XOR
} dccrec;                                     // The received DCC message is assembled here

struct {
  uint8_t port;
  uint8_t bit;                                // Bitmask for reading the input Port
  volatile uint8_t *portRegister;
} dccIn;

void setup() {
  Serial.begin(9600);
  pinMode(PinIn1, INPUT);
  pinMode(PinOut1, OUTPUT);
  pinMode(PinOut2, OUTPUT);
  init_timer2();
  attachInterrupt(digitalPinToInterrupt(PinIn1), Dcc_Interrupt, CHANGE );
  dccIn.port = digitalPinToPort(PinIn1);
  dccIn.bit = digitalPinToBitMask(PinIn1);
  dccIn.portRegister = portInputRegister(dccIn.port);
  Serial.println ("SetUp OK");
}

void loop() {

}

void CutOut(void) {
  delayMicroseconds(8);
  asm("sbi 0x0B, 4");
  asm("sbi 0x0B, 5");
  delayMicroseconds(425);
  asm("cbi 0x0B, 4");
  asm("cbi 0x0B, 5");
}
//----------------------------------------------------------------------------------------------------------
void init_timer2(void) {
#define T2_PRESCALER   8
#define T2_PRESCALER_BITS   ((0<<CS02)|(1<<CS01)|(0<<CS00))
#define T77US (F_CPU * 77L / T2_PRESCALER / 1000000L)
#if (T77US > 254)
#warning T77US too big, use either larger prescaler or slower processor
#endif
#if (T77US < 32)
#warning T77US too small, use either smaller prescaler or faster processor
#endif
  noInterrupts();              // disable all interrupts
  TCCR2A = 0;                  // should be zero for our purpose
  TCCR2B = 0;                  // 0 => timer is stopped
  TCNT2 = 256L - T77US;        // preload the timer
  TIMSK2 |= (1 << TOIE2);      // the timer is used in overflow interrupt mode
  interrupts();                // enable all interrupts
}
//----------------------------------------------------------------------------------------
void Dcc_Interrupt() {
  if (digitalRead(PinIn1) == true) {
    asm("cbi 0x0B, 5");
    asm("sbi 0x0B, 4");
    TCCR2B |= (T2_PRESCALER_BITS);  // Start Timer 2
  }
  else {
    asm("cbi 0x0B, 4");
    asm("sbi 0x0B, 5");
  }
}
//-----------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) {
  uint8_t DccBitVal;
  DccBitVal = !(*dccIn.portRegister & dccIn.bit);
  TCCR2B = 0;                                    // 0 => timer is stopped
  TCNT2 = 256L - T77US;                          // preload the timer
  dccrec.bitCount++;
  switch (dccrecState) {
    case WAIT_PREAMBLE:
      if (DccBitVal) {                           // a "1" bit is received
        if (dccrec.bitCount >= 10)
          dccrecState = WAIT_START_BIT;
      }
      else
        dccrec.bitCount = 0;                     // not a valid preamble.
      break;
    case  WAIT_START_BIT:
      if ( !DccBitVal ) {                        // a "0" bit is received
        dccrecState = WAIT_DATA;
        dccrec.tempMessageSize = 0;
        uint8_t i;
        for (i = 0; i < MaxDccSize; i++ )
          dccrec.tempMessage[i] = 0;
        dccrec.bitCount = 0;
      }
      break;
    case WAIT_DATA:
      if ( dccrec.bitCount == 8 ) {                 // byte is complete
        if (dccrec.tempMessageSize == MaxDccSize ) { // Packet is too long - abort
          dccrecState = WAIT_PREAMBLE;
          dccrec.bitCount = 0;
        }
        else
          dccrecState = WAIT_END_BIT;              // Wait for next byte or end of packet
      }
      break;
    case WAIT_END_BIT:
      if ( DccBitVal ) {                           // End of packet?
        CutOut();
        dccrecState = WAIT_PREAMBLE;
      }
      else                                         // Get next Byte
        dccrecState = WAIT_DATA;
      dccrec.bitCount = 0;                         // prepare for the next byte
  }
}
--- Fin du code ---

trimarco232:
Bonjour,
encore une réalisation remarquable , bravo !

bobyAndCo:
Bonjour lebelge,

Je suis très intéressé et en même temps certaines choses m'étonnent.

Je comprends bien le principe adopté pour insérer le cutout à la place de certains bits du préambule. Mais encore faut il qu'il y ait assez de bits ! Si la centrale ne génère que 16 bits de préambule, ou 14 ? Avec une centrale en DIY, on peut générer le nombre de bits que l'on veut, mais une centrale du commerce ?

Par ailleurs, pour activer le transfert, il faut que le booster court-circuite la sortie pour que le décodeur envoie un courant dans la boucle ainsi créée. Or je ne vois pas comment tu réalises cela ici ? Avec un LMD18200 qui dispose d'une entrée BRAKE, c'est très simple. Sur un L603 je crois que l'on peut le faire avec la pin ENABLE1 et  ENABLE1 (mais je ne vois pas cela dans ton montage). Et avec un L298N ?

Merci pour tes réponses.

Christophe

CATPLUS:
Bonjour LeBelge

Trés intéressé et voir plus, un autre ami est sur le même projet (en cours de mise au point). Pour le soft (je me garderais bien de faire une remarque, "Christophe est beaucoup plus compétent")
4 questions:
Sur le schéma, la sortie de la centrale a un seul fil via la broche "3" du Nano, la question où brancher le second fil de la centrale?
Les centrales ont 2 bornes de sorties "J & K" merci de nous donner les branchements.
En cas de court-circuit, comment réagi le montage?
Une  centrale réglée pour 4 voir plus ampères, garde-t-on la puissance?

Je soupçonne que vous avez tester votre montage, auriez-vous une photo ou vidéo

Merci pour votre réponse

Marcel

trimarco232:

--- Citation de: bobyAndCo le avril 24, 2024, 11:54:39 pm ---(...) on peut générer le nombre de bits que l'on veut, mais une centrale du commerce ?

--- Fin de citation ---
je me permets de répondre , en fonction de ce que j'ai cru comprendre)
avec une centrale du commerce , il faut connaître le preamble pour savoir si c'est compatible (vous noterez le niveau de réflexion) ; en général , c'est compatible , si non c'est sniffer + scheduler , pas la même approche

--- Citer ---on peut le faire avec la pin ENABLE1 et  ENABLE1 (mais je ne vois pas cela dans ton montage). Et avec un L298N ?
(...)

--- Fin de citation ---
en l'état , c'est prévu pour un IC pont en H classique , cad. 1/0 = 1/0  ,  0/1 = 0/1 et , pour le cutout , 1/1 = 0/0
pour des IC ou des shields avec une entrée brake dédiée , il faut adapter/compléter le soft

Navigation

[0] Index des messages

[#] Page suivante

Utiliser la version classique