Table de commande pour 6 locomotives (ou plus)

C’est une très bonne question. Il y a au début du programme un tableau à renseigner avec les adresses des locomotives

uint16_t t_address[NB_LOCO] = { 1, 3, 4, 5, 9, 10 }

Ce sont les “loc ID” selon le terme de Marklin, celles qui sont attribuées après reconnaissance MFX.

Elle sont attribuées les une à la suite des autres souvent à partir de 1. Si l’on ne dispose pas de ces “loc ID”, il faut aller un peu à taton, Tester si une loco répond sur le potar 1 puis 2 puis 3 etc…

Les locID ne changent que très rarement ensuite. Principalement quand une nouvelle loco est posée sur les rail qui possède le même locID, mais c’est rare sauf dans les clubs.

Sinon, j’ai écrit un petit programme qui permet d’attribuer les locID que l’on souhaite à une loco, je le fournirai pour ceux qui le souhaitent.

Christophe

2 « J'aime »

Est-ce que l’on peut voir le programme ?
S’il te plaît !
Alain

Oui mais je dois faire le ménage et il faut aussi que je mette un debonce sur l’interrupteur de sens, ce sera plus propre.

Le voila donc en l’état, il fonctionne mais il sera amélioré.

Le premier potar doit être branché sur A0, le second A1 etc…

La bibliothèque nécessaire est téléchargeable ici GitHub - pierremolinaro/acan2515: MCP2515 CAN Controller Driver for Arduino

ou mieux, avec l’IDE Arduino outils → gerer les bibliothèques → rechercher ACAN2515


#include <ACAN2515.h>

//——————————————————————————————————————————————————————————————————————————————
//  MCP2515 connections:
//    - standard SPI pins for SCK, MOSI and MISO
//    - a digital output for CS
//    - interrupt input pin for INT
//——————————————————————————————————————————————————————————————————————————————
// If you use CAN-BUS shield (http://wiki.seeedstudio.com/CAN-BUS_Shield_V2.0/) with Arduino Uno,
// use B connections for MISO, MOSI, SCK, #9 or #10 for CS (as you want),
// #2 or #3 for INT (as you want).
//——————————————————————————————————————————————————————————————————————————————
// Error codes and possible causes:
//    In case you see "Configuration error 0x1", the Arduino doesn't communicate
//       with the 2515. You will get this error if there is no CAN shield or if
//       the CS pin is incorrect.
//    In case you see success up to "Sent: 17" and from then on "Send failure":
//       There is a problem with the interrupt. Check if correct pin is configured
//——————————————————————————————————————————————————————————————————————————————

/************************ ACAN *****************************/
// If you use CAN-BUS shield (http://wiki.seeedstudio.com/CAN-BUS_Shield_V2.0/) with Arduino Uno,
// use B connections for MISO, MOSI, SCK, #9 or #10 for CS (as you want),
// #2 or #3 for INT (as you want).
#include <ACAN2515.h>
static const byte MCP2515_CS = 10;  // CS input of MCP2515 (adapt to your design)
static const byte MCP2515_INT = 2;  // INT output of MCP2515 (adapt to your design)

//——————————————————————————————————————————————————————————————————————————————
//  MCP2515 Driver object
//——————————————————————————————————————————————————————————————————————————————

ACAN2515 can(MCP2515_CS, SPI, MCP2515_INT);

//——————————————————————————————————————————————————————————————————————————————
//  MCP2515 Quartz: adapt to your design
//——————————————————————————————————————————————————————————————————————————————

static const uint32_t QUARTZ_FREQUENCY = 16UL * 1000UL * 1000UL;  // 16 MHz


class Loco {
private:
  uint16_t m_address;
  uint16_t m_speed;
  uint16_t m_oldSpeed;
  byte m_direction;
  byte m_oldDirection;
  byte m_speedPin;
  byte m_dirPin;
public:
  uint16_t speed() {
    m_speed = analogRead(this->m_speedPin);
    m_speed = map(m_speed, 0, 1023, 0, 100);
    m_speed *= 10;
    return m_speed;
  }
  void speed(uint16_t o) {
    m_speed = o;
  }
  uint16_t oldSpeed() {
    return m_oldSpeed;
  }
  void oldSpeed(uint16_t os) {
    m_oldSpeed = os;
  }
  byte direction() {
    if (digitalRead(m_dirPin)) {
      m_direction = 1;  // Avant
      //Serial.println(m_direction);
      return 1;
    } else {
      m_direction = 2;  // Arrière
      //Serial.println(m_direction);
      return 2;
    }
    //   Serial.println(m_direction);
    // return m_direction;
  }
  void direction(byte d) {
    m_direction = d;
  }
  void oldDirection(byte od) {
    m_oldDirection = od;
  }
  byte oldDirection() {
    return m_oldDirection;
  }
  void speedPin(byte ap) {
    m_speedPin = ap;
  }
  byte speedPin() {
    return m_speedPin;
  }
  void dirdPin(byte dp) {
    m_dirPin = dp;
  }
  byte dirdPin() {
    return m_dirPin;
  }
  void address(uint16_t ad) {
    m_address = ad;
  }
  uint16_t address() {
    return m_address;
  }
};

const uint8_t NB_LOCO = 6;
Loco loco[NB_LOCO];

uint16_t t_address[NB_LOCO] = { 1, 2, 3, 4, 5, 6 };
byte t_speedPin[NB_LOCO] = { A0, A1, A2, A3, A4, A5 };
byte t_dirPin[NB_LOCO] = { 3, 4, 5, 6, 7, 8 };




//——————————————————————————————————————————————————————————————————————————————
//   SETUP
//——————————————————————————————————————————————————————————————————————————————

void setup() {
  ;
  //--- Start serial
  Serial.begin(115200);
  //--- Wait for serial (blink led at 10 Hz during waiting)
  while (!Serial)
    delay(50);

  //--- Begin SPI
  SPI.begin();
  //--- Configure ACAN2515
  Serial.println("Configure ACAN2515");
  ACAN2515Settings settings(QUARTZ_FREQUENCY, 250UL * 1000UL);  // CAN bit rate 250 kb/s
  //settings.mRequestedMode = ACAN2515Settings::LoopBackMode ; // Select loopback mode
  const uint16_t errorCode = can.begin(settings, [] {
    can.isr();
  });

  if (errorCode == 0) {
    Serial.print("Bit Rate prescaler: ");
    Serial.println(settings.mBitRatePrescaler);
    Serial.print("Propagation Segment: ");
    Serial.println(settings.mPropagationSegment);
    Serial.print("Phase segment 1: ");
    Serial.println(settings.mPhaseSegment1);
    Serial.print("Phase segment 2: ");
    Serial.println(settings.mPhaseSegment2);
    Serial.print("SJW: ");
    Serial.println(settings.mSJW);
    Serial.print("Triple Sampling: ");
    Serial.println(settings.mTripleSampling ? "yes" : "no");
    Serial.print("Actual bit rate: ");
    Serial.print(settings.actualBitRate());
    Serial.println(" bit/s");
    Serial.print("Exact bit rate ? ");
    Serial.println(settings.exactBitRate() ? "yes" : "no");
    Serial.print("Sample point: ");
    Serial.print(settings.samplePointFromBitStart());
    Serial.println("%");
  } else {
    Serial.print("Configuration error 0x");
    Serial.println(errorCode, HEX);
  }

  for (byte i = 0; i < NB_LOCO; i++) {
    loco[i].speedPin(t_speedPin[i]);
    loco[i].dirdPin(t_dirPin[i]);
    pinMode(loco[i].dirdPin(), INPUT_PULLUP);
    loco[i].address(t_address[i]);
  }
}





void loop() {
  CANMessage frame;
  frame.ext = 1;
  frame.id &= ~0xFFFF;
  frame.id |= 0x1813;  // hash

  for (byte i = 0; i < NB_LOCO; i++) {
    frame.data[2] = (loco[i].address() & 0xFF00) >> 8;
    frame.data[3] = loco[i].address() & 0x00FF;

    uint16_t speed = loco[i].speed();
    if (speed != loco[i].oldSpeed()) {
      Serial.println(speed);
      frame.id |= 0x80000;  // commande vitesse
      frame.len = 6;
      frame.data[4] = (speed & 0xFF00) >> 8;
      frame.data[5] = speed & 0x00FF;
      if (can.tryToSend(frame))
        Serial.println("sent");
      else
        Serial.println("echec");
      loco[i].oldSpeed(speed);
    }

    byte direction = loco[i].direction();
    if (direction != loco[i].oldDirection()) {
      Serial.println(direction);
      frame.id |= 0xA0000;  // commande direction
      frame.len = 5;
      frame.data[4] = direction;
      if (can.tryToSend(frame))
        Serial.println("sent");
      else
        Serial.println("echec");
      loco[i].oldDirection(direction);
    }
  }
}

//——————————————————————————————————————————————————————————————————————————————

2 « J'aime »

OK, Merci Christophe.
Je vais pouvoir l’étudier cette semaine. A première vue, le voidloop() est très court, donc facile.

Bon et bien j’achète les potentiomètres 4,7k linéaires et rectilignes.

Et c’est parti.

Alain

Téléversement OK, avec la bibliothèque de pierre Molinaro :

A suivre…
Cordialement.
Alain

Ah cool.

Tu peux faire un test même si tu n’as pas les potentiomètres.

Tu envoies du 5 volts (pris sur l’Arduino) dans l’une des broches A0, A1,A2 etc jusqu’à A5.

Ca revient à un potar au max. Faire gaffe car la loco peut partir à fond dans un sens ou l’autre.

Christophe

1 « J'aime »

Je viens de commander des Potar 10K chez Conrad car chez Gotronic , ils n’ont pas de rectilignes. Je les aurais à la fin de la semaine.

As tu fait un bout de schéma, même sommaire ?

Je vais faire le test que tu indique, le temps de faire un câblage minimaliste avec mes petits câbles Dupont.
Alain

1 « J'aime »

Cher Alain,

Un grand merci de te lancer dans cette aventure. Je vais attendre que tu essuie les plâtres, comme on dit, mais connaissant Christophe, il ne doit pas y avoir beaucoup de petites imperfections :wink:

Après je passerai a la réalisation, en ayant auparavant consulter téléphoniquement l’auteur de génie… :star_struck:

Phil,

Pas de souci Philippe.
Alain

Bon pour l’instant cela ne fonctionne pas.
Voici une photo du montage :

On voit les deux CAN-L et CAN-H raccordé suivant le plan; Le fil (+5v) en l’air; la BR24 sur la voie (première Mfx à priori ?) et la prise CAN raccordée à la MS2 qui ne possède qu’un seul enregistrement (à priori ?); l’Arduino étant alimenté par le PC.

Le moniteur série indique :
moniteur-serie-01

Si j’actionne la fonction son ou bien l’avance sur la MS2, la led RX du shield clignote. Par contre si je commute le +5v sur une des entrées A0 … A5, le TX du shield ne réagit pas.

Est-ce qu’il n’y a pas une configuration hardware du SPI à faire ? Ci-dessous, la face arrière du shield :
back

Ci-joint , le PDF du schéma; j’ai bien peur que je doive réaliser six points de soudure. A confirmer, car cela signifie que le CAN est alimenté mais autonome s’il ne communique pas avec l’Arduino ? :
CAN-BUS Shield v2.0.pdf (68,0 Ko)

Je suis presque certain que le SPI doit être raccordé au Canal A ou B par les soudures à faire.
SPI
Bon, je crois que je ne ferai pas plus ce soir. Je vais laisser passer la nuit.
Quelles sont les sources d’erreurs les plus probables selon toi?

Alain

Faudrait voir dans la notice …

Bon, il fallait bien que je déride un instant cette situation embarrassante, petit humour gratuit.

Amicalement,
Vincent

2 « J'aime »

Alain a du faire une connerie…

small.dinerdecons_boulette.gif.be8a67056608c5c6638fdc877afbf219

Christophe a dit: Le fil rouge sur le bouton rouge, et le fil vert sur le bouton vert.
Pour les potards, tu te démerde… :joy:

2 « J'aime »

Et dis donc , Me V’la bien ! :slight_smile:

2 « J'aime »

En supposant que j’en n’ai fait qu’une …

2 « J'aime »

J’appelle un plâtrier pour t’aider :rofl:

Oui, mais lui il ne va que boucher des trous …

“echec” dans le moniteur veut dire que tu as un problème de liaison CAN.

Sur ces shield que tu montre par dessous, il y a des liaison à souder. Je n’ai pas beaucoup de temps à l’instant mais si tu ne trouves pas de ton côté, je te donnerais ça ce soir.

Dans le programme CS et INT sont programmés comme ceci :

static const byte MCP2515_CS = 10;  // CS input of MCP2515 (adapt to your design)
static const byte MCP2515_INT = 2;  // INT output of MCP2515 (adapt to your design)

Il faut que tu réalises les bonne jonctions.

2 « J'aime »

C’est cela, mais j’allumerai le fer à souder demain.
Merci bien Christophe.
Bonne soirée.
Alain

1 « J'aime »

Il est trop fort ce Totof… :clap:

Oui, on trouve toujours son maître :

:slight_smile:

1 « J'aime »