Bonjour,
Le 1er test de motorisation sera fait avec un moteur classique commandé via un décodeur DCC. Étant équipé en Digitrax depuis plus de 20 ans, je peux utiliser le protocole LocoNet pour commander des équipements via un programme Arduino et une interface (plus d'informations à ce propos
ici). Ci-dessous le programme Arduino qui permettra de commander le pont tournant.
Il ne me reste plus qu'à intégrer (une fois le circuit imprimé reçu pour test) un lecteur MP3 à base d'un
DFPlayer. J'utilisais précédemment un
WTV020 mais il n'est possible avec ce circuit que d'utiliser certaines cartes SD de 1Go. Cette limitation n'existe pas avec le circuit DFPlayer. Ce lecteur permettra de sonoriser à terme le pont tournant.
Rq: Il est possible aussi d'utiliser un décodeur DCC sonore et d'y intégrer les sons du moteur du pont tournant.
Code : Tout sélectionner
// Name
#define NAME "DCC-TT-Motor"
#define NAME2 "LocoNet protocol (Digitrax) uses to manage a TurnTable by a DCC Decoder without stepper motor"
#define NAME3 "Sounds by a DFPlayer board"
// Version & Copyright
#define VERSION "1.0 (Arduino Uno)"
#define COPYRIGHT "Fabrice Fayolle, November 2019"
// Digitrax LocoNet -> LocoNet
// DCC Throttle -> Throttle
// Sound system -> DFPlayer
// Arduino Uno
// Pin -> Use for -> Connect to
// 0
// ...
// 6 -> Default -> Red LED (with a 220 ohms resistor)
// 7 -> LocoNet Transmit pin -> Locoshield PCB Tx pin
// 8 -> LocoNet Receive pin -> Locoshield PCB Rx pin
// 9 -> Emergency Stop -> Push button
// 10 -> Serial Rx pin -> DFPlayer PCB Tx pin
// 11 -> Serial Tx pin -> DFPlayer PCB Rx pin
// ...
// 15 -> Turntable direction -> SPDT ON-ON
// 16 -> Turntable stop -> Push button
// 17 -> Turntable brake -> Push button
// 18 -> Turntable low speed -> Push button
// 19 -> Turntable mid speed -> Push button
// INPUT
// Push button
// 1 -> Arduino Pin
// 2 -> GND
// SPDT ON-ON
// 1 -> 5V -> Normal position
// Common point -> Arduino Pin
// 2 -> GND -> Reverse position
// OUTPUT
// Digitrax LocoNet message
// Global constants and variables
const boolean Activated = LOW;
// Visual management for interlocking system
// Default lever position
const int DefaultPin = 6;
// Throttle
// Define used slots table
int used_SLOT[120];
// Define the address of the turntable DCC decoder
const int ADR_Turntable = 101;
// Define constants and variables for the turntable
boolean TT_dir = false;
const int TT_dir_PIN = 15;
const int TT_stop_PIN = 16;
const int TT_brake_PIN = 17;
#define TT_brake -0x01
const int TT_lowspeed_PIN = 18;
#define TT_lowspeed 0x03
const int TT_midspeed_PIN = 19;
#define TT_midspeed 0x40
// DFPlayer
// https://github.com/PowerBroker2/DFPlayerMini_Fast
#include <SoftwareSerial.h>
#include <DFPlayerMini_Fast.h>
// LocoNet
// https://github.com/mrrwa
#include <LocoNet.h>
// Define LocoNet Transmit Pin
#define LN_TX_PIN 7
// Emergency Stop
const int Emergency_PIN = 9;
// 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
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;
}
// DFPlayer
// Define DFPlayer Serial Receive and Transmit Pin
#define DFPl_RX_PIN 10
#define DFPl_TX_PIN 11
SoftwareSerial mySerial(DFPl_RX_PIN, DFPl_TX_PIN);
DFPlayerMini_Fast myMP3;
// 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[i] != 0)
{
i = i + 1;
}
used_SLOT[i] = SLOT;
return;
}
void Throttle::Change_SPD(int SSPD)
{
if (SSPD < 0)
{
if (SPD > 0) SPD = SPD + SSPD;
}
else
{
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 = SND + SSND;
Serial.print("SND:");
Serial.println(SND);
sendOPC_xxx(OPC_LOCO_DIRF, SLOT, SND);
}
Throttle TT_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(VERSION); Serial.print(", "); Serial.println(COPYRIGHT);
Serial.println("---------------------------------------------------------------------------");
// Visual management
pinMode(DefaultPin, OUTPUT);
digitalWrite(DefaultPin, LOW);
// LocoNet
LocoNet.init(LN_TX_PIN);
pinMode(Emergency_PIN, INPUT_PULLUP);
DCC_On();
// Throttle
// Initialize used_SLOT
for (int i = 0; i < 120; i++)
{
used_SLOT[i] = 0;
}
// Initialize Turntable INPUT
pinMode(TT_dir_PIN, INPUT_PULLUP);
pinMode(TT_stop_PIN, INPUT_PULLUP);
pinMode(TT_brake_PIN, INPUT_PULLUP);
pinMode(TT_lowspeed_PIN, INPUT_PULLUP);
pinMode(TT_midspeed_PIN, INPUT_PULLUP);
// Initialize Turntable Throttle
TT_Throttle.Setup(ADR_Turntable);
// DFPlayer
// Initialize Serial Communication at 9600 baud
//mySerial.begin(9600);
//myMP3.begin(mySerial);
//myMP3.volume(30);
//
Serial.println("Ready to use");
}
void loop()
{
// Loconet
Emergency();
// Throttle (Turntable)
Turntable_Order();
// DFPlayer
//myMP3.play(1);
}
void DCC_On()
// DCC Power ON
{
sendOPC_x(OPC_GPOFF);
delay(100);
sendOPC_x(OPC_GPON);
return;
}
void Emergency()
// Emergency Stop required
{
int i = 0;
if (digitalRead(Emergency_PIN) == Activated)
{
delay(100);
if (digitalRead(Emergency_PIN) == Activated)
{
while (digitalRead(Emergency_PIN) == Activated)
{
digitalWrite(DefaultPin, HIGH);
delay(100);
digitalWrite(DefaultPin, LOW);
delay(100);
}
Serial.println("Emergency STOP!!!");
//sendOPC_x(OPC_IDLE);
while (used_SLOT[i] != 0)
{
sendOPC_xxx(OPC_LOCO_SPD, used_SLOT[i], 0x00);
i = i + 1;
}
}
}
return;
}
void Turntable_Order()
// Control Turntable Direction by a SPDT ON-ON (Input: TT_dir_PIN)
// and Turntable Speed by some Push buttons (Input: TT_stop_PIN, TT_brake_PIN, TT_lowspeed_PIN and TT_midspeed_PIN)
{
if ((digitalRead(TT_dir_PIN) == HIGH) && TT_dir)
{
TT_dir = false;
TT_Throttle.Change_DIRF(-0x20);
}
if ((digitalRead(TT_dir_PIN) == LOW) && !TT_dir)
{
TT_dir = true;
TT_Throttle.Change_DIRF(0x20);
}
if (digitalRead(TT_stop_PIN) == Activated)
{
delay(100);
if (digitalRead(TT_stop_PIN) == Activated)
{
while (digitalRead(TT_stop_PIN) == Activated)
{
digitalWrite(DefaultPin, HIGH);
delay(100);
digitalWrite(DefaultPin, LOW);
delay(100);
}
Serial.print("Stop -> Turntable ");
TT_Throttle.Change_SPD(0x00);
}
}
if (digitalRead(TT_brake_PIN) == Activated)
{
delay(100);
if (digitalRead(TT_brake_PIN) == Activated)
{
while (digitalRead(TT_brake_PIN) == Activated)
{
digitalWrite(DefaultPin, HIGH);
delay(100);
digitalWrite(DefaultPin, LOW);
delay(100);
}
Serial.print("Brake -> Turntable ");
TT_Throttle.Change_SPD(TT_brake);
}
}
if (digitalRead(TT_lowspeed_PIN) == Activated)
{
delay(100);
if (digitalRead(TT_lowspeed_PIN) == Activated)
{
while (digitalRead(TT_lowspeed_PIN) == Activated)
{
digitalWrite(DefaultPin, HIGH);
delay(100);
digitalWrite(DefaultPin, LOW);
delay(100);
}
Serial.print("Low speed -> Turntable ");
TT_Throttle.Change_SPD(TT_lowspeed);
}
}
if (digitalRead(TT_midspeed_PIN) == Activated)
{
delay(100);
if (digitalRead(TT_midspeed_PIN) == Activated)
{
while (digitalRead(TT_midspeed_PIN) == Activated)
{
digitalWrite(DefaultPin, HIGH);
delay(100);
digitalWrite(DefaultPin, LOW);
delay(100);
}
Serial.print("Mid speed -> Turntable ");
TT_Throttle.Change_SPD(TT_midspeed);
}
}
return;
}
A suivre...
Fabrice