766 lines
31 KiB
C++
766 lines
31 KiB
C++
// Interactive Decoder Motor, Pauses, Reversals w/Sound 4 LED IDEC1_1_MotSound4Led.ino
|
|
// Version 1.08 Geoff Bunza 2020
|
|
// Works with both short and long DCC Addesses
|
|
// This decoder uses switches/sensors to control 2 motors and Five LEDs with Sound
|
|
// F0=Master Function OFF = Function ON DISABLES the decoder
|
|
// Input Pin for Decoder Disable Pin 16 Active LOW
|
|
//Motor speed via DCC speed for one motor, second motor on/off via function
|
|
//Speed Over-Ride = CV = Non-Zero Value (1-127) over-rides the DCC speed commands Bit 8 is direction 1=Forward
|
|
//Input1 Pin for Throttle Down/Pause/Throttle Up Pin 5
|
|
// CV for Throttle Down Time, CV for Throttle Up Time,, CV for Pause Time
|
|
//Input2 Pin for Throttle Down/Pause/Throttle Up Pin 6
|
|
// CV for Throttle Down Time, CV for Throttle Up Time,, CV for Pause Time
|
|
//Input Pin1 for Throttle Down/Reverse/Throttle Up Pin 7
|
|
// CV for Throttle Down Time, CV for Throttle Up Time;,CV for Reverse Pause Time
|
|
//Input Pin2 for Throttle Down/Reverse/Throttle Up Pin 8
|
|
// CV for Throttle Down Time, CV for Throttle Up Time;,CV for Reverse Pause Time
|
|
//Input Pin for immediate Stop Pin 11
|
|
//Input Pin for Immediate Start Pin 12
|
|
//Functions for lights on/off:
|
|
// F1-F5 5 Functions LED ON/OFF by default PINS 13,14,17,18,19
|
|
/* Pro Mini D15 A1 (TX) connected to DFPlayer1 Receive (RX) Pin 2 via 1K Ohm 1/4W Resistor
|
|
* Remember to connect +5V and GND to the DFPlayer too: DFPLAYER PINS 1 & 7 respectively
|
|
* This is a “mobile/function” decoder with audio play to dual motor control and
|
|
* LED functions. Audio tracks or clips are stored on a micro SD card for playing,
|
|
* in a folder labeled mp3, with tracks named 0001.mp3, 0002.mp3, etc.
|
|
* MAX 3 Configurations per pin function:
|
|
* Config 0=Decoder DISABLE On/Off, 1=LED; 2=Motor2 Control On/Off
|
|
F0 == Master Decoder Disable == ON
|
|
F1 == LED == D13
|
|
F2 == LED == D14/A0
|
|
F3 == LED == D17/A3
|
|
F4 == LED == D18/A4
|
|
F5 == LED == D19/A5
|
|
F6 == Motor2 On/OFF speed & direction set by CV 80 Normally Base Station will Transmit F5 as initial OFF
|
|
If no DCC present Decoder will power up with Motor2 ON at speed specified in CV 72
|
|
Motor1 speed control is via throttle or overridden by non zero value in CV 50
|
|
High Bit=Direction, Lower 7 Bits=Speed == DSSSSSSS
|
|
|
|
PRO MINI PIN ASSIGNMENT:
|
|
2 - DCC Input
|
|
3 - m2h Motor Control
|
|
4 - m2l Motor Control
|
|
5 - Input1 Pin for Throttle Down/Pause/Throttle Up
|
|
6 - Input2 Pin for Throttle Down/Pause/Throttle Up
|
|
7 - Input1 Pin for Throttle Down/Reverse/Throttle Up
|
|
8 - Input2 Pin for Throttle Down/Reverse/Throttle Up
|
|
9 - m0h Motor Control
|
|
10 - m0l Motor Control
|
|
11 - Input Pin for immediate Stop
|
|
12 - Input Pin for Immediate Start
|
|
13 - LED F1
|
|
14 A0 - LED F2
|
|
15 A1 - (TX) connected to DFPlayer1 Receive (RX) Pin 2 via 1K Ohm 1/4W Resistor
|
|
16 A2 - Input Pin for MasterDecoderDisable Active LOW
|
|
17 A3 - LED F3
|
|
18 A4 - LED F4
|
|
19 A5 - LED F5
|
|
*/
|
|
|
|
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
|
|
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
|
|
//#define DECODER_LOADED
|
|
|
|
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
|
|
// ******** INFO TO THE SERIAL MONITOR
|
|
//#define DEBUG
|
|
|
|
#include <NmraDcc.h>
|
|
#include <SoftwareSerial.h>
|
|
#include <DFRobotDFPlayerMini.h>
|
|
SoftwareSerial DFSerial1(21,15); // PRO MINI RX, PRO MINI TX serial to DFPlayer
|
|
DFRobotDFPlayerMini Player1;
|
|
|
|
#define This_Decoder_Address 24
|
|
uint8_t CV_DECODER_MASTER_RESET = 252;
|
|
|
|
//Uncomment ONLY ONE of the following:
|
|
//#define MasterTimeConstant 10L // 10's of milliseconds Timing
|
|
#define MasterTimeConstant 100L // Tenths of a second Timing
|
|
//#define MasterTimeConstant 1000L // Seconds Timing
|
|
//#define MasterTimeConstant 10000L // 10's of Seconds Timing
|
|
//#define MasterTimeConstant 60000L // Minutes Timing
|
|
//#define MasterTimeConstant 3600000L // Hours Timing
|
|
|
|
#define runAfter(t) for (static unsigned long _dTimer;(unsigned long)(millis()-_dTimer)>=(t);_dTimer=millis())
|
|
|
|
int tctr, tctr2;
|
|
uint16_t ttemp, i;
|
|
#define First_Track 1 // Play Random Tracks First_Track#=Start_Track >=1
|
|
#define Last_Track 12 // Play Random Tracks Last_Track= Last Playable Track in Range <= Last Numbered Track
|
|
|
|
const int audiocmddelay = 34;
|
|
boolean Use_DCC_speed = true; // Switch to disable DCC Speed updates
|
|
int Motor1Speed = 0; // Variablw for Motor1 Speed
|
|
int Starting_Motor1Speed = 0;
|
|
int Motor1ForwardDir = 1; // Variable for Motor1 Dir
|
|
int ForcedStopSpeedMotor1 = 0; // Holding Variablw for Last Speed when Immediate Stop
|
|
int ForcedStopDirMotor1 = 1; // Holding Variablw for Last Direction when Immediate Stop
|
|
int Motor2Speed = 0; // Variable for Motor2 Speed
|
|
int Motor2ForwardDir = 1; // Variable for Motor2 Dir
|
|
int Motor2ON = 0;
|
|
int fwdon = 0;
|
|
int fwdtime = 1;
|
|
int bwdon = 0;
|
|
int bwdtime = 1;
|
|
int cyclewidth = 2048;
|
|
int loopdelay = 0; //14;
|
|
|
|
const int m2h = 3; //R H Bridge Motor1
|
|
const int m2l = 4; //B H Bridge Motor1
|
|
const int ThrottlePause1Pin = 5; // Throttle Speed Pause1 Input Pin
|
|
const int ThrottlePause2Pin = 6; // Throttle Speed Pause2 Input Pin
|
|
const int ThrottleInputReversePin1 = 7; // Throttle Speed Reverse Input Pin
|
|
const int ThrottleInputReversePin2 = 8; // Throttle Immediate Speed Reverse Input Pin
|
|
const int m0h = 9; //R H Bridge Motor2
|
|
const int m0l = 10; //B H Bridge //Motor2
|
|
const int ImmediateStopPin = 11; // Throttle Immediate Stop Input Pin
|
|
const int ImmediateStartPin = 12; // Throttle Immediate Start Input Pin
|
|
const int MasterDecoderDisablePin = 16; // D16/A0 Master Decoder Disable Input Pin Active LOW
|
|
// arduino pin D 15; // D15/A1 DFPlayer Receive (RX) Pin 2 via 470 Ohm Resistor
|
|
|
|
const int numfpins = 10; // Number of Output pins to initialize
|
|
const int num_active_functions = 7; // Number of Functions stating with F0
|
|
byte fpins [] = {13,13,14,17,18,19,3,4,9,10}; //These are all the Output Pins (first 13 is placeholder)
|
|
const int FunctionPin0 = 20; // D14/A0 DFPlayer Transmit (TX) Pin 3
|
|
const int FunctionPin1 = 13; // A2 LED
|
|
const int FunctionPin2 = 14; // A3 LED
|
|
const int FunctionPin3 = 17; // A4 LED
|
|
const int FunctionPin4 = 18; // A5 LED
|
|
const int FunctionPin5 = 19; // A6 LED
|
|
|
|
const int FunctionPin6 = 20; // Turns on Motor2 DCC Function Control Only NO Local Input Pin
|
|
const int FunctionPin7 = 20; // Place holders ONLY
|
|
const int FunctionPin8 = 20; // Place holders ONLY
|
|
const int FunctionPin9 = 20; // Place holders ONLY
|
|
const int FunctionPin10 = 20; // Place holders ONLY
|
|
const int FunctionPin11 = 20; // Place holders ONLY
|
|
const int FunctionPin12 = 20; // Place holders ONLY
|
|
const int FunctionPin13 = 20; // Place holders ONLY
|
|
const int FunctionPin14 = 20; // Place holders ONLY
|
|
const int FunctionPin15 = 20; // Place holders ONLY
|
|
const int FunctionPin16 = 20; // Place holders ONLY
|
|
int MasterDecoderDisable = 0;
|
|
int Function0_value = 0;
|
|
|
|
|
|
NmraDcc Dcc ;
|
|
DCC_MSG Packet ;
|
|
int t; // temp
|
|
struct QUEUE
|
|
{
|
|
int inuse;
|
|
int current_position;
|
|
int increment;
|
|
int stop_value;
|
|
int start_value;
|
|
};
|
|
QUEUE *ftn_queue = new QUEUE[17];
|
|
|
|
struct CVPair
|
|
{
|
|
uint16_t CV;
|
|
uint8_t Value;
|
|
};
|
|
CVPair FactoryDefaultCVs [] =
|
|
{
|
|
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
|
|
|
|
// These two CVs define the Long DCC Address
|
|
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, ((This_Decoder_Address>>8)&0x7F)+192 },
|
|
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address&0xFF },
|
|
|
|
// ONLY uncomment 1 CV_29_CONFIG line below as approprate DEFAULT IS SHORT ADDRESS
|
|
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
|
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
|
// {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long Address 28/128 Speed Steps
|
|
{CV_DECODER_MASTER_RESET, 0},
|
|
|
|
{30, 0}, //F0 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
|
|
{31, 1}, //F1 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{32, 1}, //F2 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{33, 1}, //F3 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{34, 1}, //F4 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{35, 1}, //F5 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
|
|
{36, 2}, //F6 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
|
|
{37,4}, //F7 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{38,4}, //F8 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{39,4}, //F9 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{40,4}, //F10 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{41,4}, //F11 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{42,4}, //F12 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{43,4}, //F13 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{44,4}, //F14 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{45,4}, //F15 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{46,4}, //F16 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{47,4}, //F17 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{48,4}, //F18 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
{49,4}, //F19 Config 0=DISABLE On/Off,1=LED,2=Motor2 Control On/Off,3=NOT Implemented
|
|
|
|
{50, 0}, // Speed Over-Ride = CV = Non-Zero Value (1-127) over-rides the DCC speed commands
|
|
// Bit 8 (128 or 0x80) ON=Forward Direction 0=Reverse Direction
|
|
|
|
{51, 75}, // ThrottlePause1 Pause Time 0-255 (0.1 secs)
|
|
{52, 3}, // ThrottlePause1 Throttle Ramp DOWN Delay 0-255 Larger Delay=Slower Ramp Down
|
|
{53, 3}, // ThrottlePause1 Throttle Ramp UP Delay 0-255 Larger Delay=Slower Ramp Up
|
|
{54, 1}, // ThrottlePause1 Pause Sound Clip 1-nn 0=No Sound
|
|
{55, 20}, // ThrottlePause1 Pause Sound Clip Volume 0-30
|
|
|
|
{56, 22}, // ThrottlePause2 Pause Time 0-255 (0.1 secs)
|
|
{57, 5}, // ThrottlePause2 Throttle Ramp DOWN 0-255 Delay
|
|
{58, 5}, // ThrottlePause2 Throttle Ramp UP Delay 0-255
|
|
{59, 1}, // ThrottlePause2 Pause Sound Clip 1-nn 0=No Sound
|
|
{60, 20}, // ThrottlePause2 Pause Sound Clip Volume 0-30
|
|
|
|
{61, 28}, // ThrottleInputReverse1 Pause Time 0-255 (0.1 secs)
|
|
{62, 3}, // ThrottleInputReverse1 Ramp DOWN Delay 0-255
|
|
{63, 3}, // ThrottleInputReverse1 Ramp UP Delay 0-255
|
|
{64, 2}, // ThrottleInputReverse1 Sound Clip 1-nn 0=No Sound
|
|
{65, 20}, // ThrottleInputReverse1 Sound Clip Volume 0-30
|
|
|
|
{66, 22}, // ThrottleInputReverse2 Pause Time 0-255 (0.1 secs)
|
|
{67, 5}, // ThrottleInputReverse2 Ramp DOWN Delay 0-255
|
|
{68, 5}, // ThrottleInputReverse2 Ramp UP Delay 0-255
|
|
{69, 2}, // ThrottleInputReverse2 Sound Clip 1-nn 0=No Sound
|
|
{70, 20}, // ThrottleInputReverse2 Sound Clip Volume 0-30
|
|
|
|
{71, 0}, // ThrottleImmediateStop Sound Clip 1-nn 0=No Sound
|
|
{72, 20}, // ThrottleImmediateStop Sound Clip Volume 0-30
|
|
|
|
{73, 0}, // ThrottleImmediateStart Sound Clip 1-nn 0=No Sound
|
|
{74, 20}, // ThrottleImmediateStart Sound Clip Volume 0-30
|
|
|
|
{80, 20}, // Motor2 Speed 0-127 Bit 8 (128 or 0x80) ON=Forward Direction 0=Reverse Direction
|
|
|
|
//252,252 CV_DECODER_MASTER_RESET
|
|
|
|
{253, 0}, // Extra
|
|
};
|
|
|
|
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
|
void notifyCVResetFactoryDefault()
|
|
{
|
|
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
|
// to flag to the loop() function that a reset to Factory Defaults needs to be done
|
|
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
|
};
|
|
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
|
// OUTPUT PINS FOR FUNCTIONS
|
|
|
|
void setup() //******************************************************
|
|
{
|
|
#ifdef DEBUG
|
|
Serial.begin(115200);
|
|
#endif
|
|
DFSerial1.begin (9600);
|
|
Player1.begin (DFSerial1);
|
|
|
|
pinMode (ThrottlePause1Pin,INPUT_PULLUP); // Throttle Speed Pause1 Input Pin Active LOW
|
|
pinMode (ThrottlePause2Pin,INPUT_PULLUP); // Throttle Speed Pause2 Input Pin Active LOW
|
|
pinMode (ThrottleInputReversePin1,INPUT_PULLUP); // Throttle Speed Reverse Input Pin 1 Active LOW
|
|
pinMode (ThrottleInputReversePin2,INPUT_PULLUP); // Throttle Speed Reverse Input Pin 2 Active LOW
|
|
pinMode (ImmediateStopPin,INPUT_PULLUP); // Throttle Immediate Stop Input Pin Active LOW
|
|
pinMode (ImmediateStartPin,INPUT_PULLUP); // Throttle Immediate Start Input Pin Active LOW
|
|
pinMode (MasterDecoderDisablePin,INPUT_PULLUP); // Master Decoder Disable Input Pin Active LOW
|
|
uint8_t cv_value;
|
|
// initialize the digital pins as outputs
|
|
for (int i=0; i < numfpins; i++) {
|
|
pinMode(fpins[i], OUTPUT);
|
|
digitalWrite(fpins[i], 0); // All OUPUT pins initialized LOW
|
|
}
|
|
// Setup which External Interrupt, the Pin it's associated with that we're using
|
|
Dcc.pin(0, 2, 0);
|
|
// Call the main DCC Init function to enable the DCC Receiver
|
|
Dcc.init( MAN_ID_DIY, 61, FLAGS_MY_ADDRESS_ONLY, 0 );
|
|
delay(800);
|
|
#if defined(DECODER_LOADED)
|
|
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
|
|
#endif
|
|
{
|
|
for (int j=0; j < FactoryDefaultCVIndex; j++ )
|
|
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
|
|
}
|
|
|
|
for ( i=0; i < num_active_functions; i++) {
|
|
cv_value = Dcc.getCV(30+i) ;
|
|
switch ( cv_value ) {
|
|
case 0: // Master Decoder Disable
|
|
MasterDecoderDisable = 0;
|
|
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
|
|
break;
|
|
case 1: // LED On/Off
|
|
ftn_queue[i].inuse = 0;
|
|
break;
|
|
case 2: // Motor2 Control
|
|
if ( Dcc.getCV(72) != 0) {
|
|
Motor2ON = 1;
|
|
Motor2Speed = (Dcc.getCV(72))&0x7f ;
|
|
Motor2ForwardDir = (byte)((Dcc.getCV(72))&0x80)>>7 ;
|
|
} else Motor2ON = 0;
|
|
break;
|
|
case 3: // NEXT FEATURE for the Future
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
Motor1ForwardDir = 1; // Default start value for direction if throttle controlled
|
|
if ( Dcc.getCV(50) != 0) {
|
|
Motor1Speed = (Dcc.getCV(50))&0x7f ;
|
|
Motor1ForwardDir = (byte)((Dcc.getCV(50))&0x80 )>>7;
|
|
}
|
|
#ifdef DEBUG
|
|
Serial.println("CV Dump:");
|
|
for (i=30; i<51; i++) { Serial.print(i,DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Throttle Pause 1");
|
|
for (i=51; i<56; i++) { Serial.print(i,DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Throttle Pause 2");
|
|
for (i=56; i<61; i++) { Serial.print(i,DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Throttle Reverse 1");
|
|
for (i=61; i<66; i++) { Serial.print(Dcc.getCV(i),DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Throttle Reverse 2");
|
|
for (i=66; i<71; i++) { Serial.print(i,DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Immediate Stop");
|
|
for (i=71; i<73; i++) { Serial.print(Dcc.getCV(i),DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Immediate Start");
|
|
for (i=73; i<75; i++) { Serial.print(i,DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
|
|
Serial.println("Motor2 Speed");
|
|
Serial.print(Dcc.getCV(80),DEC); Serial.print("\t"); }
|
|
Serial.println("");
|
|
#endif
|
|
}
|
|
void loop() //**********************************************************************
|
|
{
|
|
//MUST call the NmraDcc.process() method frequently
|
|
// from the Arduino loop() function for correct library operation
|
|
Dcc.process();
|
|
run_at_speed();
|
|
//delay(1);
|
|
|
|
// INPUT OVER RIDES
|
|
// Check Master Input Over ride
|
|
MasterDecoderDisable = 0;
|
|
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
|
|
else MasterDecoderDisable = Function0_value & 1;
|
|
|
|
if (MasterDecoderDisable == 1) { Motor1Speed = 0; Motor2Speed = 0; }
|
|
|
|
// ======== Throttle Pause 1 ========================
|
|
if (digitalRead(ThrottlePause1Pin) == LOW) { // Throttle Speed Pause1 Input Pin
|
|
Use_DCC_speed = false; // Do not update speed via DCC
|
|
Starting_Motor1Speed = Motor1Speed;
|
|
while (Motor1Speed >0) {
|
|
--Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(52)); //Throttle Ramp DOWN Delay 0-255
|
|
}
|
|
Motor1Speed = 0;
|
|
ttemp=(Dcc.getCV(54));
|
|
setVolumeOnChannel (Dcc.getCV(55));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
delay(int(Dcc.getCV(51)*MasterTimeConstant)); //Pause Time 0-255 (0.1 secs)
|
|
while (Motor1Speed <= Starting_Motor1Speed) {
|
|
++Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(53)); //Throttle Ramp UP Delay 0-255
|
|
}
|
|
Motor1Speed = Starting_Motor1Speed;
|
|
run_at_speed();
|
|
while (digitalRead(ThrottlePause1Pin) == LOW) idle(); //Wait for Sensor
|
|
Use_DCC_speed = true; // Do not update speed via DCC
|
|
}
|
|
|
|
// ======== Throttle Pause 2 ========================
|
|
if (digitalRead(ThrottlePause2Pin) == LOW) { // Throttle Speed Pause2 Input Pin
|
|
|
|
Use_DCC_speed = false; // Do not update speed via DCC
|
|
Starting_Motor1Speed = Motor1Speed;
|
|
while (Motor1Speed >0) {
|
|
--Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(57)); //Throttle Ramp DOWN Delay 0-255
|
|
}
|
|
Motor1Speed = 0;
|
|
ttemp=(Dcc.getCV(59));
|
|
setVolumeOnChannel (Dcc.getCV(60));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
delay(int(Dcc.getCV(56)*MasterTimeConstant)); //Pause Time 0-255 (0.1 secs)
|
|
while (Motor1Speed <= Starting_Motor1Speed) {
|
|
++Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(58)); //Throttle Ramp UP Delay 0-255
|
|
}
|
|
Motor1Speed = Starting_Motor1Speed;
|
|
run_at_speed();
|
|
while (digitalRead(ThrottlePause2Pin) == LOW) idle(); //Wait for Sensor
|
|
Use_DCC_speed = true; // Do not update speed via DCC
|
|
}
|
|
|
|
// ======== Throttle Reverse 1 ========================
|
|
if (digitalRead(ThrottleInputReversePin1)==LOW){ // Throttle Speed Reverse1 Input Pin
|
|
Use_DCC_speed = false; // Do not update speed via DCC
|
|
Starting_Motor1Speed = Motor1Speed;
|
|
Motor1Speed--;
|
|
while (Motor1Speed >1) {
|
|
run_at_speed();
|
|
--Motor1Speed;
|
|
delay(Dcc.getCV(62)); //Throttle Ramp DOWN Delay 0-255
|
|
}
|
|
Motor1Speed = 0;
|
|
ttemp=(Dcc.getCV(64));
|
|
setVolumeOnChannel (Dcc.getCV(65));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
Motor1ForwardDir = (Motor1ForwardDir^0x01) & 0x01;
|
|
delay(Dcc.getCV(61)*MasterTimeConstant); //Pause Time 0-255 (0.1 secs)
|
|
while (Motor1Speed < Starting_Motor1Speed) {
|
|
Motor1Speed++;;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(63)); //Throttle Ramp UP Delay 0-255
|
|
}
|
|
Motor1Speed = Starting_Motor1Speed;
|
|
run_at_speed();
|
|
while (digitalRead(ThrottleInputReversePin1) == LOW) idle(); //Wait for Sensor
|
|
Use_DCC_speed = true;
|
|
}
|
|
|
|
// ======== Throttle Reverse 2 ========================
|
|
if (digitalRead(ThrottleInputReversePin2)==LOW){ // Throttle Speed Reverse Input Pin
|
|
Use_DCC_speed = false; // Do not update speed via DCC
|
|
Starting_Motor1Speed = Motor1Speed;
|
|
while (Motor1Speed >0) {
|
|
--Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(67)); //Throttle Ramp DOWN Delay 0-255
|
|
}
|
|
Motor1Speed = 0;
|
|
ttemp=(Dcc.getCV(69));
|
|
setVolumeOnChannel (Dcc.getCV(70));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
Motor1ForwardDir = (Motor1ForwardDir^0x01) & 0x01;
|
|
delay(int(Dcc.getCV(66)*MasterTimeConstant)); //Pause Time 0-255 (0.1 secs)
|
|
while (Motor1Speed <= Starting_Motor1Speed) {
|
|
++Motor1Speed;
|
|
run_at_speed();
|
|
delay(Dcc.getCV(68)); //Throttle Ramp UP Delay 0-255
|
|
}
|
|
Motor1Speed = Starting_Motor1Speed;
|
|
run_at_speed();
|
|
while (digitalRead(ThrottleInputReversePin2) == LOW) idle(); //Wait for Sensor
|
|
Use_DCC_speed = true; // Do not update speed via DCC
|
|
}
|
|
|
|
// ======== Throttle Immediate Stop ========================
|
|
if (digitalRead(ImmediateStopPin) == LOW) { // Throttle Immediate Stop Input Pin
|
|
ForcedStopSpeedMotor1 = Motor1Speed;
|
|
ForcedStopDirMotor1 = Motor1ForwardDir;
|
|
Motor1Speed = 0;
|
|
ttemp=(Dcc.getCV(71));
|
|
setVolumeOnChannel (Dcc.getCV(72));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
}
|
|
|
|
// ======== Throttle Immediate Start ========================
|
|
if (digitalRead(ImmediateStartPin) == LOW) { // Throttle Immediate Start Input Pin
|
|
ttemp=(Dcc.getCV(73));
|
|
setVolumeOnChannel (Dcc.getCV(74));
|
|
if (ttemp!=0) playTrackOnChannel(ttemp); // play clip
|
|
if (ForcedStopSpeedMotor1 != 0) {
|
|
Motor1Speed = ForcedStopSpeedMotor1 ;
|
|
Motor1ForwardDir = ForcedStopDirMotor1;
|
|
}
|
|
else
|
|
if ( Dcc.getCV(50) != 0) {
|
|
Motor1Speed = (Dcc.getCV(50))&0x7f ;
|
|
Motor1ForwardDir = (byte)((Dcc.getCV(50))&0x80 )>>7;
|
|
}
|
|
ForcedStopSpeedMotor1 = 0; // Take us out of forced stop mode
|
|
run_at_speed();
|
|
while (digitalRead(ImmediateStartPin) == LOW) idle(); //Wait for Sensor
|
|
}
|
|
|
|
// ********************************************************************************
|
|
|
|
for (int i=0; i < num_active_functions; i++) {
|
|
switch (Dcc.getCV(30+i)) {
|
|
case 0: // Master Decoder Disable Ops
|
|
break;
|
|
case 1: // LED On/Off
|
|
if (MasterDecoderDisable == 1) digitalWrite(fpins[i], 0); //decoder disabled so LEDs off
|
|
break;
|
|
case 2: // Motor2 Control
|
|
Motor2Speed = (Dcc.getCV(72))&0x7f ; // Re-read Motor2Speed if the CV was updated
|
|
Motor2ForwardDir = (byte)((Dcc.getCV(72))&0x80)>>7 ; // Re-read Motor2ForwardDir if the CV was updated
|
|
|
|
if ((MasterDecoderDisable == 0)&&(Motor2ON == 1)) {
|
|
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, Motor2Speed<<4);
|
|
else gobwd2 (bwdtime, Motor2Speed<<4);
|
|
}
|
|
if (MasterDecoderDisable == 1) {
|
|
digitalWrite(m0h, LOW); //Motor2OFF
|
|
digitalWrite(m0l, LOW); //Motor2 OFF
|
|
}
|
|
break;
|
|
|
|
case 3: // NEXT FEATURE for the Future
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#ifdef DEBUG
|
|
Serial.print("loop4 Motor1Speed= ");
|
|
Serial.print(Motor1Speed, DEC) ;
|
|
Serial.print(" Motor2Speed= ");
|
|
Serial.println(Motor2Speed, DEC) ;
|
|
#endif
|
|
} // end loop()
|
|
|
|
void idle() {
|
|
Dcc.process();
|
|
run_at_speed();
|
|
} // end idle()
|
|
|
|
void run_at_speed() {
|
|
#ifdef DEBUG
|
|
Serial.print("run Motor1Speed= ");
|
|
Serial.print(Motor1Speed, DEC) ;
|
|
Serial.print(" Motor1ForwardDir= ");
|
|
Serial.println(Motor1ForwardDir, DEC) ;
|
|
#endif
|
|
if (MasterDecoderDisable == 0) {
|
|
if (Motor1Speed != 0) {
|
|
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, Motor1Speed<<4);
|
|
else gobwd1 (bwdtime, Motor1Speed<<4);
|
|
}
|
|
}
|
|
if (MasterDecoderDisable == 1) {
|
|
digitalWrite(m2h, LOW); //Motor1 OFF
|
|
digitalWrite(m2l, LOW); //Motor1 OFF
|
|
digitalWrite(m0h, LOW); //Motor2 OFF
|
|
digitalWrite(m0l, LOW); //Motor2 OFF
|
|
}
|
|
if ((MasterDecoderDisable == 0)&&(Motor2ON == 1)) {
|
|
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, Motor2Speed<<4);
|
|
else gobwd2 (bwdtime, Motor2Speed<<4);
|
|
}
|
|
} // end run_at_speed()
|
|
|
|
void gofwd1(int fcnt,int fcycle) {
|
|
int icnt;
|
|
int delta_tp,delta_tm;
|
|
delta_tp = fcycle+loopdelay<<2;
|
|
delta_tm = cyclewidth-fcycle-loopdelay;
|
|
icnt = 0;
|
|
while (icnt < fcnt)
|
|
{
|
|
digitalWrite(m2h, HIGH); //Motor1
|
|
delayMicroseconds(delta_tp);
|
|
digitalWrite(m2h, LOW); //Motor1
|
|
delayMicroseconds(delta_tm);
|
|
icnt++;
|
|
}
|
|
} // end gofwd1()
|
|
|
|
void gobwd1(int bcnt,int bcycle) {
|
|
int icnt;
|
|
int delta_tp,delta_tm;
|
|
delta_tp = bcycle+loopdelay<<2;
|
|
delta_tm = cyclewidth-bcycle-loopdelay;
|
|
icnt=0;
|
|
while (icnt < bcnt)
|
|
{
|
|
digitalWrite(m2l, HIGH); //Motor1
|
|
delayMicroseconds(delta_tp);
|
|
digitalWrite(m2l, LOW); //Motor1
|
|
delayMicroseconds(delta_tm);
|
|
icnt++;
|
|
}
|
|
} // end gobwd1()
|
|
|
|
void gofwd2(int fcnt,int fcycle) {
|
|
int icnt;
|
|
int delta_tp,delta_tm;
|
|
delta_tp = fcycle+loopdelay<<2;
|
|
delta_tm = cyclewidth-fcycle-loopdelay;
|
|
icnt = 0;
|
|
while (icnt < fcnt)
|
|
{
|
|
digitalWrite(m0h, HIGH); //Motor2
|
|
delayMicroseconds(delta_tp);
|
|
digitalWrite(m0h, LOW); //Motor2
|
|
delayMicroseconds(delta_tm);
|
|
icnt++;
|
|
}
|
|
} // end gofwd2()
|
|
|
|
void gobwd2(int bcnt,int bcycle) {
|
|
int icnt;
|
|
int delta_tp,delta_tm;
|
|
delta_tp = bcycle+loopdelay<<2;
|
|
delta_tm = cyclewidth-bcycle-loopdelay;
|
|
icnt=0;
|
|
while (icnt < bcnt)
|
|
{
|
|
digitalWrite(m0l, HIGH); //Motor2
|
|
delayMicroseconds(delta_tp);
|
|
digitalWrite(m0l, LOW); //Motor2
|
|
delayMicroseconds(delta_tm);
|
|
icnt++;
|
|
}
|
|
} // end gobwd2()
|
|
|
|
void playTrackOnChannel ( byte dtrack) {
|
|
if (dtrack!=255) {Player1.play(dtrack); delay(audiocmddelay); }
|
|
else {Player1.play(random(First_Track,Last_Track+1)); delay(audiocmddelay); }
|
|
} // end playTrackOnChannel()
|
|
|
|
void setVolumeOnChannel ( byte dvolume) {
|
|
if(dvolume>30) return; // Don't change the volume if out of range
|
|
Player1.volume (dvolume);
|
|
delay(audiocmddelay);
|
|
} // end setVolumeOnChannel()
|
|
|
|
void notifyCVChange( uint16_t CV, uint8_t Value) {
|
|
if ( CV== 50 ) {
|
|
Motor1Speed = (Dcc.getCV(50))&0x7f ;
|
|
Motor1ForwardDir = (byte)((Dcc.getCV(50))&0x80 )>>7;
|
|
}
|
|
} // end notifyCVChange()
|
|
|
|
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
|
|
if ( !Use_DCC_speed ) return;
|
|
if ( Dcc.getCV(50) == 0) {
|
|
Motor1Speed = (Speed & 0x7f );
|
|
}
|
|
if (Motor1Speed == 1) Motor1Speed = 0;
|
|
} // end notifyDccSpeed()
|
|
|
|
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
|
|
#ifdef DEBUG
|
|
Serial.print("Addr= ");
|
|
Serial.println(Addr, DEC) ;
|
|
Serial.print("FuncState= ");
|
|
Serial.println(FuncState, DEC) ;
|
|
#endif
|
|
switch(FuncGrp)
|
|
{
|
|
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
|
|
exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 );
|
|
exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01));
|
|
exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1);
|
|
exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 );
|
|
exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 );
|
|
break;
|
|
case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
|
|
exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05));
|
|
exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 );
|
|
//exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 );
|
|
//exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 );
|
|
break;
|
|
|
|
case FN_9_12:
|
|
//exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09));
|
|
//exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 );
|
|
//exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 );
|
|
//exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 );
|
|
break;
|
|
case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control
|
|
//exec_function( 13, FunctionPin13, (FuncState & FN_BIT_13);
|
|
//exec_function( 14, FunctionPin14, (FuncState & FN_BIT_14)>>1;
|
|
//exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 );
|
|
//exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 );
|
|
break;
|
|
|
|
case FN_21_28:
|
|
break;
|
|
}
|
|
} // end notifyDccSpeed()
|
|
|
|
void exec_function (int function, int pin, int FuncState) {
|
|
#ifdef DEBUG
|
|
Serial.print("ex function= ");
|
|
Serial.println(function, DEC) ;
|
|
Serial.print("FuncState= ");
|
|
Serial.println(FuncState, DEC) ;
|
|
#endif
|
|
switch ( Dcc.getCV( 30+function) ) { // Config 0=On/Off,1=Blink
|
|
case 0: // Master Disable Function0 Value will transfer to MasterDecoderDisable in loop()
|
|
Function0_value = byte(FuncState);
|
|
break;
|
|
case 1: // On - Off LED
|
|
if (MasterDecoderDisable == 0) {
|
|
digitalWrite (pin, FuncState);
|
|
}
|
|
break;
|
|
case 2: // Motor2 Control
|
|
if (MasterDecoderDisable == 0) Motor2ON= FuncState;
|
|
break;
|
|
case 3: // NEXT FEATURE for the Future
|
|
break;
|
|
default:
|
|
ftn_queue[function].inuse = 0;
|
|
break;
|
|
}
|
|
} // end exec_function()
|
|
|
|
/* DFPlayer Commands
|
|
//----Set volume----
|
|
myDFPlayer.volume(10); //Set volume value (0~30).
|
|
myDFPlayer.volumeUp(); //Volume Up
|
|
myDFPlayer.volumeDown(); //Volume Down
|
|
//----Set different EQ----
|
|
myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
|
|
// myDFPlayer.EQ(DFPLAYER_EQ_POP);
|
|
// myDFPlayer.EQ(DFPLAYER_EQ_ROCK);
|
|
// myDFPlayer.EQ(DFPLAYER_EQ_JAZZ);
|
|
// myDFPlayer.EQ(DFPLAYER_EQ_CLASSIC);
|
|
// myDFPlayer.EQ(DFPLAYER_EQ_BASS);
|
|
//----Set device we use SD as default----
|
|
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_U_DISK);
|
|
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);
|
|
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_AUX);
|
|
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_SLEEP);
|
|
// myDFPlayer.outputDevice(DFPLAYER_DEVICE_FLASH);
|
|
//----Mp3 control----
|
|
// myDFPlayer.sleep(); //sleep
|
|
// myDFPlayer.reset(); //Reset the module
|
|
// myDFPlayer.enableDAC(); //Enable On-chip DAC
|
|
// myDFPlayer.disableDAC(); //Disable On-chip DAC
|
|
// myDFPlayer.outputSetting(true, 15); //output setting, enable the output and set the gain to 15
|
|
//----Mp3 play----
|
|
myDFPlayer.next(); //Play next mp3
|
|
myDFPlayer.previous(); //Play previous mp3
|
|
myDFPlayer.play(1); //Play the first mp3
|
|
myDFPlayer.loop(1); //Loop the first mp3
|
|
myDFPlayer.pause(); //pause the mp3
|
|
myDFPlayer.start(); //start the mp3 from the pause
|
|
myDFPlayer.playFolder(15, 4); //play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255)
|
|
myDFPlayer.enableLoopAll(); //loop all mp3 files.
|
|
myDFPlayer.disableLoopAll(); //stop loop all mp3 files.
|
|
myDFPlayer.playMp3Folder(4); //play specific mp3 in SD:/MP3/0004.mp3; File Name(0~65535)
|
|
myDFPlayer.advertise(3); //advertise specific mp3 in SD:/ADVERT/0003.mp3; File Name(0~65535)
|
|
myDFPlayer.stopAdvertise(); //stop advertise
|
|
myDFPlayer.playLargeFolder(2, 999); //play specific mp3 in SD:/02/004.mp3; Folder Name(1~10); File Name(1~1000)
|
|
myDFPlayer.loopFolder(5); //loop all mp3 files in folder SD:/05.
|
|
myDFPlayer.randomAll(); //Random play all the mp3.
|
|
myDFPlayer.enableLoop(); //enable loop.
|
|
myDFPlayer.disableLoop(); //disable loop.
|
|
*/
|