39 Commits

Author SHA1 Message Date
Alex Shepherd 4b52381fa4 added RP2040 Pico 16 Servo project 2022-02-28 00:35:59 +13:00
Alex Shepherd 5f1e271f2c added CV Storage EEPROM delayed commit
fixed debug for RP2040
2022-02-28 00:35:14 +13:00
Alex Shepherd 6f91d4f7d4 added wait for USB Device to enumerate to some examples
added CV_MANUFACTURER_START
2022-02-27 18:21:52 +13:00
Alex Shepherd b35c1fbbd0 add .gitignore 2021-09-12 01:23:23 +12:00
Alex Shepherd f59048383f Reworked the handling of Accessory OPS Mode CV writing to handle the difference of 11-bit Basic Extended Commands and 11-bit Signal Commands 2021-09-12 01:22:21 +12:00
Alex Shepherd 6333abf691 made some changes to the handling of Accessory Basic and Extended OPS Mode CV Programming 2021-09-05 00:28:15 +12:00
Alex Shepherd afe488d792 bumbump version to 2.0.10 to force update of Arduino Library Manager Indexer 2021-08-30 22:48:44 +12:00
Alex Shepherd 61a730bf82 unified example folder/sketch name that was detected by the arduino-lint utility 2021-08-30 17:55:25 +12:00
Alex Shepherd b0b27ce0cc bump version to 2.0.9 2021-08-30 14:14:38 +12:00
Alex Shepherd c3dc28479a corrected Fwd/Rev LED logic in NmraDccMultiFunctionMotorDecoder example
added conditional compilation to use the newer Dcc.pin() method that used digitalPinToInterrupt() to determine the Ext Interrupt Number based on Arduino Pin to reduce confusion
2021-08-30 14:11:54 +12:00
Alex Shepherd a05c12ce95 tidied up Ardunio Every and Raspberry Pi Pico attachInterrupt() function calls 2021-07-23 21:38:24 +12:00
Alex Shepherd 0a72fc610b reformatted the NmraDcc.h & NmraDcc.cpp files using the astyle rules in the new file: .astyle as per the PR from David Zuhn (davidzuhn) 2021-05-09 16:56:08 +12:00
Alex Shepherd ad5ce96253 after making a mess of a PR from davidzuhn and not having the git skills to fix it, I've resorted to simply copying the desired files from his PR.
I've excluded his reformatted NmraDcc.h NmraDcc.cpp because there were too many merge conflicts now, so I'll reapply his formatting rules in another commit
2021-05-09 16:51:08 +12:00
Alex Shepherd 1e81b95044 removed incorrect comment about notifyDccAccTurnoutOutput() callback function 2021-05-02 23:06:59 +12:00
Alex Shepherd 84fdf45dce added support for the Arduino AVR Nano Every 2021-05-02 23:02:37 +12:00
Jueff 037070b899 Add support for Raspberry Pico (#56)
* fix ESP32 bug on interrupt reinitialisation

* - add first version of Raspberry Pico support

* - add first version of Raspberry Pico support

* Fix problem with missing type PinStatus
merge changes from master project

* fix encoding issue
2021-04-26 23:33:17 +12:00
Fred eb15c25491 Update NmraDcc.h (#53)
Fix notifyDccAccTurnoutOutput() comments to show this is used when CV29_OUTPUT_ADDRESS_MODE IS set. Add emphasis to this and notifyDccAccTurnoutBoard() similar routine.
2021-04-26 23:32:58 +12:00
Alex Shepherd 681b362811 Added MACROs CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB and CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB to correctly compute the DCC Address for CV storage
Corrected bug:  ESP32 version stops working when loosing interupts or signal is bad (#48)
bumped version to 2.0.7
2021-04-04 14:01:35 +12:00
Geoff Bunza f5d7e9b8c3 Gbidec (#44)
* Create IDEC

* Delete IDEC

* Add files via upload

* Add files via upload
2020-11-20 12:10:19 +13:00
Alex Shepherd 7e3b3e3469 Changed how INPUT_PULLUP is done to be compatibile with ESP32
Bumped version to 2.0.6
2020-10-20 09:42:00 +13:00
Alex Shepherd a09c6b1002 bumped NMRADCC_VERSION to 205 2020-06-02 09:50:12 +12:00
Alex Shepherd 29bc2aa1c0 default to DISABLE_OUTPUTS_IDLE uncommented 2020-06-01 19:04:56 +12:00
Alex Shepherd 3abb683d8d improved DCCInterface_TurntableControl example to:
- Added selectable Movement Strategy: Positive Direction Only, Negative Direction Only, Shortest Distance
- Made Disabling Output on Idle optional
2020-06-01 18:49:00 +12:00
Alex Shepherd f3da07c739 added Franz-Peter's changes to pass NMRA Tests ( always search for preamble ) 2020-05-31 20:14:28 +12:00
Alex Shepherd dead808af2 added work-around for ATtiny1614 range of chips that have a bug in: eeprom_is_ready() 2020-05-30 16:14:27 +12:00
Alex Shepherd 38194c0148 Correct the inconsistent license text in the source files to be the Lesser GPL as was intended by the LICENSE file and the repo classification 2020-02-03 22:16:00 +13:00
Alex Shepherd 7819716ac0 manually merged in Franz-Peter's changes as his PR#30 pull-request had too many differences to merge once I'd already solved the advancedAck issue.
This commit contains the remaining relevant changes after doing a manual diff of the library files
2020-01-10 17:33:09 +13:00
Alex Shepherd 5349a21e2e fix bug caused when AdvancedCVAck logic was added as the CV Programming code was shared between Service Mode and Ops Mode programming. 2020-01-10 15:30:30 +13:00
Alex Shepherd 36418f4d66 fixed a bug with the Extended DCC Packet Decoder Reset command was only handling the Hard Reset but not the Soft Reset 2019-11-23 14:25:28 +13:00
Alex Shepherd a8081526ba Merge commit '71bb657e3a7d80edc096094564f5d279e8a1fb69'
* commit '71bb657e3a7d80edc096094564f5d279e8a1fb69':
  Esp32 iram attr (#26)

The merge adds extra STM32 handling

Als manually resolved the conflict around the type for lastMicros, to now be:

	    static unsigned int  lastMicros = 0;

Howefully this does the right thing on each platform
2019-10-28 18:58:02 +13:00
Alex Shepherd 7063e4e7e7 Merge branch 'master' of https://github.com/mrrwa/NmraDcc
* 'master' of https://github.com/mrrwa/NmraDcc:
  Update NmraDcc.cpp
  Update NmraDcc.cpp (#28)
2019-08-19 19:08:28 +12:00
Alex Shepherd d8fb99ed91 Update NmraDcc.cpp
Added some more comments to the ServiceMode programming DCC Packet comparison logic
2019-08-19 19:04:51 +12:00
Roeland 794128fe4b Update NmraDcc.cpp (#28)
Changed the Service Mode duplicate packet comparison to only compare the packet Size and  Data fields and ignore the number of Preamble bits as some command stations appear to send different numbers of preamble bits for otherwise duplicated packets, so we detecting the required two identical packets in sequence and performing the ServiceMode Operation
2019-08-19 18:59:29 +12:00
Alex Shepherd 1542a6fe6c Merge branch 'AdvancedCVAck'
* AdvancedCVAck:
  corrected method description
  split out ServiceMode ackCV from Ops Mode AdvancedCVAck as doing a ackCV in Ops Mode is wrong and adds 6ms busy delay add cache of CV29 value
2019-08-09 08:20:45 +12:00
Alex Shepherd 828b1feaba corrected method description 2019-08-09 08:19:53 +12:00
Bob Jacobsen 462025b9fe Comment update (#27)
Incredibly trivial update to comment noticed while reading code.
2019-08-06 09:10:21 +12:00
Franz-Peter 71bb657e3a Esp32 iram attr (#26)
* changed the version to 201 in the header

* added conditional compilation for ESP8266 to add ICACHE_RAM_ATTR to ExternalInterruptHandler
changed storage for Micros to unsigned long

* some tuning to bit recognition and nested IRQ (STM32)
2019-08-06 01:14:58 +12:00
Alex Shepherd f3a2b87693 split out ServiceMode ackCV from Ops Mode AdvancedCVAck as doing a ackCV in Ops Mode is wrong and adds 6ms busy delay
add cache of CV29 value
2019-08-06 00:22:04 +12:00
Alex Shepherd e06f6b3bce bumped version to 2.0.2 2019-08-05 21:34:48 +12:00
39 changed files with 23475 additions and 1896 deletions
+55
View File
@@ -0,0 +1,55 @@
# http://astyle.sourceforge.net/astyle.html#_style=allman
# use the allman style for braces
--style=allman
# http://astyle.sourceforge.net/astyle.html#_lineend
# newlines for all line endings
--lineend=linux
# http://astyle.sourceforge.net/astyle.html#_indent=spaces
# 4 space indents
--indent=spaces=4
# http://astyle.sourceforge.net/astyle.html#_add-braces
# don't leave any unbraced one-line blocks by changing:
# if (thing)
# statement;
#
# to
# if (thing)
# {
# statement;
# }
#
# --add-braces
# http://astyle.sourceforge.net/astyle.html#_indent-preproc-cond
# line up #if/#endif with the code
#
# statement;
# #if SOMETHING
# statement;
# #endif
#
--indent-preproc-cond
# http://astyle.sourceforge.net/astyle.html#_indent-preproc-block
# indent top level preprocessor block contents
#
# #ifdef __ARDUINO__
# #include "Arduino.h"
# #endif
#
--indent-preproc-block
# normalize spacing around parenthese
# http://astyle.sourceforge.net/astyle.html#_unpad-paren
# first, remove all whitespace on either side of a paren
--unpad-paren
# http://astyle.sourceforge.net/astyle.html#_pad-paren-out
# then add a space on the "outer" side of a paren
--pad-paren-out
# http://astyle.sourceforge.net/astyle.html#_max-code-length
# we've got big monitors these days....
--max-code-length=180
+5
View File
@@ -0,0 +1,5 @@
.development
*.zip
*.orig
*~
*.txt
+1374 -1108
View File
File diff suppressed because it is too large Load Diff
+771 -721
View File
File diff suppressed because it is too large Load Diff
+11
View File
@@ -10,3 +10,14 @@ The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 and T
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State )
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State)
Developers:
Use of the supplied git pre-commit hook is encouraged. This will require installation of the 'astyle' package for formatting source file.
See http://astyle.sourceforge.net for details on this package.
On Linux or Mac development machines, run the following command after you clone the repository:
ln -s support/pre-commit .git/hooks/pre-commit
Reformatting the source code to the preferred style is easy using astyle. Just run 'astyle --options=.astylerc NmraDcc.h NmraDcc.cpp'
@@ -1,8 +1,8 @@
// DCC Stepper Motor Controller ( A4988 ) Example for Model Railroad Turntable Control
//
// See: https://www.dccinterface.com/how-to/assemblyguide/
// See: https://www.dccinterface.com/product/arduino-model-railway-dcc-stepper-motor-controller-a4988-assembled/
//
// Author: Alex Shepherd 2017-12-04
// Author: Alex Shepherd 2020-06-01
//
// This example requires two Arduino Libraries:
//
@@ -19,15 +19,28 @@
#include <AccelStepper.h>
#include <NmraDcc.h>
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
// The lines below define the pins used to connect to the A4988 driver module
#define A4988_STEP_PIN 4
#define A4988_DIRECTION_PIN 5
// Uncomment the next line to enable Powering-Off the Stepper when its not running to reduce heating the motor and driver
#define A4988_ENABLE_PIN 6
#ifdef A4988_ENABLE_PIN
// Uncomment the next line to enable Powering-Off the Stepper when its not running to reduce heating the motor and driver
#define DISABLE_OUTPUTS_IDLE
#endif
// By default the stepper motor will move the shortest distance to the desired position.
// If you need the turntable to only move in the Positive/Increasing or Negative/Decreasing step numbers to better handle backlash in the mechanism
// Then uncomment the appropriate line below
//#define ALWAYS_MOVE_POSITIVE
//#define ALWAYS_MOVE_NEGATIVE
// The lines below define the stepping speed and acceleration, which you may need to tune for your application
#define STEPPER_MAX_SPEED 800 // Sets the maximum permitted speed
#define STEPPER_ACCELARATION 1000 // Sets the acceleration/deceleration rate
#define STEPPER_ACCELARATION 1000 // Sets the acceleration/deceleration rate
#define STEPPER_SPEED 300 // Sets the desired constant speed for use with runSpeed()
// The line below defines the number of "Full Steps" your stepper motor does for a full rotation
@@ -92,6 +105,9 @@ TurnoutPosition turnoutPositions[] = {
// --------------------------------------------------------------------------------------------
// You shouldn't need to edit anything below this line unless you're needing to make big changes... ;)
// --------------------------------------------------------------------------------------------
#if defined(ALWAYS_MOVE_POSITIVE) && defined(ALWAYS_MOVE_NEGATIVE)
#error ONLY uncomment one of ALWAYS_MOVE_POSITIVE or ALWAYS_MOVE_NEGATIVE but NOT both
#endif
#define MAX_TURNOUT_POSITIONS (sizeof(turnoutPositions) / sizeof(TurnoutPosition))
@@ -104,11 +120,12 @@ NmraDcc Dcc ;
// Variables to store the last DCC Turnout message Address and Direction
uint16_t lastAddr = 0xFFFF ;
uint8_t lastDirection = 0xFF;
int lastStep = 0;
// This function is called whenever a normal DCC Turnout Packet is received
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
{
Serial.print("notifyDccAccTurnoutOutput: ") ;
Serial.print(F("notifyDccAccTurnoutOutput: "));
Serial.print(Addr,DEC) ;
Serial.print(',');
Serial.print(Direction,DEC) ;
@@ -131,23 +148,50 @@ void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t Output
#ifdef A4988_ENABLE_PIN
stepper1.enableOutputs();
#endif
if (Direction)
{
Serial.println(turnoutPositions[i].positionFront, DEC);
stepper1.moveTo(turnoutPositions[i].positionFront);
break;
}
int newStep;
if(Direction)
newStep = turnoutPositions[i].positionFront;
else
{
Serial.println(turnoutPositions[i].positionBack, DEC);
stepper1.moveTo(turnoutPositions[i].positionBack);
break;
}
newStep = turnoutPositions[i].positionBack;
Serial.print(newStep, DEC);
Serial.print(F(" Last Step: "));
Serial.print(lastStep, DEC);
int diffStep = newStep - lastStep;
Serial.print(F(" Diff Step: "));
Serial.print(diffStep, DEC);
#if defined ALWAYS_MOVE_POSITIVE
Serial.print(F(" Positive"));
if(diffStep < 0)
diffStep += FULL_TURN_STEPS;
#elif defined ALWAYS_MOVE_NEGATIVE
Serial.print(F(" Negative"));
if(diffStep > 0)
diffStep -= FULL_TURN_STEPS;
#else
if(diffStep > HALF_TURN_STEPS)
diffStep = diffStep - FULL_TURN_STEPS;
else if(diffStep < -HALF_TURN_STEPS)
diffStep = diffStep + FULL_TURN_STEPS;
#endif
Serial.print(F(" Move: "));
Serial.println(diffStep, DEC);
stepper1.move(diffStep);
lastStep = newStep;
break;
}
}
};
#ifdef A4988_ENABLE_PIN
#ifdef DISABLE_OUTPUTS_IDLE
bool lastIsRunningState ;
#endif
@@ -161,8 +205,12 @@ void setupStepperDriver()
stepper1.setMaxSpeed(STEPPER_MAX_SPEED); // Sets the maximum permitted speed
stepper1.setAcceleration(STEPPER_ACCELARATION); // Sets the acceleration/deceleration rate
stepper1.setSpeed(STEPPER_SPEED); // Sets the desired constant speed for use with runSpeed()
#ifdef A4988_ENABLE_PIN
stepper1.enableOutputs();
#endif
#ifdef DISABLE_OUTPUTS_IDLE
lastIsRunningState = stepper1.isRunning();
#endif
}
@@ -173,14 +221,19 @@ bool moveToHomePosition()
pinMode(HOME_SENSOR_PIN, INPUT_PULLUP);
#ifdef ALWAYS_MOVE_NEGATIVE
stepper1.move(0 - (FULL_TURN_STEPS * 2));
#else
stepper1.move(FULL_TURN_STEPS * 2);
#endif
while(digitalRead(HOME_SENSOR_PIN) != HOME_SENSOR_ACTIVE_STATE)
stepper1.run();
if(digitalRead(HOME_SENSOR_PIN) == HOME_SENSOR_ACTIVE_STATE)
{
Serial.println(F("Found Home Position - Setting Current Position to 0"));
stepper1.stop();
stepper1.setCurrentPosition(0);
Serial.println(F("Found Home Position - Setting Current Position to 0"));
return true;
}
else
@@ -193,8 +246,14 @@ void setupDCCDecoder()
{
Serial.println(F("Setting up DCC Decorder..."));
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 1);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
@@ -210,28 +269,32 @@ void setup()
Serial.print(F("Full Rotation Steps: "));
Serial.println(FULL_TURN_STEPS);
Serial.print(F("Movement Strategy: "));
#if defined ALWAYS_MOVE_POSITIVE
Serial.println(F("Positive Direction Only"));
#elif defined ALWAYS_MOVE_NEGATIVE
Serial.println(F("Negative Direction Only"));
#else
Serial.println(F("Shortest Distance"));
#endif
for(uint8_t i = 0; i < MAX_TURNOUT_POSITIONS; i++)
{
Serial.print("DCC Addr: ");
Serial.print(F("DCC Addr: "));
Serial.print(turnoutPositions[i].dccAddress);
Serial.print(" Front: ");
Serial.print(F(" Front: "));
Serial.print(turnoutPositions[i].positionFront);
Serial.print(" Back: ");
Serial.print(F(" Back: "));
Serial.println(turnoutPositions[i].positionBack);
}
setupStepperDriver();
if(moveToHomePosition());
{
setupDCCDecoder();
#ifdef A4988_ENABLE_PIN
stepper1.enableOutputs();
#endif
// Fake a DCC Packet to cause the Turntable to move to Position 1
notifyDccAccTurnoutOutput(POSITION_01_DCC_ADDRESS, 1, 1);
}
@@ -245,7 +308,7 @@ void loop()
// Process the Stepper Library
stepper1.run();
#ifdef A4988_ENABLE_PIN
#ifdef DISABLE_OUTPUTS_IDLE
if(stepper1.isRunning() != lastIsRunningState)
{
lastIsRunningState = stepper1.isRunning();
@@ -0,0 +1,765 @@
// 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.
*/
@@ -0,0 +1,264 @@
// Interactive Decoder Random Building Lighting DCC Decoder IDEC2_1_Building.ino
// Version 1.08 Geoff Bunza 2020
// Works with both short and long DCC Addesses
// This decoder will control Random Building Lighting
// F0=Master Function OFF = Function ON DISABLES the decoder
// Input Pin for Decoder Disable Pin 3 Active LOW
/*
F0 == Master Decoder Disable
PRO MINI PIN ASSIGNMENT:
2 - DCC Input
3 - Input Pin for MasterDecoderDisable Active LOW
4 - LED
5 - LED
6 - LED
7 - LED
8 - LED
9 - LED
10 - LED
11 - LED
12 - LED
13 - LED
14 A0 - LED
15 A1 - LED
16 A2 - LED
17 A3 - LED
18 A4 - LED
19 A5 - LED
*/
// ******** 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>
#define runEvery(t) for (static typeof(t) _lasttime;\
(typeof(t))((typeof(t))millis() - _lasttime) > (t);\
_lasttime += (t))
int master_tim_delay = 100;
long delta = 0;
int tctr, tctr2, i;
int numleds = 16; // Number of Output pins to initialize
int num_active_functions = 1; // Number of Functions stating with F0
byte fpins [] = {4,5,6,7,8,9,10,11,12,13,54,55,56,57,58,59}; //These are all the Output Pins
const int MasterDecoderDisablePin = 3; // D3 Master Decoder Disable Input Pin Active LOW
const int FunctionPin0 = 20; // Input Master Pin Disable Active LOW {;aceholder
const int FunctionPin1 = 20; // A0 LED
const int FunctionPin2 = 20; // A1 LED
const int FunctionPin3 = 20; // A2 LED
const int FunctionPin4 = 20; //A3 LED
const int FunctionPin5 = 20; //A4 LED
const int FunctionPin6 = 20; //A5 LED
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 ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[3];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define This_Decoder_Address 24
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
{50, 90}, // Master Building Time Delay 0-255 255=Slowest
{51, 0}, //
{52, 0}, //
};
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
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 < numleds; i++) {
pinMode(fpins[i], OUTPUT);
digitalWrite(fpins[i], 0); // All OUPUT pins initialized LOW
}
for (int i=0; i< numleds; i++) { //As a test turn all ON in sequence
digitalWrite(fpins[i], HIGH);
delay (60);
}
delay(400);
for (int i=0; i< numleds; i++) { //Now turn all OFF in sequence
digitalWrite(fpins[i], LOW);
delay (60);
}
// 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, 601, 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);
digitalWrite(fpins[10], 1);
delay (500);
digitalWrite(fpins[10], 0);
}
for ( i=0; i < num_active_functions; i++) {
cv_value = Dcc.getCV(30+i) ;
#ifdef DEBUG
Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
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:
break;
case 3: // NEXT FEATURE for the Future
break;
default:
break;
}
}
master_tim_delay = int(Dcc.getCV(50)) * 11 ;
delta = millis() + master_tim_delay;
} // end setup
// ================================================================
void loop()
{
//MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation
Dcc.process();
delay(1);
// INPUT OVER RIDE
// Check Master Input Over ride
MasterDecoderDisable = 0;
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
else MasterDecoderDisable = Function0_value & 1;
runEvery(master_tim_delay) digitalWrite(fpins [random (0,numleds)], lightsw() );
} //end loop
boolean lightsw() {
if (MasterDecoderDisable == 1) return LOW; //Eventually turn all lights OFF
if (random(0,100)>48) return HIGH; //48 represents a 52% ON time
else return LOW;
} // end lightsw
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 notifyDccFunc
void exec_function (int function, int pin, int FuncState) {
#ifdef DEBUG
Serial.print("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 = byte(FuncState);
break;
case 1: // NEXT FEATURE for the Future
break;
default:
break;
}
} // end exec_function
@@ -0,0 +1,301 @@
// Interactive Decoder Random Building Lighting DCC Decoder IDEC2_2_Building1Wldr.ino
// Version 1.08 Geoff Bunza 2020
// Works with both short and long DCC Addesses
// This decoder will control Random Building Lighting
// F0=Master Function OFF = Function ON DISABLES the decoder
// Input Pin for Decoder Disable Pin 3 Active LOW
/*
F0 == Master Decoder Disable == ON
F1 == Welder 1 Disable == ON
PRO MINI PIN ASSIGNMENT:
2 - DCC Input
3 - Input Pin for MasterDecoderDisable Active LOW
4 - LED Blue Welder1
5 - LED White Welder1
6 - LED
7 - LED
8 - LED
9 - LED
10 - LED
11 - LED
12 - LED
13 - LED
14 A0 - LED
15 A1 - LED
16 A2 - LED
17 A3 - LED
18 A4 - LED
19 A5 - LED
*/
// ******** 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>
#define runEvery(t) for (static typeof(t) _lasttime;\
(typeof(t))((typeof(t))millis() - _lasttime) > (t);\
_lasttime += (t))
int building_tim_delay;
int welder1_tim_delay;
byte welder1_on = 0;
int welder1_delta;
long delta = 0;
int tctr, tctr2, i;
int numleds = 16; // Number of Output pins to initialize
int num_active_functions = 2; // Number of Functions stating with F0
byte fpins [] = {4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; //These are all the Output Pins
const int MasterDecoderDisablePin = 3; // D3 Master Decoder Disable Input Pin Active LOW
const int Welder1BluePin = 4; // Blue LED simulation Welder 1
const int Welder1WhitePin = 5; // White LED simulation Welder 1
const int FunctionPin0 = 20; // Input Master Pin Disable Active LOW {;aceholder
const int FunctionPin1 = 20; // A0 LED
const int FunctionPin2 = 20; // A1 LED
const int FunctionPin3 = 20; // A2 LED
const int FunctionPin4 = 20; //A3 LED
const int FunctionPin5 = 20; //A4 LED
const int FunctionPin6 = 20; //A5 LED
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 MasterDisable_value = 0;
int Disable_welder1 = 0;
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[3];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define This_Decoder_Address 24
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=Disable Welder 1,2=Deisable Welder2
{31, 1}, // F1 Config 0=DISABLE On/Off,1=Disable Welder 1,2=Deisable Welder2
{50, 90}, // Master Building Time Delay 0-255 255=Slowest
{51, 127}, // Welder1 Time Constant
{52, 0}, // Extra
{53, 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
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 < numleds; i++) {
pinMode(fpins[i], OUTPUT);
digitalWrite(fpins[i], 0); // All OUPUT pins initialized LOW
}
for (int i=0; i< numleds; i++) { //As a test turn all ON in sequence
digitalWrite(fpins[i], HIGH);
delay (60);
}
delay(400);
for (int i=0; i< numleds; i++) { //Now turn all OFF in sequence
digitalWrite(fpins[i], LOW);
delay (60);
}
// 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, 601, 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);
digitalWrite(fpins[10], 1);
delay (500);
digitalWrite(fpins[10], 0);
}
for ( i=0; i < num_active_functions; i++) {
cv_value = Dcc.getCV(30+i) ;
#ifdef DEBUG
Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) {
case 0: // Master Decoder Disable
MasterDecoderDisable = 0;
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
break;
case 1: // F1 Disables Welder 1
Disable_welder1 = 0; // Initialized
break;
case 2:
break;
case 3: // NEXT FEATURE for the Future
break;
default:
break;
}
}
building_tim_delay = int(Dcc.getCV(50)) * 11 ;
welder1_tim_delay = int(Dcc.getCV(51)) * 21 ;
} // end setup
// ================================================================
void loop()
{
//MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation
Dcc.process();
delay(1);
// INPUT OVER RIDE // Check Master Input Over ride
MasterDecoderDisable = 0;
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
else MasterDecoderDisable = MasterDisable_value & 1;
// Random Building Lights
runEvery(building_tim_delay) digitalWrite(fpins[random (2,numleds)], lightsw() );
// Welder1
if ((MasterDecoderDisable == 0)&&(Disable_welder1==0)) {
runEvery(welder1_tim_delay) {welder1_on = random(20,50); welder1_delta=random(23,133); }
}
runEvery(welder1_delta) digitalWrite(Welder1WhitePin,run_welder1_wsw() );
runEvery(welder1_delta) digitalWrite(Welder1BluePin,run_welder1_bsw() );
} //end loop
boolean run_welder1_wsw() {
if ((MasterDecoderDisable == 1)||(welder1_on<=0)) return LOW; //Eventually turn all lights OFF
welder1_on--;
if (random(0,100)>48) return HIGH; //48 represents a 52% ON time
else return LOW;
} // end run_welder1_wsw
boolean run_welder1_bsw() {
if ((MasterDecoderDisable == 1)||(welder1_on<=0)) return LOW; //Eventually turn all lights OFF
welder1_on--;
if (random(0,100)>35) return HIGH; //35 represents a 65% ON time
else return LOW;
} // end run_welder1_bsw
boolean lightsw() {
if (MasterDecoderDisable == 1) return LOW; //Eventually turn all lights OFF
if (random(0,100)>40) return HIGH; //40 represents a 60% ON time
else return LOW;
} // end lightsw
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 notifyDccFunc
void exec_function (int function, int pin, int FuncState) {
#ifdef DEBUG
Serial.print("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 by Function 0
MasterDisable_value = byte(FuncState);
break;
case 1: // Master Disable by Function 1
Disable_welder1 = byte(FuncState);
break;
case 2: // Next Features
break;
default:
break;
}
} // end exec_function
@@ -0,0 +1,344 @@
// Interactive Decoder Random Building Lighting DCC Decoder IDEC2_3_Building2Wldrs.ino
// Version 1.08 Geoff Bunza 2020
// Works with both short and long DCC Addesses
// This decoder will control Random Building Lighting
// F0=Master Function OFF = Function ON DISABLES the decoder
// Input Pin for Decoder Disable Pin 3 Active LOW
/*
F0 == Master Decoder Disable == ON
F1 == Welder 1 Disable == ON
F2 == Welder 2 Disable == ON
PRO MINI PIN ASSIGNMENT:
2 - DCC Input
3 - Input Pin for MasterDecoderDisable Active LOW
4 - LED Blue Welder1
5 - LED White Welder1
6 - LED Blue Welder2
7 - LED White Welder2
8 - LED
9 - LED
10 - LED
11 - LED
12 - LED
13 - LED
14 A0 - LED
15 A1 - LED
16 A2 - LED
17 A3 - LED
18 A4 - LED
19 A5 - LED
*/
// ******** 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>
#define runAfter(t) for (static unsigned long _dTimer=millis();\
(unsigned long)(millis()-_dTimer)>=(t);\
_dTimer = millis())
#define runAfterOnce(t) for (static unsigned long _dTimer=millis();\
(unsigned long)(millis()-_dTimer)*estop>=(t);\
_dTimer = millis())
#define runEvery(t) for (static typeof(t) _lasttime;\
(typeof(t))((typeof(t))millis() - _lasttime) >= (t);\
_lasttime += (t))
unsigned long estop = 1;
int building_tim_delay;
int welder1_tim_delay;
int welder2_tim_delay;
byte welder1_on = 0;
byte welder2_on = 0;
int welder1_delta;
int welder2_delta;
long delta = 0;
int tctr, tctr2, i;
int numleds = 16; // Number of Output pins to initialize
int num_active_functions = 3; // Number of Functions stating with F0
byte fpins [] = {4,5,6,7,8,9,10,11,12,13,54,55,56,57,58,59}; //These are all the Output Pins
const int MasterDecoderDisablePin = 3; // D3 Master Decoder Disable Input Pin Active LOW
const int Welder1BluePin = 4; // Blue LED simulation Welder 1
const int Welder1WhitePin = 5; // White LED simulation Welder 1
const int Welder2BluePin = 6; // Blue LED simulation Welder 2
const int Welder2WhitePin = 7; // White LED simulation Welder 2
const int FunctionPin0 = 20; // Input Master Pin Disable Active LOW {;aceholder
const int FunctionPin1 = 20; // A0 LED
const int FunctionPin2 = 20; // A1 LED
const int FunctionPin3 = 20; // A2 LED
const int FunctionPin4 = 20; //A3 LED
const int FunctionPin5 = 20; //A4 LED
const int FunctionPin6 = 20; //A5 LED
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 MasterDisable_value = 0;
int Disable_welder1 = 0;
int Disable_welder2 = 0;
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[3];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define This_Decoder_Address 24
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=Disable Welder 1,2=Deisable Welder2
{31, 1}, // F1 Config 0=DISABLE On/Off,1=Disable Welder 1,2=Deisable Welder2
{32, 2}, // F2 Config 0=DISABLE On/Off,1=Disable Welder 1,2=Deisable Welder2
{50, 90}, // Master Building Time Delay 0-255 255=Slowest
{51, 127}, // Welder1 Time Constant
{52, 147}, // Welder2 Time Constant
{53, 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
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 < numleds; i++) {
pinMode(fpins[i], OUTPUT);
digitalWrite(fpins[i], 0); // All OUPUT pins initialized LOW
}
for (int i=0; i< numleds; i++) { //As a test turn all ON in sequence
digitalWrite(fpins[i], HIGH);
delay (60);
}
delay(400);
for (int i=0; i< numleds; i++) { //Now turn all OFF in sequence
digitalWrite(fpins[i], LOW);
delay (60);
}
// 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, 601, 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);
digitalWrite(fpins[10], 1);
delay (500);
digitalWrite(fpins[10], 0);
}
for ( i=0; i < num_active_functions; i++) {
cv_value = Dcc.getCV(30+i) ;
#ifdef DEBUG
Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) {
case 0: // Master Decoder Disable
MasterDecoderDisable = 0;
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
break;
case 1: // F1 Disables Welder 1
Disable_welder1 = 0; // Initialized
break;
case 2: // F2 Disables Welder 2
Disable_welder2 = 0; // Initialized
break;
case 3: // NEXT FEATURE for the Future
break;
default:
break;
}
}
building_tim_delay = int(Dcc.getCV(50)) * 11 ;
welder1_tim_delay = int(Dcc.getCV(51)) * 21 ;
welder2_tim_delay = int(Dcc.getCV(52)) * 21 ;
} // end setup
// ================================================================
void loop()
{
//MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation
Dcc.process();
delay(1);
// INPUT OVER RIDE // Check Master Input Over ride
MasterDecoderDisable = 0;
if (digitalRead(MasterDecoderDisablePin)==LOW) MasterDecoderDisable = 1;
else MasterDecoderDisable = MasterDisable_value & 1;
// Random Building Lights
runEvery(building_tim_delay) digitalWrite(fpins[random (4,numleds)], lightsw() );
// Welder1
if ((MasterDecoderDisable == 0)&&(Disable_welder1==0)) {
runEvery(welder1_tim_delay) {welder1_on = random(20,50); welder1_delta=random(23,133); }
}
runEvery(welder1_delta) digitalWrite(Welder1WhitePin,run_welder1_wsw() );
runEvery(welder1_delta) digitalWrite(Welder1BluePin,run_welder1_bsw() );
// Welder2
if ((MasterDecoderDisable == 0)&&(Disable_welder2==0)) {
runEvery(welder2_tim_delay) {welder2_on = random(25,47); welder2_delta=random(22,125); }
}
runEvery(welder2_delta) digitalWrite(Welder2WhitePin,run_welder2_wsw() );
runEvery(welder2_delta) digitalWrite(Welder2BluePin,run_welder2_bsw() );
} //end loop
boolean run_welder1_wsw() {
if ((MasterDecoderDisable == 1)||(welder1_on<=0)) return LOW; //Eventually turn all lights OFF
welder1_on--;
if (random(0,100)>48) return HIGH; //48 represents a 52% ON time
else return LOW;
} // end run_welder1_wsw
boolean run_welder1_bsw() {
if ((MasterDecoderDisable == 1)||(welder1_on<=0)) return LOW; //Eventually turn all lights OFF
welder1_on--;
if (random(0,100)>35) return HIGH; //35 represents a 65% ON time
else return LOW;
} // end run_welder1_bsw
boolean run_welder2_wsw() {
if ((MasterDecoderDisable == 1)||(welder2_on<=0)) return LOW; //Eventually turn all lights OFF
welder2_on--;
if (random(0,100)>48) return HIGH; //48 represents a 52% ON time
else return LOW;
} // end run_welder2_wsw
boolean run_welder2_bsw() {
if ((MasterDecoderDisable == 1)||(welder2_on<=0)) return LOW; //Eventually turn all lights OFF
welder2_on--;
if (random(0,100)>35) return HIGH; //35 represents a 65% ON time
else return LOW;
} // end run_welder2_bsw
boolean lightsw() {
if (MasterDecoderDisable == 1) return LOW; //Eventually turn all lights OFF
if (random(0,100)>40) return HIGH; //40 represents a 60% ON time
else return LOW;
} // end lightsw
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 notifyDccFunc
void exec_function (int function, int pin, int FuncState) {
#ifdef DEBUG
Serial.print("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 by Function 0
MasterDisable_value = byte(FuncState);
break;
case 1: // Master Disable by Function 1
Disable_welder1 = byte(FuncState);
break;
case 2: // Master Disable by Function 1
Disable_welder2 = byte(FuncState);
break;
case 3: // Next Features
break;
default:
break;
}
} // end exec_function
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
@@ -0,0 +1,735 @@
// 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
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE PAUSE 1 SENSOR
//#define Pause1
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE PAUSE 2 SENSOR
//#define Pause2
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE REVERSE 1 SENSOR
#define Reverse1
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE REVERSE 2 SENSOR
//#define Reverse2
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE IMMEDIATE STOP SENSOR
//#define ImmediateStop
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE IMMEDIATE START SENSOR
//#define ImmediateStart
#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
uint16_t ttemp, i;
#define First_Track 1 // Play Random Tracks First_Track#=Start_Track >=1
#define Last_Track 2 // Play Random Tracks Last_Track= Last Playable Track in Range <= Last Numbered Track
#define starting_volume 22 // If no volume is set use this at the start
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 cyclewidth = 8192;
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 ThrottleInputReverse1Pin = 7; // Throttle Speed Reverse Input Pin
const int ThrottleInputReverse2Pin = 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, 0}, // ThrottlePause1 Pause Time 0-255 (0.1 secs)
{52, 0}, // ThrottlePause1 Throttle Ramp DOWN Delay 0-255 Larger Delay=Slower Ramp Down
{53, 0}, // ThrottlePause1 Throttle Ramp UP Delay 0-255 Larger Delay=Slower Ramp Up
{54, 11}, // ThrottlePause1 Pause Sound Clip 1-nn 0=No Sound
{55, 55}, // ThrottlePause1 Pause Sound Clip Volume 0-30
{56, 0}, // ThrottlePause2 Pause Time 0-255 (0.1 secs)
{57, 0}, // ThrottlePause2 Throttle Ramp DOWN 0-255 Delay
{58, 0}, // ThrottlePause2 Throttle Ramp UP Delay 0-255
{59, 11}, // ThrottlePause2 Pause Sound Clip 1-nn 0=No Sound
{60, 55}, // ThrottlePause2 Pause Sound Clip Volume 0-30
{61, 0}, // ThrottleInputReverse1 Pause Time 0-255 (0.1 secs)
{62, 0}, // ThrottleInputReverse1 Ramp DOWN Delay 0-255
{63, 0}, // ThrottleInputReverse1 Ramp UP Delay 0-255
{64, 11}, // ThrottleInputReverse1 Sound Clip 1-nn 0=No Sound
{65, 55}, // ThrottleInputReverse1 Sound Clip Volume 0-30
{66, 0}, // ThrottleInputReverse2 Pause Time 0-255 (0.1 secs)
{67, 0}, // ThrottleInputReverse2 Ramp DOWN Delay 0-255
{68, 0}, // ThrottleInputReverse2 Ramp UP Delay 0-255
{69, 11}, // ThrottleInputReverse2 Sound Clip 1-nn 0=No Sound
{70, 55}, // ThrottleInputReverse2 Sound Clip Volume 0-30
{71, 0}, // ThrottleImmediateStop Sound Clip 1-nn 0=No Sound
{72, 55}, // ThrottleImmediateStop Sound Clip Volume 0-30
{73, 0}, // ThrottleImmediateStart Sound Clip 1-nn 0=No Sound
{74, 55}, // ThrottleImmediateStart Sound Clip Volume 0-30
{80, 0}, // 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 (ThrottleInputReverse1Pin,INPUT_PULLUP); // Throttle Speed Reverse Input Pin 1 Active LOW
pinMode (ThrottleInputReverse2Pin,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;
}
}
setVolumeOnChannel (starting_volume);
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; }
#ifdef Pause1
// ======== 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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottlePause1Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef Pause2
// ======== 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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottlePause2Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef Reverse1
// ======== Throttle Reverse 1 ========================
if (digitalRead(ThrottleInputReverse1Pin)==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;
if (Dcc.getCV(62)!=0) delay(Dcc.getCV(62)); //Throttle Ramp DOWN Delay 0-255
else Motor1Speed=0;
}
//Motor1Speed = 0;
ttemp=(Dcc.getCV(64));
if (ttemp!=0) {setVolumeOnChannel (Dcc.getCV(65)); 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();
if (Dcc.getCV(63)!=0) delay(Dcc.getCV(63)); //Throttle Ramp UP Delay 0-255
else Motor1Speed=Starting_Motor1Speed;
}
//Motor1Speed = Starting_Motor1Speed;
for (i=0; i<10; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottleInputReverse1Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true;
}
#endif
#ifdef Reverse2
// ======== Throttle Reverse 2 ========================
if (digitalRead(ThrottleInputReverse2Pin)==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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottleInputReverse2Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef ImmediateStop
// ======== 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
}
#endif
#ifdef ImmediateStart
// ======== 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
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ImmediateStartPin) == LOW) run_at_speed(); //Wait for Sensor
}
#endif
// ********************************************************************************
for (int i=1; 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 (Motor2Speed<<4);
else gobwd2 (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;
}
run_at_speed();
}
} // end loop()
void run_at_speed() {
Dcc.process();
if (MasterDecoderDisable == 0) {
if (Motor1Speed != 0) {
if (Motor1ForwardDir == 0) gofwd1 (Motor1Speed<<6);
else gobwd1 (Motor1Speed<<6);
}
}
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 (Motor2Speed<<6);
else gobwd2 (Motor2Speed<<6);
}
} // end run_at_speed()
void gofwd1(int fcycle) {
digitalWrite(m2h, HIGH); //Motor1
delayMicroseconds(fcycle);
digitalWrite(m2h, LOW); //Motor1
delayMicroseconds(cyclewidth-fcycle);
} // end gofwd1()
void gobwd1(int bcycle) {
digitalWrite(m2l, HIGH); //Motor1
delayMicroseconds(bcycle);
digitalWrite(m2l, LOW); //Motor1
delayMicroseconds(cyclewidth-bcycle);
} // end gobwd1()
void gofwd2(int fcycle) {
digitalWrite(m0h, HIGH); //Motor2
delayMicroseconds(fcycle);
digitalWrite(m0h, LOW); //Motor2
delayMicroseconds(cyclewidth-fcycle);
} // end gofwd2()
void gobwd2(int bcycle) {
digitalWrite(m0l, HIGH); //Motor2
delayMicroseconds(bcycle);
digitalWrite(m0l, LOW); //Motor2
delayMicroseconds(cyclewidth-bcycle);
} // 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.
*/
@@ -0,0 +1,735 @@
// 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
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE PAUSE 1 SENSOR
//#define Pause1
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE PAUSE 2 SENSOR
//#define Pause2
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE REVERSE 1 SENSOR
#define Reverse1
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE REVERSE 2 SENSOR
//#define Reverse2
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE IMMEDIATE STOP SENSOR
//#define ImmediateStop
// ******** REMOVE THE "//" IN THE FOLLOWING LINE TO INCLUDE THE IMMEDIATE START SENSOR
//#define ImmediateStart
#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
uint16_t ttemp, i;
#define First_Track 1 // Play Random Tracks First_Track#=Start_Track >=1
#define Last_Track 2 // Play Random Tracks Last_Track= Last Playable Track in Range <= Last Numbered Track
#define starting_volume 22 // If no volume is set use this at the start
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 cyclewidth = 16384;
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 ThrottleInputReverse1Pin = 7; // Throttle Speed Reverse Input Pin
const int ThrottleInputReverse2Pin = 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, 0}, // ThrottlePause1 Pause Time 0-255 (0.1 secs)
{52, 0}, // ThrottlePause1 Throttle Ramp DOWN Delay 0-255 Larger Delay=Slower Ramp Down
{53, 0}, // ThrottlePause1 Throttle Ramp UP Delay 0-255 Larger Delay=Slower Ramp Up
{54, 11}, // ThrottlePause1 Pause Sound Clip 1-nn 0=No Sound
{55, 55}, // ThrottlePause1 Pause Sound Clip Volume 0-30
{56, 0}, // ThrottlePause2 Pause Time 0-255 (0.1 secs)
{57, 0}, // ThrottlePause2 Throttle Ramp DOWN 0-255 Delay
{58, 0}, // ThrottlePause2 Throttle Ramp UP Delay 0-255
{59, 11}, // ThrottlePause2 Pause Sound Clip 1-nn 0=No Sound
{60, 55}, // ThrottlePause2 Pause Sound Clip Volume 0-30
{61, 0}, // ThrottleInputReverse1 Pause Time 0-255 (0.1 secs)
{62, 0}, // ThrottleInputReverse1 Ramp DOWN Delay 0-255
{63, 0}, // ThrottleInputReverse1 Ramp UP Delay 0-255
{64, 11}, // ThrottleInputReverse1 Sound Clip 1-nn 0=No Sound
{65, 55}, // ThrottleInputReverse1 Sound Clip Volume 0-30
{66, 0}, // ThrottleInputReverse2 Pause Time 0-255 (0.1 secs)
{67, 0}, // ThrottleInputReverse2 Ramp DOWN Delay 0-255
{68, 0}, // ThrottleInputReverse2 Ramp UP Delay 0-255
{69, 11}, // ThrottleInputReverse2 Sound Clip 1-nn 0=No Sound
{70, 55}, // ThrottleInputReverse2 Sound Clip Volume 0-30
{71, 0}, // ThrottleImmediateStop Sound Clip 1-nn 0=No Sound
{72, 55}, // ThrottleImmediateStop Sound Clip Volume 0-30
{73, 0}, // ThrottleImmediateStart Sound Clip 1-nn 0=No Sound
{74, 55}, // ThrottleImmediateStart Sound Clip Volume 0-30
{80, 0}, // 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 (ThrottleInputReverse1Pin,INPUT_PULLUP); // Throttle Speed Reverse Input Pin 1 Active LOW
pinMode (ThrottleInputReverse2Pin,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;
}
}
setVolumeOnChannel (starting_volume);
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; }
#ifdef Pause1
// ======== 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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottlePause1Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef Pause2
// ======== 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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottlePause2Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef Reverse1
// ======== Throttle Reverse 1 ========================
if (digitalRead(ThrottleInputReverse1Pin)==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;
if (Dcc.getCV(62)!=0) delay(Dcc.getCV(62)); //Throttle Ramp DOWN Delay 0-255
else Motor1Speed=0;
}
//Motor1Speed = 0;
ttemp=(Dcc.getCV(64));
if (ttemp!=0) {setVolumeOnChannel (Dcc.getCV(65)); 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();
if (Dcc.getCV(63)!=0) delay(Dcc.getCV(63)); //Throttle Ramp UP Delay 0-255
else Motor1Speed=Starting_Motor1Speed;
}
//Motor1Speed = Starting_Motor1Speed;
for (i=0; i<10; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottleInputReverse1Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true;
}
#endif
#ifdef Reverse2
// ======== Throttle Reverse 2 ========================
if (digitalRead(ThrottleInputReverse2Pin)==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;
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ThrottleInputReverse2Pin) == LOW) run_at_speed(); //Wait for Sensor
Use_DCC_speed = true; // Do not update speed via DCC
}
#endif
#ifdef ImmediateStop
// ======== 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
}
#endif
#ifdef ImmediateStart
// ======== 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
for (i=0; i<30; i++) run_at_speed(); // Move away from sensor
while (digitalRead(ImmediateStartPin) == LOW) run_at_speed(); //Wait for Sensor
}
#endif
// ********************************************************************************
for (int i=1; 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 (Motor2Speed<<4);
else gobwd2 (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;
}
run_at_speed();
}
} // end loop()
void run_at_speed() {
Dcc.process();
if (MasterDecoderDisable == 0) {
if (Motor1Speed != 0) {
if (Motor1ForwardDir == 0) gofwd1 (Motor1Speed<<7);
else gobwd1 (Motor1Speed<<7);
}
}
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 (Motor2Speed<<7);
else gobwd2 (Motor2Speed<<7);
}
} // end run_at_speed()
void gofwd1(int fcycle) {
digitalWrite(m2h, HIGH); //Motor1
delayMicroseconds(fcycle);
digitalWrite(m2h, LOW); //Motor1
delayMicroseconds(cyclewidth-fcycle);
} // end gofwd1()
void gobwd1(int bcycle) {
digitalWrite(m2l, HIGH); //Motor1
delayMicroseconds(bcycle);
digitalWrite(m2l, LOW); //Motor1
delayMicroseconds(cyclewidth-bcycle);
} // end gobwd1()
void gofwd2(int fcycle) {
digitalWrite(m0h, HIGH); //Motor2
delayMicroseconds(fcycle);
digitalWrite(m0h, LOW); //Motor2
delayMicroseconds(cyclewidth-fcycle);
} // end gofwd2()
void gobwd2(int bcycle) {
digitalWrite(m0l, HIGH); //Motor2
delayMicroseconds(bcycle);
digitalWrite(m0l, LOW); //Motor2
delayMicroseconds(cyclewidth-bcycle);
} // 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.
*/
@@ -0,0 +1,92 @@
// Interactive Decoder Sound Test IDEC9_Sound_Test.ino
// Version 1.08 Geoff Bunza 2020
/*
* Copyright: DFRobot
* name: DFPlayer_Mini_Mp3 sample code
* Author: lisper <lisper.li@dfrobot.com>
* Date: 2014-05-30
* Description: connect DFPlayer Mini by SoftwareSerial, this code is test on Uno
* Note: the mp3 files must put into mp3 folder in your tf card
*/
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
#define DEBUG
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
//15 A1 - DFPlayer1 Receive (RX) Pin 2 via 470 Ohm Resistor
SoftwareSerial DFSerial1(22,11); // PRO MINI RX, PRO MINI TX serial to DFPlayer
DFRobotDFPlayerMini Player1;
#define Max_Num_Tracks_On_SDCard 12
const int audiocmddelay = 40;
void setup () {
//pinMode(8,INPUT_PULLUP);
#ifdef DEBUG
Serial.begin(115200);
#endif
DFSerial1.begin (9600);
Player1.begin (DFSerial1);
Player1.reset ();
delay(1000);
Player1.volume (21);
delay(audiocmddelay);
} // end setup()
int delta = 1500;
int track = 1;
void loop () {
for (int i=1; i<=Max_Num_Tracks_On_SDCard; i++) {
Player1.play (i);
#ifdef DEBUG
Serial.print("Playing Track ");
Serial.println(i);
#endif
delay(2000);
}
delay (6000);
} // end loop ()
/* 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.
*/
@@ -0,0 +1,32 @@
/* Sweep
by BARRAGAN <http://barraganstudio.com>
This example code is in the public domain.
modified 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Sweep
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(8); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 50; pos <= 140; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 140; pos >= 50; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
delay(12000);
}
@@ -7,6 +7,9 @@
NmraDcc Dcc ;
DCC_MSG Packet ;
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
struct CVPair
{
uint16_t CV;
@@ -15,8 +18,8 @@ struct CVPair
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
};
uint8_t FactoryDefaultCVIndex = 0;
@@ -92,14 +95,22 @@ void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
// Configure the DCC CV Programing ACK pin for an output
pinMode( DccAckPin, OUTPUT );
Serial.println("NMRA DCC Example 1");
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 1);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
@@ -18,6 +18,9 @@
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
//#define ENABLE_DCC_ACK 15 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
#define NUM_TURNOUTS 8 // Set Number of Turnouts (Pairs of Pins)
#define ACTIVE_OUTPUT_STATE LOW // Set the ACTIVE State of the output to Drive the Turnout motor electronics HIGH or LOW
@@ -40,8 +43,8 @@ struct CVPair
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1}, // CV 1 Board Address (lower 6 bits)
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, // CV 9 Board Address (Upper 3 bits)
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
{CV_ACCESSORY_DECODER_OUTPUT_PULSE_TIME, 50}, // x 10mS for the output pulse duration
{CV_ACCESSORY_DECODER_CDU_RECHARGE_TIME, 30}, // x 10mS for the CDU recharge delay time
{CV_ACCESSORY_DECODER_ACTIVE_STATE, ACTIVE_OUTPUT_STATE},
@@ -118,8 +121,14 @@ void setup()
{
Serial.begin(115200);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 1);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, CV29_ACCESSORY_DECODER, 0 );
@@ -0,0 +1,377 @@
// This Example shows how to use the library as a DCC Accessory Decoder to drive 16 Servos to control Turnouts
#include <NmraDcc.h>
#include <Servo.h>
#include <SlowMotionServo.h>
#include <elapsedMillis.h>
#include <EEPROM.h>
// You can print every DCC packet by un-commenting the line below
//#define NOTIFY_DCC_MSG
// You can print every notifyDccAccTurnoutOutput call-back by un-commenting the line below
#define NOTIFY_TURNOUT_MSG
// You can also print other Debug Messages uncommenting the line below
#define DEBUG_MSG
// Un-Comment the line below to force CVs to be written to the Factory Default values
// defined in the FactoryDefaultCVs below on Start-Up
//#define FORCE_RESET_FACTORY_DEFAULT_CV
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
#define ENABLE_DCC_ACK 27 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 26
#define NUM_SERVOS 16 // Set Number of Servos
#define DCC_DECODER_VERSION_NUM 12 // Set the Decoder Version - Used by JMRI to Identify the decoder
#define EEPROM_COMMIT_DELAY_MS 3000
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define CV_VALUE_SERVO_DETACH_MILLIS 0 // CV Default Value for the delay in ms x 10ms to Detach the servo signal to stop chattering
#define CV_ADDRESS_SERVO_DETACH_MILLIS CV_MANUFACTURER_START
#define CV_VALUE_SERVO_MOVE_SPEED 40 // CV Default Value for the Serov movement speed x 10
#define CV_ADDRESS_SERVO_MOVE_SPEED (CV_MANUFACTURER_START + 1)
#define CV_ADDRESS_SERVO_INDIVIDUAL_VALUES (CV_MANUFACTURER_START + 2)
#define CV_ADDRESS_LAST_POS_LSB (CV_MANUFACTURER_START + (NUM_SERVOS * 2 ) + 3)
#define CV_ADDRESS_LAST_POS_MSB (CV_MANUFACTURER_START + (NUM_SERVOS * 2 ) + 4)
#define CV_VALUE_SERVO_MIN_POS 40 // CV Default Value for the Minimum Servo Position as a % of Full Scale
#define CV_ADDRESS_SERVO_MIN_POS(x) (CV_ADDRESS_SERVO_INDIVIDUAL_VALUES + (2 * x) + 1)
#define CV_VALUE_SERVO_MAX_POS 60 // CV Default Value for the Maximum Servo Position as a % of Full Scale
#define CV_ADDRESS_SERVO_MAX_POS(x) (CV_ADDRESS_SERVO_INDIVIDUAL_VALUES + (2 * x) + 2)
// To set the Turnout Addresses for this board you need to change the CV values for CV1 (CV_ACCESSORY_DECODER_ADDRESS_LSB) and
// CV9 (CV_ACCESSORY_DECODER_ADDRESS_MSB) in the FactoryDefaultCVs structure below. The Turnout Addresses are defined as:
// Base Turnout Address is: ((((CV9 * 64) + CV1) - 1) * 4) + 1
// With NUM_TURNOUTS 8 (above) a CV1 = 1 and CV9 = 0, the Turnout Addresses will be 1..8, for CV1 = 2 the Turnout Address is 5..12
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
{CV_ADDRESS_SERVO_DETACH_MILLIS, CV_VALUE_SERVO_DETACH_MILLIS}, // 0 = don't Detach else the Detach will occur after the CV Value x 10ms
{CV_ADDRESS_SERVO_MOVE_SPEED, CV_VALUE_SERVO_MOVE_SPEED}, // 0 = don't Detach else the Detach will occur after the CV Value x 10ms
{CV_ADDRESS_SERVO_MIN_POS(0), CV_VALUE_SERVO_MIN_POS}, // Servo 0
{CV_ADDRESS_SERVO_MAX_POS(0), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(1), CV_VALUE_SERVO_MIN_POS}, // Servo 1
{CV_ADDRESS_SERVO_MAX_POS(1), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(2), CV_VALUE_SERVO_MIN_POS}, // Servo 2
{CV_ADDRESS_SERVO_MAX_POS(2), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(3), CV_VALUE_SERVO_MIN_POS}, // Servo 3
{CV_ADDRESS_SERVO_MAX_POS(3), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(4), CV_VALUE_SERVO_MIN_POS}, // Servo 4
{CV_ADDRESS_SERVO_MAX_POS(4), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(5), CV_VALUE_SERVO_MIN_POS}, // Servo 5
{CV_ADDRESS_SERVO_MAX_POS(5), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(6), CV_VALUE_SERVO_MIN_POS}, // Servo 6
{CV_ADDRESS_SERVO_MAX_POS(6), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(7), CV_VALUE_SERVO_MIN_POS}, // Servo 7
{CV_ADDRESS_SERVO_MAX_POS(7), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(8), CV_VALUE_SERVO_MIN_POS}, // Servo 8
{CV_ADDRESS_SERVO_MAX_POS(8), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(9), CV_VALUE_SERVO_MIN_POS}, // Servo 9
{CV_ADDRESS_SERVO_MAX_POS(9), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(10), CV_VALUE_SERVO_MIN_POS}, // Servo 10
{CV_ADDRESS_SERVO_MAX_POS(10), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(11), CV_VALUE_SERVO_MIN_POS}, // Servo 11
{CV_ADDRESS_SERVO_MAX_POS(11), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(12), CV_VALUE_SERVO_MIN_POS}, // Servo 12
{CV_ADDRESS_SERVO_MAX_POS(12), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(13), CV_VALUE_SERVO_MIN_POS}, // Servo 13
{CV_ADDRESS_SERVO_MAX_POS(13), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(14), CV_VALUE_SERVO_MIN_POS}, // Servo 14
{CV_ADDRESS_SERVO_MAX_POS(14), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_SERVO_MIN_POS(15), CV_VALUE_SERVO_MIN_POS}, // Servo 15
{CV_ADDRESS_SERVO_MAX_POS(15), CV_VALUE_SERVO_MAX_POS},
{CV_ADDRESS_LAST_POS_LSB, 0},
{CV_ADDRESS_LAST_POS_MSB, 0},
};
uint8_t FactoryDefaultCVIndex = 0;
NmraDcc Dcc ;
DCC_MSG Packet ;
uint16_t BaseTurnoutAddress;
uint16_t lastPositionBits;
SMSSmooth Servos[NUM_SERVOS];
// This function is called whenever a normal DCC Turnout Packet is received
void notifyDccAccTurnoutOutput (uint16_t OutputAddress, uint8_t Direction, uint8_t OutputPower)
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.print("notifyDccAccTurnoutOutput: Output Addr: ") ;
Serial.print(OutputAddress,DEC) ;
Serial.print(" Direction: ");
Serial.print(Direction ? "Closed" : "Thrown") ;
Serial.print(" Output: ");
Serial.print(OutputPower ? "On" : "Off") ;
#endif
if(( OutputAddress >= BaseTurnoutAddress ) && ( OutputAddress < (BaseTurnoutAddress + NUM_SERVOS )) && OutputPower ) // Only Drive the Servo on Activation
{
uint16_t servoIndex = OutputAddress - BaseTurnoutAddress;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print(" Servo Num: ");
Serial.println(servoIndex,DEC);
#endif
setServoPos(servoIndex, Direction != 0);
}
else
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.println();
#endif
}
}
void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower)
{
uint16_t Addr = ((BoardAddr - 1) * 4) + OutputPair + 1;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print("notifyDccAccTurnoutBoard: Board Addr: ") ;
Serial.print(BoardAddr,DEC) ;
Serial.print(" Output Pair: ");
Serial.print(OutputPair,DEC) ;
Serial.print(" Turnout Addr: ");
Serial.print(Addr,DEC) ;
Serial.print(" Base Turnout Addr: ");
Serial.print(BaseTurnoutAddress,DEC) ;
Serial.print(" Direction: ");
Serial.print(Direction ? "Closed" : "Thrown") ;
Serial.print(" Output: ");
Serial.print(OutputPower ? "On" : "Off") ;
#endif
if(( Addr >= BaseTurnoutAddress ) && ( Addr < (BaseTurnoutAddress + NUM_SERVOS )) && OutputPower ) // Only Drive the Servo on Activation
{
uint16_t servoIndex = Addr - BaseTurnoutAddress;
#ifdef NOTIFY_TURNOUT_MSG
Serial.print(" Servo Num: ");
Serial.println(servoIndex,DEC);
#endif
setServoPos(servoIndex, Direction != 0);
}
else
{
#ifdef NOTIFY_TURNOUT_MSG
Serial.println();
#endif
}
}
void setServoPos(uint8_t index, bool position)
{
if(index < NUM_SERVOS)
{
Servos[index].goTo( position ? 1.0 : 0.0);
setLastTurnoutPosition(index, position);
}
}
bool getLastTurnoutPosition(uint8_t index)
{
if(index < NUM_SERVOS)
{
uint16_t bitMask = 1 << index;
return lastPositionBits & bitMask ? true : false;
}
return 0;
}
void setLastTurnoutPosition(uint8_t index, bool position)
{
if(index < NUM_SERVOS)
{
uint16_t bitMask = 1 << index;
if(position)
lastPositionBits |= bitMask;
else
lastPositionBits &= ~bitMask;
Dcc.setCV(CV_ADDRESS_LAST_POS_LSB, lastPositionBits & 0x00ff);
Dcc.setCV(CV_ADDRESS_LAST_POS_MSB, (lastPositionBits >> 8) & 0x00ff);
}
}
void initServos()
{
BaseTurnoutAddress = (((Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_MSB) * 64) + Dcc.getCV(CV_ACCESSORY_DECODER_ADDRESS_LSB) - 1) * 4) + 1 ;
uint16_t servoDetachMillis = Dcc.getCV(CV_ADDRESS_SERVO_DETACH_MILLIS) * 10;
SlowMotionServo::setDelayUntilStop(servoDetachMillis); // This is a static class member so only needs to be set once and is used globally
#ifdef DEBUG_MSG
Serial.print("initServos: DCC Turnout Base Address: "); Serial.print(BaseTurnoutAddress, DEC);
Serial.print(" Detach Servo Signal MilliSeconds: "); Serial.print(servoDetachMillis);
#endif
float servoMoveSpeed = Dcc.getCV(CV_ADDRESS_SERVO_MOVE_SPEED) / 10.0;
lastPositionBits = Dcc.getCV(CV_ADDRESS_LAST_POS_LSB) | (Dcc.getCV(CV_ADDRESS_LAST_POS_MSB) << 8);
for(uint8_t i = 0; i < NUM_SERVOS; i++)
{
Servos[i].setPin(i);
Servos[i].setupMin( map(Dcc.getCV(CV_ADDRESS_SERVO_MIN_POS(i)), 0, 100, 544, 2400));
Servos[i].setupMax( map(Dcc.getCV(CV_ADDRESS_SERVO_MAX_POS(i)), 0, 100, 544, 2400));
Servos[i].setSpeed(servoMoveSpeed);
Servos[i].setDetach(servoDetachMillis != 0);
Servos[i].setInitialPosition(getLastTurnoutPosition(i) ? 1.0 : 0.0);
}
SlowMotionServo::update();
#ifdef DEBUG_MSG
Serial.println("\ninitServos: Done");
#endif
}
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
#ifdef DEBUG_MSG
Serial.print("\nNMRA DCC 16-Servo Accessory Decoder. Ver: "); Serial.println(DCC_DECODER_VERSION_NUM,DEC);
#endif
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 1);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, FLAGS_DCC_ACCESSORY_DECODER|FLAGS_EXTENDED_ADDRESS_MODE, 0);
#ifdef FORCE_RESET_FACTORY_DEFAULT_CV
Serial.println("Resetting CVs to Factory Defaults");
notifyCVResetFactoryDefault();
#endif
if( FactoryDefaultCVIndex == 0) // Not forcing a reset CV Reset to Factory Defaults so initPinPulser
initServos();
}
void loop()
{
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process();
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
{
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
uint16_t cv = FactoryDefaultCVs[FactoryDefaultCVIndex].CV;
uint8_t val = FactoryDefaultCVs[FactoryDefaultCVIndex].Value;
#ifdef DEBUG_MSG
Serial.print("loop: Write Default CV: "); Serial.print(cv,DEC); Serial.print(" Value: "); Serial.println(val,DEC);
#endif
Dcc.setCV( cv, val );
if( FactoryDefaultCVIndex == 0) // Is this the last Default CV to set? if so re-initPinPulser
initServos();
}
SlowMotionServo::update();
}
void notifyCVChange(uint16_t CV, uint8_t Value)
{
#ifdef DEBUG_MSG
Serial.print("notifyCVChange: CV: ") ;
Serial.print(CV,DEC) ;
Serial.print(" Value: ") ;
Serial.println(Value, DEC) ;
#endif
Value = Value; // Silence Compiler Warnings...
if((CV == CV_ACCESSORY_DECODER_ADDRESS_MSB) || (CV == CV_ACCESSORY_DECODER_ADDRESS_LSB) ||
((CV >= CV_ADDRESS_SERVO_DETACH_MILLIS) && (CV < CV_ADDRESS_LAST_POS_LSB)) && (FactoryDefaultCVIndex == 0))
initServos(); // Some CV we care about changed so re-init the PinPulser with the new CV settings
}
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);
};
// This function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
#ifdef ENABLE_DCC_ACK
void notifyCVAck(void)
{
#ifdef DEBUG_MSG
Serial.println("notifyCVAck") ;
#endif
// Configure the DCC CV Programing ACK pin for an output
pinMode( ENABLE_DCC_ACK, OUTPUT );
// Generate the DCC ACK 60mA pulse
digitalWrite( ENABLE_DCC_ACK, HIGH );
delay( 10 ); // The DCC Spec says 6ms but 10 makes sure... ;)
digitalWrite( ENABLE_DCC_ACK, LOW );
}
#endif
#ifdef NOTIFY_DCC_MSG
void notifyDccMsg( DCC_MSG * Msg)
{
Serial.print("notifyDccMsg: ") ;
for(uint8_t i = 0; i < Msg->Size; i++)
{
Serial.print(Msg->Data[i], HEX);
Serial.write(' ');
}
Serial.println();
}
#endif
@@ -1,6 +1,7 @@
#include <NmraDcc.h>
#define This_Decoder_Address 3
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
struct CVPair
{
@@ -11,11 +12,11 @@ struct CVPair
CVPair FactoryDefaultCVs [] =
{
// The CV Below defines the Short DCC Address
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_MULTIFUNCTION_DECODER_ADDRESS},
// These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_Decoder_Address},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_MULTIFUNCTION_DECODER_ADDRESS)},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_MULTIFUNCTION_DECODER_ADDRESS)},
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
@@ -169,8 +170,14 @@ void setup()
pinMode( DccAckPin, OUTPUT );
digitalWrite( DccAckPin, LOW );
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 0);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
//Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
@@ -32,6 +32,7 @@
// This section defines the Arduino UNO Pins to use
#ifdef __AVR_ATmega328P__
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
#define LED_PIN_FWD 5
@@ -42,6 +43,7 @@
// This section defines the Arduino ATTiny85 Pins to use
#elif ARDUINO_AVR_ATTINYX5
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
#define LED_PIN_FWD 0
@@ -89,8 +91,8 @@ CVPair FactoryDefaultCVs [] =
{CV_VHIGH, 255},
// These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DEFAULT_DECODER_ADDRESS},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_DECODER_ADDRESS)},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_DECODER_ADDRESS)},
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
@@ -217,8 +219,14 @@ void setup()
pinMode(MOTOR_PWM_PIN, OUTPUT);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
@@ -292,8 +300,8 @@ void loop()
#ifdef DEBUG_FUNCTIONS
Serial.println("LED On");
#endif
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
digitalWrite(LED_PIN_FWD, newDirection ? HIGH : LOW);
digitalWrite(LED_PIN_REV, newDirection ? LOW : HIGH);
}
else
{
@@ -1,5 +1,3 @@
#include <NmraDcc.h>
// This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
// You can find out more about this DCC Interface here: http://www.iascaled.com/store/ARD-DCCSHIELD
//
@@ -16,6 +14,9 @@
// JP6 - Boards without VIO - User Choice
// JP7 - Enable Programming ACK - 1-2 ON 3-4 ON
//
#include <NmraDcc.h>
#include <elapsedMillis.h>
// It is a very basic DCC Accessory Decoder that does nothing except allow CV Read/Write and
// you can also print every DCC packet by uncommenting the "#define NOTIFY_DCC_MSG" line below
#define NOTIFY_DCC_MSG
@@ -26,6 +27,9 @@
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
#define ENABLE_DCC_ACK 15 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
// Define the Arduino input Pin number for the DCC Signal
#define DCC_PIN 2
NmraDcc Dcc ;
struct CVPair
@@ -36,8 +40,8 @@ struct CVPair
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
};
uint8_t FactoryDefaultCVIndex = 0;
@@ -98,11 +102,19 @@ void notifyCVChange(uint16_t CV, uint8_t Value)
void setup()
{
Serial.begin(115200);
elapsedMillis millisWaitedForUSB = 0;
while(!Serial && (millisWaitedForUSB < 3000)); // Wait up to 3 seconds for USB to Connect
Serial.println("NMRA DCC Iowa Scaled Engineering ARD-DCCSHIELD Example");
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 1);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
// Interrupt Number for the Arduino Pin number, which reduces confusion.
#ifdef digitalPinToInterrupt
Dcc.pin(DCC_PIN, 0);
#else
Dcc.pin(0, DCC_PIN, 1);
#endif
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
@@ -106,9 +106,9 @@ CVPair FactoryDefaultCVs [] =
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
// These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // Extended address MSB.
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DECODER_ADDR}, // Extended address LSB.
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DECODER_ADDR)},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DECODER_ADDR)},
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
};
+9 -9
View File
@@ -1,9 +1,9 @@
name=NmraDcc
version=2.0.1
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
sentence=Enables NMRA DCC Communication
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
category=Communication
url=https://github.com/mrrwa/NmraDcc
architectures=*
name=NmraDcc
version=2.0.11
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner, bugfixes by Jueff
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
sentence=Enables NMRA DCC Communication
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
category=Communication
url=https://github.com/mrrwa/NmraDcc
architectures=*
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
FORMAT_SOURCES="NmraDcc.h NmraDcc.cpp"
error=0
for file in ${FORMAT_SOURCES}
do
output=$(mktemp -t stylecheckXXXXXXX)
astyle --options=.astylerc < $file > $output
if ! cmp -s $file $output
then
echo "Formatting on $file doesn't match expectations"
diff -u $file $output
error=1
fi
[ -f $output ] && rm $output
done
exit $error