Bonjour à tous,
En parallèle de la réalisation de la zone commutable, je remets au point un programme Arduino qui me permet de gérer des aller-retours automatiques sur le réseau. La détection est basée sur la détection de courant en utilisant un module de chez NCE (BD20 Block Detector). Cf.
https://www.dccconcepts.com/themencode- ... &pagemode=
Je risque d'en perdre un certain nombre mais guère moins qu'avec la guerre intestine du moment. Alors, je vous livre le code.
Et bien évidemment pour que tout cela fonctionne, il faut créer une interface entre le protocole Loconet et la carte Arduino.
Tout est sur cette page :
https://www.modelrailway-online.com/ard ... loconet-3/
A suivre mais d'ici là, bonne lecture
Fabrice
// Name
#define NAME "Digitrax LocoNet"
#define NAME2 "DCC Automatic Reverse Circuit System"
#define NAME3 "(Detection by NCE BD20)"
// Version & Copyright
#define VERSION "V4.0 (Arduino Uno)"
#define COPYRIGHT "Fabrice Fayolle, February 2024"
// Arduino Uno
// Pin -> Use for -> Connect to
// 0
// 1
// 2
// 3 -> ACR On -> SPDT
// 4 -> DCC Sound -> SPDT
// 5
// 6 -> ACR Indicator -> Red LED (with a 220 ohms resistor)
// 7 -> LocoNet Transmit pin -> Locoshield PCB Tx pin
// 8 -> LocoNet Receive pin -> Locoshield PCB Rx pin
// 9
// 10
// 11
// 12
// 13
// 14 to 15 -> Detection Input (West) -> NCE BD20
// 16 -> ADR Loco selection -> Potentiometer
// 17 to 18 -> Detection Input (East) -> NCE BD20
// 19
#define ACR_On_Pin 3
// ACR On -> SPDT ON-ON
// 5V -> Not activated / 0V -> Activated
#define Sound_On_Pin 4
// DCC Sound -> SPDT ON-ON
// 5V -> Not activated / 0V -> Activated
#define ACR_Indicator 6
// Pin 7 and 8, go to LocoNet section
// Digitrax LocoNet message
#define Detect_West1_PIN 14
// Detection : NCE BD20
// Not detected -> HIGH
// Detected -> LOW
#define Detect_West2_PIN 15
#define ADR_Loco_Pin 16
// ADR Loco selection -> Potentiometer 10K
#define Detect_East1_PIN 17
#define Detect_East2_PIN 18
// Global constants and variables
const boolean Not_Activated = true;
const boolean Activated = !(Not_Activated);
#define Min_Time 1600
#define Coefficent_Min_Time 4
#define Max_Time 4800
#define Coefficent_Max_Time 11
const boolean On = true;
const boolean Off = !(On);
// Throttle
// Define used slots table
int used_SLOT[120];
// Define specifications of the loco DCC decoder you want to use for ACR system
#define Nb_Specifications 5
#define Nb_Loco 4
// ADR_Loco / Speed_Loco / Decoder_Model (1 -> ESU / 2 -> Zimo / 3 -> Lenz / 4 -> SoundTraxx / 5 -> Others) / Detect_Time / Sound (0 -> No Sound DCC Decoder / 1 -> Sound DCC Decoder)
const int Loco_DCC_Decoder_Specifications[Nb_Specifications * Nb_Loco] = {
//
3, 0x03, 5, 100, 1,
//
12, 0x40, 2, 0, 1,
//
39, 0x18, 1, 1000, 1,
//
13, 0x30, 3, 0, 0
};
// LocoNet
#include <LocoNet.h>
// Define LocoNet Transmit Pin
#define LN_TX_PIN 7
// Pointer to a received LocoNet packet
lnMsg *LnPacket;
void slot_Init()
// Initiliaze all slots
{
for (int slot = 0; slot < 120; slot++)
{
sendOPC_xxx(OPC_RQ_SL_DATA, slot, 0);
}
}
void sendOPC_x(int OPC_Type)
// OPC_GPOFF - OPC_GPON - OPC_IDLE LocoNet Message
{
lnMsg SendPacket;
SendPacket.data[0] = OPC_Type;
LocoNet.send( &SendPacket );
switch (OPC_Type)
{
case OPC_GPOFF:
// OPC_GPOFF -> Power OFF
Serial.print("OPC_GPOFF");
break;
case OPC_GPON:
// OPC_GPON -> Power ON
Serial.print("OPC_GPON");
break;
case OPC_IDLE:
// OPC_IDLE -> Emergency Stop_Time
Serial.print("OPC_IDLE");
break;
}
Serial.println(" LocoNet message sent");
delay(250);
return;
}
void sendOPC_xxx(int OPC_Type, int Arg1, int Arg2)
// OPC_LOCO_SPD - OPC_LOCO_DIRF - OPC_LOCO_SND - OPC_SW_REQ - OPC_MOVE_SLOTS - OPC_RQ_SL_DATA - OPC_LOCO_ADR LocoNet Message
{
lnMsg SendPacket;
SendPacket.data[0] = OPC_Type;
SendPacket.data[1] = Arg1;
SendPacket.data[2] = Arg2;
LocoNet.send( &SendPacket );
switch (OPC_Type)
{
case OPC_LOCO_SPD:
// OPC_LOCO_SPD
Serial.print ("SLOT ");
Serial.print(Arg1);
Serial.print(" : OPC_LOCO_SPD");
break;
case OPC_LOCO_DIRF:
// OPC_LOCO_DIRF
Serial.print ("SLOT ");
Serial.print(Arg1);
Serial.print(" : OPC_LOCO_DIRF");
break;
case OPC_LOCO_SND:
// OPC_LOCO_SND
Serial.print ("SLOT ");
Serial.print(Arg1);
Serial.print(" : OPC_LOCO_SND");
break;
case OPC_SW_REQ:
// OPC_SW_REQ
Serial.print ("Turnout Adr ");
Serial.print(Arg1 + 1);
Serial.print(" : OPC_SW_REQ");
break;
case OPC_MOVE_SLOTS:
// OPC_MOVE_SLOTS
Serial.print ("SLOT ");
Serial.print(Arg1);
Serial.print(" : OPC_MOVE_SLOTS");
break;
case OPC_RQ_SL_DATA:
// OPC_RQ_SL_DATA
Serial.print ("SLOT ");
Serial.print(Arg1);
Serial.print(" : OPC_RQ_SL_DATA");
break;
case OPC_LOCO_ADR:
// OPC_LOCO_ADR
Serial.print ("DCC Adr ");
Serial.print(Arg2);
Serial.print(" : OPC_LOCO_ADR");
break;
}
Serial.println(" LocoNet message sent");
delay(250);
return;
}
void LocoNet_Message_For_Lever(int SLever_dcc, int SLever_type, boolean SLever_state)
{
int sw1 = 0x00;
int sw2 = 0x00;
switch (SLever_type)
{
case 0 :
// 0 -> Not use
break;
case 1 :
// 1 -> Point
SLever_dcc = SLever_dcc - 1;
if (SLever_state)
{
sw1 |= B00100000;
sw2 |= B00100000;
}
sw1 |= B00010000;
sw1 |= (SLever_dcc >> 7) & 0x0F;
sw2 |= (SLever_dcc >> 7) & 0x0F;
sendOPC_xxx(OPC_SW_REQ, SLever_dcc & 0x7F, sw1);
sendOPC_xxx(OPC_SW_REQ, SLever_dcc & 0x7F, sw2);
break;
case 2:
// 2 -> FPL
break;
case 3:
// 3 -> Signal
break;
case 4:
// 4 -> Block signal
break;
}
return;
}
// Object "Throttle"
class Throttle
{
private:
int SLOT;
int ADR;
int SPD;
int DIRF;
int SND;
public:
void Setup(int SADR);
void Change_SPD(int SSPD);
void Change_DIRF(int SDIRF);
void Change_SND(int SSND);
}
;
void Throttle::Setup(int SADR)
{
sendOPC_xxx(OPC_LOCO_ADR, 0, SADR);
LnPacket = LocoNet.receive() ;
while ((LnPacket->data[0] != 0xE7) | (LnPacket->data[4] != SADR))
{
sendOPC_xxx(OPC_LOCO_ADR, 0, SADR);
LnPacket = LocoNet.receive();
}
Serial.print(LnPacket->data[0], HEX);
Serial.print(" LocoNet Message Received -> DCC Adr ");
Serial.print(LnPacket->data[4]);
Serial.print(" was found in SLOT ");
Serial.println(LnPacket->data[2]);
SLOT = LnPacket->data[2];
ADR = LnPacket->data[4];
SPD = 0x00;
DIRF = 0x00;
SND = 0x00;
//sendOPC_xxx(OPC_MOVE_SLOTS, SLOT, SLOT);
//sendOPC_xxx(OPC_LOCO_DIRF, SLOT, DIRF);
//sendOPC_xxx(OPC_LOCO_SPD, SLOT, SPD);
//sendOPC_xxx(OPC_LOCO_SND, SLOT, SND);
Serial.println("Communication initialized");
int i = 0;
while (used_SLOT
!= 0)
{
i = i + 1;
}
used_SLOT = SLOT;
return;
}
void Throttle::Change_SPD(int SSPD)
{
SPD = SSPD;
Serial.print("SPD at ");
Serial.print((SPD * 100) / 128);
Serial.println(" % ");
sendOPC_xxx(OPC_LOCO_SPD, SLOT, SPD);
}
void Throttle::Change_DIRF(int SDIRF)
{
DIRF = DIRF + SDIRF;
Serial.print("DIRF: ");
Serial.print(DIRF);
Serial.print("\t\tDirection: ");
Serial.print(((DIRF & 0x20) == 0) ? "->" : "<-");
Serial.print("\tFunction(s): ");
Serial.print(((DIRF & 0x10) == 0) ? "" : "F0 ");
Serial.print(((DIRF & 0x01) == 0) ? "" : "F1 ");
Serial.print(((DIRF & 0x02) == 0) ? "" : "F2 ");
Serial.println(((DIRF & 0x04) == 0) ? "" : "F3");
sendOPC_xxx(OPC_LOCO_DIRF, SLOT, DIRF);
}
void Throttle::Change_SND(int SSND)
{
SND = SSND;
Serial.print("SND: ");
Serial.println(SND);
sendOPC_xxx(OPC_LOCO_SND, SLOT, SND);
}
Throttle Loco_Throttle;
void setup()
{
// Initialize Serial Port USB at 9600 baud
Serial.begin(9600);
Serial.println(NAME);
Serial.println(NAME2);
Serial.println(NAME3);
Serial.println("-------------------------------------------------------------------------- -");
Serial.print(VERSION); Serial.print(", "); Serial.println(COPYRIGHT);
Serial.println("---------------------------------------------------------------------------");
// LocoNet
LocoNet.init(LN_TX_PIN);
// DCC
delay(2500);
DCC_On();
delay(2500);
// DCC Sound
pinMode(Sound_On_Pin, INPUT_PULLUP);
// ADR Loco
pinMode(ADR_Loco_Pin, INPUT);
// Initialize Detection Input
pinMode(Detect_West1_PIN, INPUT);
digitalWrite(Detect_West1_PIN, Not_Activated);
pinMode(Detect_West2_PIN, INPUT);
digitalWrite(Detect_West2_PIN, Not_Activated);
pinMode(Detect_East1_PIN, INPUT);
digitalWrite(Detect_East1_PIN, Not_Activated);
pinMode(Detect_East2_PIN, INPUT);
digitalWrite(Detect_East2_PIN, Not_Activated);
// ACR
pinMode(ACR_On_Pin, INPUT_PULLUP);
delay(1000);
// ACR Indicator
pinMode(ACR_Indicator, OUTPUT);
digitalWrite(ACR_Indicator, Off);
// Initialize Random Stop_Time Time Variable
randomSeed(analogRead(0));
// System initialized
Serial.println("System ACR initialized");
}
int ind_tab_read()
{
int value;
int k = 1024 / Nb_Loco;
int i = 0;
value = analogRead(ADR_Loco_Pin);
while (value > k)
{
k = k + 1024 / Nb_Loco;
i++;
}
return (i);
}
void ACR_Detection_Indicated(int delay_time, int nb)
{
for (int x = 0; x < nb; x++)
{
digitalWrite(ACR_Indicator, Off);
delay(delay_time);
digitalWrite(ACR_Indicator, On);
delay(delay_time);
}
return;
}
void Stop_Time()
{
unsigned int delay_time;
delay_time = random(Min_Time, Max_Time) * random (Coefficent_Min_Time, Coefficent_Max_Time);
Serial.print("Stop during ");
Serial.print(delay_time);
Serial.println(" ms");
delay(delay_time);
return;
}
void Whistle(int Decoder_Model_Loco)
{
switch (Decoder_Model_Loco)
{
case 1:
Loco_Throttle.Change_DIRF(0x02);
Loco_Throttle.Change_DIRF(-0x02);
break;
case 2:
Loco_Throttle.Change_DIRF(0x04);
Loco_Throttle.Change_DIRF(-0x04);
break;
case 3:
break;
case 4:
break;
case 5:
break;
}
return;
}
void ACR_loop(byte Decoder_Model_Loco, byte Speed_Loco, int Detect_Time, boolean Sound_Activated)
{
while ((digitalRead(Detect_West1_PIN) == Not_Activated) && (digitalRead(Detect_West2_PIN) == Not_Activated))
{
delay(100);
}
Serial.println("Loco on West detector");
ACR_Detection_Indicated(250, 2);
delay(Detect_Time);
Loco_Throttle.Change_SPD(0x00);
if (Decoder_Model_Loco == 2)
{
Loco_Throttle.Change_DIRF(0x02);
delay(3000);
Loco_Throttle.Change_DIRF(-0x02);
}
Stop_Time();
Loco_Throttle.Change_DIRF(-0x20);
delay(1000);
if (Sound_Activated)
{
Whistle(Decoder_Model_Loco);
delay(2500);
}
Loco_Throttle.Change_SPD(Speed_Loco);
while ((digitalRead(Detect_East1_PIN) == Not_Activated) && (digitalRead(Detect_East2_PIN) == Not_Activated))
{
delay(100);
}
Serial.println("Loco on East detector");
ACR_Detection_Indicated(250, 2);
delay(Detect_Time);
Loco_Throttle.Change_SPD(0x00);
if (Decoder_Model_Loco == 2)
{
Loco_Throttle.Change_DIRF(0x02);
delay(3000);
Loco_Throttle.Change_DIRF(-0x02);
}
Stop_Time();
if (digitalRead(ACR_On_Pin) == Activated)
{
Loco_Throttle.Change_DIRF(0x20);
delay(1000);
if (Sound_Activated)
{
Whistle(Decoder_Model_Loco);
delay(2500);
}
Loco_Throttle.Change_SPD(Speed_Loco);
ACR_loop(Decoder_Model_Loco, Speed_Loco, Detect_Time, Sound_Activated);
}
return;
}
void loop()
{
// Constants and Variables
byte Specifications_Ind = 0;
byte ADR_Loco = 3;
byte Speed_Loco = 0x03;
byte Decoder_Model_Loco = 5;
int Detect_Time = 100;
boolean Sound_Activated = LOW;
while (digitalRead(ACR_On_Pin) == Not_Activated)
{
delay(100);
}
// Initialize Automatic Circuit Reverse
// Loco must have activated West 1 detector to initialize the system
// Specifications_Ind = ind_tab_read();
Specifications_Ind = 2;
ADR_Loco = Loco_DCC_Decoder_Specifications[Specifications_Ind * Nb_Specifications];
Speed_Loco = Loco_DCC_Decoder_Specifications[(Specifications_Ind * Nb_Specifications) + 1];
Decoder_Model_Loco = Loco_DCC_Decoder_Specifications[(Specifications_Ind * Nb_Specifications) + 2];
Detect_Time = Loco_DCC_Decoder_Specifications[(Specifications_Ind * Nb_Specifications) + 3];
Serial.print("Waiting for System ACR activation on West 1 detector with ADR_LOCO ");
Serial.println(ADR_Loco);
Serial.println("Parameters:");
Serial.print("-Loco speed defined at ");
Serial.print((Speed_Loco * 100) / 128);
Serial.println("%");
Serial.print("-DCC Decoder Model: ");
switch (Decoder_Model_Loco)
{
case 1:
Serial.println("ESU");
break;
case 2:
Serial.println("Zimo");
break;
case 3:
Serial.println("Lenz (Switching On (F3))");
break;
case 4:
Serial.println("Soundtraxx");
break;
case 5:
Serial.println("Others");
break;
}
// Sound
if (Loco_DCC_Decoder_Specifications[(Specifications_Ind * Nb_Specifications) + 4])
{
if (digitalRead(Sound_On_Pin) == Activated)
{
Sound_Activated = HIGH;
}
}
Serial.println((Sound_Activated) ? "-Sound" : "-No sound");
while (digitalRead (Detect_West1_PIN) == Not_Activated)
{
ACR_Detection_Indicated(100, 1);
}
// System initialized
Serial.println("System ACR activited");
digitalWrite(ACR_Indicator, On);
// Initialize Loco Throttle with ADR Loco Selected
Loco_Throttle.Setup(ADR_Loco);
Serial.print("Loco ADR ");
Serial.print(ADR_Loco);
Serial.println(" -> USED");
delay(500);
Loco_Throttle.Change_SPD(0x00);
delay(2500);
switch (Decoder_Model_Loco)
{
case 1:
Loco_Throttle.Change_DIRF(0x30);
break;
case 2:
Loco_Throttle.Change_DIRF(0x30);
break;
case 3:
Loco_Throttle.Change_DIRF(0x34);
break;
case 4:
Loco_Throttle.Change_DIRF(0x30);
break;
case 5:
Loco_Throttle.Change_DIRF(0x30);
break;
}
if (Sound_Activated)
{
delay(1000);
switch (Decoder_Model_Loco)
{
case 1:
Loco_Throttle.Change_DIRF(0x01);
break;
case 2:
Loco_Throttle.Change_DIRF(0x01);
break;
case 3:
break;
case 4:
Loco_Throttle.Change_SND(0x00);
break;
case 5:
break;
}
}
ACR_loop(Decoder_Model_Loco, Speed_Loco, Detect_Time, Sound_Activated);
Serial.println("System ACR stopped");
if (Sound_Activated)
{
delay(1000);
switch (Decoder_Model_Loco)
{
case 1:
Loco_Throttle.Change_DIRF(-0x01);
break;
case 2:
Loco_Throttle.Change_DIRF(-0x01);
break;
case 3:
Loco_Throttle.Change_SND(0x08);
break;
case 4:
break;
case 5:
break;
}
delay(5000);
}
switch (Decoder_Model_Loco)
{
case 1:
Loco_Throttle.Change_DIRF(-0x10);
break;
case 2:
Loco_Throttle.Change_DIRF(-0x10);
break;
case 3:
Loco_Throttle.Change_DIRF(-0x14);
break;
case 4:
Loco_Throttle.Change_DIRF(-0x10);
break;
case 5:
Loco_Throttle.Change_DIRF(-0x10);
break;
}
Serial.print("Loco ADR ");
Serial.print(ADR_Loco);
Serial.println(" -> NOT USED");
digitalWrite(ACR_Indicator, Off);
}
void DCC_On()
// DCC Power ON
{
sendOPC_x(OPC_GPOFF);
delay(1000);
sendOPC_x(OPC_GPON);
return;
}