Bon je viens de refaire des tests pendant 2 heures et tout fonctionne vraiment bien chez moi. J'ai fais le test avec 2 locos, une Roco avec adresse 3 et une Trix avec adresse 78 (Cette loco avec décodeur Trix génère le Railcom!!!).
Pas de problème de commande en CAN. J'utilise pour cela une MS2. On ne peut pas être plus CAN Marklin !
Pas de problème pour la lecture Railcom !
J'en ai profité pour apporter quelques nouvelles améliorations sur les fichiers CanMarklin (en particulier sur le filtre des messages). Les fichiers sont joints. Il faut juste remplacer les anciens par ceux-ci.
J'ai aussi réalisé un petit programme de test qui fonctionne sur un Arduino UNO avec un shield SEEED STUDIO relié à la Box bien sûr et qui pilote ma locomotive adresse 78 (qui allume laBox, envoie la loco en avant, arrière, changement de vitesse etc...)
Il suffit de mettre l'adresse de la loco que vous voulez piloter à la ligne 39 : const uint32_t addressLoco = 78; // Renseigner l'adresse de votre locomotive
Selon le module CAN que vous utilisez, assurez-vous des bonne pins pour CS et INT. Chez moi c'est :
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)
Voici le programme dans son ensemble :
#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
enum : bool {
off,
on
};
enum : uint8_t {
setPower,
setSpeed,
setDirection,
setfunction
};
struct Loco {
uint32_t address;
uint16_t speed;
uint8_t direction;
byte fn[28];
};
Loco *loco = new Loco;
const uint32_t addressLoco = 78; // Renseigner l'adresse de votre locomotive
class LaBoxCmd {
private:
uint32_t mID;
bool mDebug;
bool mPower;
public:
LaBoxCmd(uint32_t);
void setup();
void setPower(bool power) {
mPower = power;
}
bool getPower() {
return mPower;
}
};
LaBoxCmd::LaBoxCmd(uint32_t id)
: mID(id) {}
uint32_t thisId = 0x1811; // Identifiant de cet expéditeur
LaBoxCmd laBox(thisId);
void canSendMsg(uint8_t commande, uint8_t function = 0) {
CANMessage frame;
frame.ext = true; // Utiliser un identifiant étendu
uint32_t ok;
frame.id = thisId; // Identifiant de la trame
switch (commande) {
case setPower:
frame.len = 5; // Nombre d'octets de data
frame.id |= (uint32_t)0x00 << 17;
frame.data32[0] = thisId;
frame.data[4] = laBox.getPower();
break;
case setSpeed:
frame.len = 6; // Nombre d'octets de data
frame.id |= (uint32_t)0x04 << 17;
frame.data32[0] = loco->address;
Serial.print("speed : ");
Serial.println(loco->speed);
frame.data[4] = (loco->speed & 0xFF00) >> 8;
frame.data[5] = loco->speed & 0x00FF;
//frame.data16[4] = loco->speed;
break;
case setDirection:
frame.len = 5; // Nombre d'octets de data
frame.id |= (uint32_t)0x05 << 17;
frame.data32[0] = loco->address;
frame.data[4] = loco->direction;
break;
case setfunction:
frame.len = 6; // Nombre d'octets de data
frame.id |= (uint32_t)0x06 << 17;
frame.data32[0] = loco->address;
frame.data[4] = function;
frame.data[5] = loco->fn[function];
break;
}
ok = can.tryToSend(frame);
if (ok)
Serial.println("envoi ok");
}
//——————————————————————————————————————————————————————————————————————————————
// SETUP
//——————————————————————————————————————————————————————————————————————————————
void setup() {
//--- Switch on builtin led
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
//--- Start serial
Serial.begin(115200);
//--- Wait for serial (blink led at 10 Hz during waiting)
while (!Serial) {
delay(50);
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
//--- Begin SPI
SPI.begin();
//--- Configure ACAN2515
Serial.println("Configure ACAN2515");
ACAN2515Settings settings(QUARTZ_FREQUENCY, 250UL * 1000UL); // CAN bit rate 250 kb/s
const uint16_t errorCode = can.begin(settings, [] {
can.isr();
});
if (errorCode == 0) {
Serial.print("Configuration CAN ok");
} else {
Serial.print("Configuration error 0x");
Serial.println(errorCode, HEX);
}
loco->address = addressLoco;
}
//——————————————————————————————————————————————————————————————————————————————
void loop() {
CANMessage frame;
// Power on
laBox.setPower(on);
canSendMsg(setPower);
delay(1000);
// Test des differentes fonctions du decodeur
// for (byte i = 0; i <= 28; i++) {
// // Activation
// loco->fn[i] = on;
// canSendMsg(setfunction, i);
// delay(1000);
// // Desactivation
// loco->fn[i] = off;
// canSendMsg(setfunction, i);
// delay(1000);
// }
loco->fn[0] = on;
canSendMsg(setfunction, 1);
delay(10);
loco->fn[1] = on;
canSendMsg(setfunction, 1);
delay(10);
// Vers l'avant
loco->direction = 1;
canSendMsg(setDirection);
delay(10);
loco->speed = 500; // 500 / 1000 = 50% de la vitesse max
canSendMsg(setSpeed);
delay(1000ul * 50ul);
loco->fn[2] = on;
canSendMsg(setfunction, 2);
delay(1000);
loco->fn[2] = off;
canSendMsg(setfunction, 2);
delay(10);
loco->speed = 100; // 100 / 1000 = 10% de la vitesse max
canSendMsg(setSpeed);
delay(1000ul * 50ul);
// Vers l'arriere
loco->direction = 2;
canSendMsg(setDirection);
delay(10);
loco->speed = 500; // 300 / 1000 = 30% de la vitesse max
canSendMsg(setSpeed, 0);
delay(1000ul * 50ul);
loco->fn[3] = on;
canSendMsg(setfunction, 2);
delay(3000);
loco->fn[3] = off;
canSendMsg(setfunction, 3);
delay(10);
loco->speed = 50; // 50 / 1000 = 5% de la vitesse max
canSendMsg(setSpeed);
delay(10000);
//Power off
laBox.setPower(off);
canSendMsg(setPower);
delay(1000);
}
//——————————————————————————————————————————————————————————————————————————————