Voir les contributions

Cette section vous permet de consulter les contributions (messages, sujets et fichiers joints) d'un utilisateur. Vous ne pourrez voir que les contributions des zones auxquelles vous avez accès.


Messages - lebelge2

Pages: [1] 2 3
1
Bonjour.
Noter que le code ci-dessus peut-être transcrit dans la librairie « La Box » pour compatibilité RailCom.
Il faudra quand même  une légère modification matériel.


2
Le logiciel DCC++ / Logiciel DCC BaseStation avec fonction RailCom
« le: mai 09, 2024, 02:08:47 pm »
Bonjour.

J’ai modifié légèrement ce logiciel pour qu’il insère un CutOut  à la fin des trames.
Donc maintenant compatible RailCom.

Fonctionne sur Mega et Uno.

Dans DCCpp_Uno, chercher l’interruption :  ISR(TIMER1_COMPB_vect)  (Ligne 457)
Remplacer la par le code  ci-dessous.

///////////////////////////////////////////////////////////////////////////////
// NOW USE THE ABOVE MACRO TO CREATE THE CODE FOR EACH INTERRUPT

/* Suivant votre configuration matériel, modifier les Ports et Pins
 *  Dans cet example, L298N et L6203 entrées, IN1=>PB5 =>11.  IN2=>PB7=>13 (Mega)
 *  LMD18200 entrée DIR=>PB6=>12.  Brake=>PB4=>10 (Mega)
 *  Ne pas omettre les Pins en sorties.
*/
bool EndBit;
bool CutOut;
ISR(TIMER1_COMPB_vect) {
  if (CutOut == false) {
    PORTB = PORTB | B10000000;               // PB7 IN1 niveau haut
    PORTB = PORTB &= ~ B00100000;            // PB5 IN2 niveau bas
  } else                                     // CutOut:
    PORTB = PORTB | B10110000;               // IN1, IN2 et Brake (PB4)niveau haut
  DCC_SIGNAL(mainRegs, 1);                   // Vers chargement du timer1
  if (mainRegs.currentBit == 2) {            // Fin Bit Stop
    OCR1B = 450;                             // Le Bit suivant aura un niveau bas de 30µs,
    OCR1A = 7107;                            // puis un niveau haut de 418µs.
    EndBit = true;                           // Validation
  }
}

ISR(TIMER1_COMPA_vect) {
  PORTB = PORTB &= ~ B10000000;              // PB7 IN1 niveau bas
  PORTB = PORTB | B00100000;                 // PB5 IN2 niveau haut
  if (CutOut == true) {
    PORTB = PORTB &= ~ B10110000;            // Fin CutOut, pins IN1, IN2, Brake (PB4) niveaux bas
    EndBit = false;
    CutOut = false;
  }
  if (EndBit == true)
    CutOut = true;
}

Il faut activer la nouvelle interruption. (ISR(TIMER1_COMPA_vect))
A la ligne 309, écrivez :   bitSet(TIMSK1,OCIE1A);   

Testé avec Mega, Uno et L298N, doit fonctionner avec L6203
Je viens de recevoir un LMD18200 mais il est défectueux, pas testé

Bien à vous.



3
Bonjour.

J’ai modifié légèrement ce logiciel pour qu’il insère un CutOut  à la fin des trames.
Donc maintenant compatible RailCom.

Fonctionne sur Mega et Uno.

Restrictions :

Pour le Mega; Dans MotorDriver.h  la Pin 9 est imposée.
    ex: new MotorDriver(7, 9, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN),
Pour l'Uno; Dans MotorDriver.h  la Pin 12 est imposée.
    ex: new MotorDriver(7, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN),

Trois nouvelles sorties pour les signaux (Out1, Out2, CutOut/Brake) sur PC0, PC1, PC2
 (sur Mega 35 36 37, Uno A0 A1 A2)
Bien entendu que toutes les sorties d’origines fonctionnent toujours mais sans CutOut.
Le code est extrêmement simple, les bidouilleurs pourront modifier toutes les sorties.

La modification logiciel :

Tout ce passe dans l’interruption du Timer1 :ISR(TIMER1_OVF_vect)   dans DCCTimerAVR.cpp
Il faut la remplacer par le code que je propose ci-dessous avec les défines et variables.

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)  // MEGA
#define PINx   PINH             // Pin numéro 9 sur Mega (PH6)     
#define PinIn  6                // new MotorDriver(7, 9, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN),
#define PORTx  PORTC            // Pin de sorties des signaux Out1, Out2, Brake/CutOut sur port C
#define Etat1  B00000100        // -_-_-_   Direct   Pin 35  (In1 pour type L298N, L6203, Dir pour type LMD18200)
#define Etat2  B00000010        // _-_-_-   Inversé  Pin 36  (In2 pour type L298N, L6203, Dir pour type LMD18200)
#define CutOut_ON  B00000111    // __----__          Pin 37  (BraKe Pour Type LMD08200)
#define CutOut_OFF B00000000    // ________
#else                                                           // UNO
#define PINx  PINB              // Pin numéro 12 sur Uno (PB4)
#define PinIn  4                // new MotorDriver(7, 12, UNUSED_PIN, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN),
#define PORTx  PORTC
#define Etat1  B00000100
#define Etat2  B00000010
#define CutOut_ON  B00000111
#define CutOut_OFF B00000000
#endif

int i;
int temps;
int oldtemps;
int bitt;
uint8_t bitCount;
uint8_t DccBitVal;
volatile uint8_t dccrecState;
ISR(TIMER1_OVF_vect) {     // ISR called by timer interrupt every 58uS
  temps = (bitRead(PINx, PinIn));
  if (temps == 1)
    PORTx = Etat1;
  else
    PORTx = Etat2;
  interruptHandler();
 temps = (bitRead(PINx, PinIn));
  i++;
  if ((i % 2) == 0) {
    if (temps != oldtemps) {
      bitt += 1;
      DccBitVal = 0;
    }
    else {
      bitt += 2;
      DccBitVal = 1;
    }
    oldtemps = temps;
    if (bitt > 1) {
      bitt = 0;
      bitCount++;
      switch (dccrecState) {
        case 0:
          if (DccBitVal) {
            if (bitCount >= 10)
              dccrecState = 1;
          }
          else {
            bitCount = 0;
          }
          break;
        case  1:
          if (!DccBitVal ) {
            dccrecState = 2;
            bitCount = 0;
          }
          break;
        case 2:
          if (bitCount == 8 ) {
            dccrecState = 3;
          }
          break;
        case 3:
          if ( DccBitVal ) {
            dccrecState = 4;
          }
          else
            dccrecState = 2;
          bitCount = 0;
          break;
        case 4:
          dccrecState = 0;
          PORTx = CutOut_ON;
          delayMicroseconds(420);
          PORTx = CutOut_OFF;
      }
    }
  }
}


Dans le void setup()   (CommandStation-EX), placer le code ci-dessous.

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)  // MEGA
  pinMode(35, OUTPUT);         // OUT 1  PC0
  pinMode(36, OUTPUT);         // OUT 2  PC1
  pinMode(37, OUTPUT);         // BRAKE  PC2
#else                                                           // UNO
  pinMode(A2, OUTPUT);         // OUT 1  PC0
  pinMode(A1, OUTPUT);         // OUT 2  PC1
  pinMode(A0, OUTPUT);         // BRAKE  PC2
#endif

Testé avec Mega, Uno et L298N, doit fonctionner avec L6203
Je viens de recevoir un LMD18200 mais il est défectueux, donc rien testé

Cablage :
Mega  =======> Bridge  Driver                 
    35  =======> In1  (Dir pour type LMD18200)
    36  =======> In2
    37  =======> Brake, seulement pour type LMD18200

  Uno  =======> Bridge  Driver                 
    A2  =======> In1  (Dir pour type LMD18200)
    A1  =======> In2
    A0  =======> Brake, seulement pour type LMD18200

Bien à vous.

4
Vos projets / Re : centrale DCC / analogique modulaire
« le: mai 03, 2024, 03:54:24 pm »
Oui, pour le montage des composants, il y a un supplément de 23 € par face, donc 46 € pour un double face (plus les composants)

5
Vos projets / Re : centrale DCC / analogique modulaire
« le: mai 02, 2024, 07:29:48 pm »
Bonjour.

Assemblage PCB:

Juste pour vous informer que je  viens de faire une simulation pour un double face et les prix ont fortement augmenté chez JLCPCB.
Pour ma part, je ne ferai plus que des simples faces....
Alors pour un quatre couches……

6
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 30, 2024, 04:21:19 pm »
Arduino Mega et  Commande/Base Station.

Petite carte shield dotée seulement d’un Attiny85.
Insère la découpe RailCom dans la trame Dcc.

Signaux disponibles sur trois broches pour piloter tout type de Bridge Driver.

Fabriquée de façon artisanale mais suivant demande, je pourrais dessiner puis publier les fichiers Gerber/Kicad.

Bien à vous.

7
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 30, 2024, 12:22:48 am »
BobyAndCo

Je crois avoir trouvé ton problème avec tes Attiny.
Le programme est fait pour mes Attiny que je programme avec une interface USB virtuelle et à 16,5 Mhz.

Je suppose que tu les programmes à  8 Mhz  avec un programmateur ordinaire, alors il
faut changer 2 paramètres :

TCCR1 à 3 au lieu de 4
TCNT1 à 102 au lieu de 112           (à 2 endroits)

J’ai fait ces modif et ça marche

8
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 29, 2024, 11:23:36 am »
Bonjour, ton cablage est correct.
Avec le L928N j'ai aussi parfois des très mauvaises mesures hors normes, je n'ais pas encore trouvé pourquoi, comportement étrange du module...
Je pense que à la sortie du nano, les signaux sont parfaits, c'est le module qui pose problème.
Pour en être certain, j'ai ajouter un test de diagnostique au programme.
Avec le moniteur série, il permet de faire des mesures et modifier les paramètres relatif au CutOut, test en cours...

9
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 28, 2024, 06:11:25 pm »
BodyAndCo
Avec Mon Attiny85, ça fonctionne très bien, j’ai ajusté les tempos.
Dans la void CutOut()
Remplacer le delayMicroseconds(38) par 36 et le delayMicroseconds(20)  par 24
On peut ajuster précisément les signaux, si ça ne vas pas, je ne sais quoi te dire.
On pourrait modifier ces valeurs via le moniteur série en temps réel.

Laurent
On pourrait aisément intégrer un SECURITY GAP 4µs avant et après le CutOut avec Enable à l’état bas.
Le LMD18200 n’a pas de broche Enable, il faut mettre le PWM bas et Brake haut.
Voir les Datasheet.
Le LN298N a une broche Enable.

Bien à vous.

10
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 28, 2024, 01:33:36 pm »
Pour les possesseurs de La Box qui souhaitent la fonction RailCom.
Une légère modification est possible :
Enlever Q1, R1, R2 et couper une piste.
Placer en « volant » un Attiny85 avec le soft.

N’ayant pas La Box, je ne sais pas aider plus.

Aliexpress Attiny85

https://fr.aliexpress.com/item/2043055746.html



11
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 28, 2024, 12:18:35 am »
BobyAndCo

Avec exactement le même matériel que toi, ça marche chez moi.
Mega2560 ==> Uno ==>  L298N

J’ai mis ta configuration pin :
 new MotorDriver(7, 6, 5, UNUSED_PIN, A0, 2.99, 2000, UNUSED_PIN), \

Pin 5 et 6 fonctionnent.

Attention que dans cette version (V.1.1)
Entrée Dcc      Pin 2  (Sur Uno)
Out1              Pin 3
Out2              Pin 4

Le cablage:
MEGA 5 ou 6 -------> UNO 2
MEGA 7 ------------> L298 EN1
UNO 3 -------------> L298 IN2
UNO 4 -------------> L298 IN1

Décodeur Loco: ESU standard
Il faudra certainement ajuster les tempos dans: void CutOut()

12
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 27, 2024, 08:23:51 pm »
Bonjour.

Ci joint le soft avec un correctif pour décoder les trames inversées.
Fonctionne aussi avec un Attiny85 en version bêta.

Attention changement des Pins pour compatibilité avec l’Attiny
     2   Entrée Dcc
     3   Sortie vers IN1  (ou Dir     pour LMD18200)
     4   Sortie vers IN2  (ou Brake pour LMD18200)

Prévu pour LMD18200 mais rien testé, j’attends la réception de ce module.
Ligne n° 10:       //#define LMD18200

Bien à vous.

// RailCom: Programme pour insérer un CutOut dans les trames DCC.  Arduino Uno, Nano, Micro.  Attiny85.(Betâ)
//
// V.1.0.   24-04-24  Testé avec Bridge Driver L6203 et L298N
// V.1.1.   27-04-24  Upgrade pour Attiny85 et polarité inverse.
//
// lebelge2@yahoo.fr
//--------------------------------- Sélectionné votre  Hardware Bridge Driver------------------------------------
#define L298N           // L6203
//#define LMD18200
//----------------------------------------------------------------------------------------------
volatile uint8_t dccrecState;
volatile uint8_t tempByte;
bool PolariteDcc = true;
bool Brake;
unsigned long currentTime = 0;
unsigned long previousTime = 0;
unsigned long Temps;
#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 value

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;
//---------------------------------------------- SetUp -------------------------------------------------------
void setup() {
#ifdef LMD18200
  Brake = true;
#endif
#ifdef __AVR_ATmega328P__                    // --- Arduino AVR ---
#define PORTx PORTD                          // PORTD
  Serial.begin(250000);
  init_timer2();                             // Timer 2
#elif ARDUINO_AVR_ATTINYX5                   // --- ATTINY CORE ATTINY85 ---  (Micronucleus DigiSpark)
#define PORTx PORTB                          // PORTB
  init_timer1();                             // Timer 1
#else
#error "Unsupported CPU, you need to add another configuration section for your CPU"
#endif
#define PinIn 2                               // Entrée trames Dcc sans CutOut
#define PinOut1 3                             // Sortie trames DCC avec CutOut           (LMD18200: Dir (sans CutOut))
#define PinOut2 4                             // Sortie trames DCC inversées avec CutOut (LMD18200: Brake (uniquement CutOut))
  pinMode(PinIn, INPUT);
  pinMode(PinOut1, OUTPUT);
  pinMode(PinOut2, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(PinIn), Dcc_Interrupt, CHANGE );
  dccIn.port = digitalPinToPort(PinIn);
  dccIn.bit = digitalPinToBitMask(PinIn);
  dccIn.portRegister = portInputRegister(dccIn.port);
}
//--------------------------------------------- Loop --------------------------------------------------------
void loop() {}
//------------------------------------------- Attiny 85 -----------------------------------------------------------
#ifdef ARDUINO_AVR_ATTINYX5
void init_timer1(void) {
  noInterrupts();              // disable all interrupts
  TCCR1 = 0;                   // B0 à B3: diviseur par 1, 2, 4, 8
  TCNT1 = 102;                 // preload the timer
  TIMSK = 4;                   // the timer is used in overflow interrupt mode
  interrupts();                // enable all interrupts
}
//--------------------------------------------- AVR ---------------------------------------------------------
#elif __AVR_ATmega328P__
void init_timer2(void) {
  noInterrupts();              // disable all interrupts
  TCCR2A = 0;                  // should be zero for our purpose
  TCCR2B = 0;                  // 0 => timer is stopped
  TCNT2 = 102;                 // preload the timer
  TIMSK2 |= 1;                 // the timer is used in overflow interrupt mode
  interrupts();                // enable all interrupts
}
#endif
//----------------------------------------------------------------------------
void CutOut() {
  if (PolariteDcc == false) {        // Si DCC inversé,
    delayMicroseconds(38);           // retarder CutOut d'un demis-bit
    PORTx = PORTx | B00001000;
    PORTx = PORTx &= ~ B00010000;
    delayMicroseconds(20);
  }
  delayMicroseconds(8);
  PORTx = PORTx | B00010000;
  PORTx = PORTx | B00001000;
  delayMicroseconds(430);
  PORTx = PORTx &= ~ B00001000;
  PORTx = PORTx &= ~ B00010000;
}
//------------------------------------------ DCC Interrupt -------------------------------------------
void Dcc_Interrupt() {
#ifdef __AVR_ATmega328P__
  if ((bitRead(PIND, PinIn)) == 1) {                // bitRead en 3µs,    digitalRead en 7µs
    TCCR2B |= 2;                                    // Start Timer 2
#elif ARDUINO_AVR_ATTINYX5
  if ((bitRead(PINB, PinIn)) == 1) {
    TCCR1 |= 4;                                     // Start Timer 1
#endif
    if (Brake == false)
      PORTx = PORTx &= ~ B00010000;                 // Temps d'exécution de ces instructions:
    PORTx = PORTx | B00001000;                      // 0,125µs en ASM,    0,170µs en C,      6µs en C++
  }
  else {
    if (Brake == false)
      PORTx = PORTx | B00010000;
    PORTx = PORTx &= ~ B00001000;
  }
  if (dccrecState == WAIT_START_BIT)  {           // L'intervalle de temps après le préambule est évalué,
    Temps = micros();
    previousTime = Temps - currentTime;
    currentTime = Temps;                          // si l'écart entre le dernier et le premier zéro est de 116 µs,
    if (previousTime > 90)                        // alors le signal est reconnu dans la bonne phase.
      PolariteDcc = true;                         // Polarité correcte
    else
      PolariteDcc = false;                        // Polarité inversée
  }
}
//------------------------------------------- ISR Timers ----------------------------------------------------
#ifdef __AVR_ATmega328P__
ISR(TIMER2_OVF_vect) {
  TCCR2B = 0;                                    // 0 => timer is stopped
  TCNT2 = 102;                                   // preload the timer. Fr. 16Mhz
#elif ARDUINO_AVR_ATTINYX5
ISR(TIMER1_OVF_vect) {
  TCCR1 = 0;                                     // 0 => timer is stopped
  TCNT1 = 112;                                   // preload the timer.  Fr. 16,5Mhz
#endif
  uint8_t DccBitVal;
  DccBitVal = !(*dccIn.portRegister & dccIn.bit);
  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
  }
}

13
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 27, 2024, 12:54:01 pm »
Oui ce soir car je teste.

14
Vos projets / Re : RailCom: Générateur de CutOut
« le: avril 27, 2024, 12:46:36 pm »
Bonjour.

Au sujet des trames inversées. (2 fils)

La première via l’entrée  In1  commande la partie droite du pont.
La deuxième via l’entrée In2  commande la partie gauche.
En mettant In1 et In2 à l’état haut, les transistors du haut (gauche et droit) sont passant et provoquent un court-circuit nécessaire à la circulation des data RailCom
Méthode utilisée par les L6203, L928N et autres.

Pour le LMD18200, un fil suffit, car les signaux sont inversés dans le composant.
Un autre fil met le pont en court circuit comme dit plus haut.

Evolution du soft , maintenant accepte les deux polarités.
Fonctionne aussi avec un  Attiny85

Bien à vous.

Pages: [1] 2 3