Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b52381fa4 | ||
|
|
5f1e271f2c | ||
|
|
6f91d4f7d4 | ||
|
|
b35c1fbbd0 | ||
|
|
f59048383f | ||
|
|
6333abf691 | ||
|
|
afe488d792 | ||
|
|
61a730bf82 | ||
|
|
b0b27ce0cc | ||
|
|
c3dc28479a | ||
|
|
a05c12ce95 | ||
|
|
0a72fc610b | ||
|
|
ad5ce96253 | ||
|
|
1e81b95044 | ||
|
|
84fdf45dce | ||
|
|
037070b899 | ||
|
|
eb15c25491 | ||
|
|
681b362811 | ||
|
|
f5d7e9b8c3 |
No files matched your search
@@ -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
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
.development
|
.development
|
||||||
*.zip
|
*.zip
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
*.txt
|
||||||
+179
-72
@@ -38,6 +38,7 @@
|
|||||||
// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net)
|
// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net)
|
||||||
// 2019-02-17 added ESP32 specific changes by Hans Tanner
|
// 2019-02-17 added ESP32 specific changes by Hans Tanner
|
||||||
// 2020-05-15 changes to pass NMRA Tests ( always search for preamble )
|
// 2020-05-15 changes to pass NMRA Tests ( always search for preamble )
|
||||||
|
// 2021-03-11 fix ESP32 bug on interrupt reinitialisation
|
||||||
//------------------------------------------------------------------------
|
//------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// purpose: Provide a simplified interface to decode NMRA DCC packets
|
// purpose: Provide a simplified interface to decode NMRA DCC packets
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
|
|
||||||
#include "NmraDcc.h"
|
#include "NmraDcc.h"
|
||||||
#include "EEPROM.h"
|
#include "EEPROM.h"
|
||||||
|
#include <elapsedMillis.h>
|
||||||
|
|
||||||
// Uncomment to print DEBUG messages
|
// Uncomment to print DEBUG messages
|
||||||
// #define DEBUG_PRINT
|
// #define DEBUG_PRINT
|
||||||
@@ -241,8 +243,13 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEBUG_PRINT
|
#ifdef DEBUG_PRINT
|
||||||
|
#ifdef ARDUINO_ARCH_RP2040
|
||||||
|
#define DB_PRINT( x, ... ) { char dbgbuf[80]; sprintf( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.println( dbgbuf ); }
|
||||||
|
#define DB_PRINT_( x, ... ) { char dbgbuf[80]; sprintf( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.print( dbgbuf ); }
|
||||||
|
#else
|
||||||
#define DB_PRINT( x, ... ) { char dbgbuf[80]; sprintf_P( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.println( dbgbuf ); }
|
#define DB_PRINT( x, ... ) { char dbgbuf[80]; sprintf_P( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.println( dbgbuf ); }
|
||||||
#define DB_PRINT_( x, ... ) { char dbgbuf[80]; sprintf_P( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.print( dbgbuf ); }
|
#define DB_PRINT_( x, ... ) { char dbgbuf[80]; sprintf_P( dbgbuf, (const char*) F( x ) , ##__VA_ARGS__ ) ; Serial.print( dbgbuf ); }
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define DB_PRINT( x, ... ) ;
|
#define DB_PRINT( x, ... ) ;
|
||||||
#define DB_PRINT_( x, ... ) ;
|
#define DB_PRINT_( x, ... ) ;
|
||||||
@@ -257,6 +264,8 @@ static ExtIntTriggerMode ISREdge;
|
|||||||
#elif defined ( ESP32 )
|
#elif defined ( ESP32 )
|
||||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
||||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||||
|
#elif defined ( ARDUINO_AVR_NANO_EVERY ) || defined(ARDUINO_ARCH_RP2040)
|
||||||
|
static PinStatus ISREdge;
|
||||||
#else
|
#else
|
||||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
||||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||||
@@ -319,6 +328,11 @@ typedef struct
|
|||||||
uint8_t TickCount;
|
uint8_t TickCount;
|
||||||
uint8_t NestedIrqCount;
|
uint8_t NestedIrqCount;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
|
elapsedMillis millisSinceEEPromWrite = 0;
|
||||||
|
bool eepromChanged = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
DCC_PROCESSOR_STATE ;
|
DCC_PROCESSOR_STATE ;
|
||||||
|
|
||||||
@@ -366,7 +380,8 @@ void ExternalInterruptHandler(void)
|
|||||||
static byte halfBit, DCC_IrqRunning, preambleBitCount;
|
static byte halfBit, DCC_IrqRunning, preambleBitCount;
|
||||||
unsigned int actMicros, bitMicros;
|
unsigned int actMicros, bitMicros;
|
||||||
#ifdef ALLOW_NESTED_IRQ
|
#ifdef ALLOW_NESTED_IRQ
|
||||||
if ( DCC_IrqRunning ) {
|
if (DCC_IrqRunning)
|
||||||
|
{
|
||||||
// nested DCC IRQ - obviously there are glitches
|
// nested DCC IRQ - obviously there are glitches
|
||||||
// ignore this interrupt and increment glitchcounter
|
// ignore this interrupt and increment glitchcounter
|
||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
@@ -380,23 +395,28 @@ void ExternalInterruptHandler(void)
|
|||||||
actMicros = micros();
|
actMicros = micros();
|
||||||
bitMicros = actMicros-lastMicros;
|
bitMicros = actMicros-lastMicros;
|
||||||
|
|
||||||
CLR_TP3; SET_TP3;
|
CLR_TP3;
|
||||||
|
SET_TP3;
|
||||||
#ifdef __AVR_MEGA__
|
#ifdef __AVR_MEGA__
|
||||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && (*DccProcState.ExtIntPort & DccProcState.ExtIntMask) != (ISRLevel) ) ) {
|
if (bitMicros < bitMin || (DccRx.State != WAIT_START_BIT && (*DccProcState.ExtIntPort & DccProcState.ExtIntMask) != (ISRLevel)))
|
||||||
|
{
|
||||||
#else
|
#else
|
||||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && digitalRead( DccProcState.ExtIntPinNum ) != (ISRLevel) ) ) {
|
if (bitMicros < bitMin || (DccRx.State != WAIT_START_BIT && digitalRead (DccProcState.ExtIntPinNum) != (ISRLevel)))
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
// too short - my be false interrupt due to glitch or false protocol or level does not match RISING / FALLING edge -> ignore this IRQ
|
// too short - my be false interrupt due to glitch or false protocol or level does not match RISING / FALLING edge -> ignore this IRQ
|
||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
SET_TP4; /*delayMicroseconds(1); */ CLR_TP4;
|
SET_TP4; /*delayMicroseconds(1); */ CLR_TP4;
|
||||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||||
}
|
}
|
||||||
CLR_TP3; SET_TP3;
|
CLR_TP3;
|
||||||
|
SET_TP3;
|
||||||
|
|
||||||
lastMicros = actMicros;
|
lastMicros = actMicros;
|
||||||
#ifndef SUPPORT_ZERO_BIT_STRETCHING
|
#ifndef SUPPORT_ZERO_BIT_STRETCHING
|
||||||
//if ( bitMicros > MAX_ZEROBITFULL ) {
|
//if ( bitMicros > MAX_ZEROBITFULL ) {
|
||||||
if ( bitMicros > (bitMax*2) ) {
|
if (bitMicros > (bitMax*2))
|
||||||
|
{
|
||||||
// too long - my be false protocol -> start over
|
// too long - my be false protocol -> start over
|
||||||
DccRx.State = WAIT_PREAMBLE ;
|
DccRx.State = WAIT_PREAMBLE ;
|
||||||
DccRx.BitCount = 0 ;
|
DccRx.BitCount = 0 ;
|
||||||
@@ -443,9 +463,11 @@ void ExternalInterruptHandler(void)
|
|||||||
#ifndef SYNC_ALWAYS
|
#ifndef SYNC_ALWAYS
|
||||||
case WAIT_START_BIT_FULL:
|
case WAIT_START_BIT_FULL:
|
||||||
// wait for startbit without level checking
|
// wait for startbit without level checking
|
||||||
if ( !DccBitVal ) {
|
if (!DccBitVal)
|
||||||
|
{
|
||||||
// we got the startbit
|
// we got the startbit
|
||||||
CLR_TP2;CLR_TP1;
|
CLR_TP2;
|
||||||
|
CLR_TP1;
|
||||||
DccRx.State = WAIT_DATA ;
|
DccRx.State = WAIT_DATA ;
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
// initialize packet buffer
|
// initialize packet buffer
|
||||||
@@ -462,25 +484,31 @@ void ExternalInterruptHandler(void)
|
|||||||
#endif
|
#endif
|
||||||
case WAIT_START_BIT:
|
case WAIT_START_BIT:
|
||||||
// we are looking for first half "0" bit after preamble
|
// we are looking for first half "0" bit after preamble
|
||||||
switch ( halfBit ) {
|
switch (halfBit)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
// check first part
|
// check first part
|
||||||
if ( DccBitVal ) {
|
if (DccBitVal)
|
||||||
|
{
|
||||||
// is still 1-bit (Preamble)
|
// is still 1-bit (Preamble)
|
||||||
halfBit=1;
|
halfBit=1;
|
||||||
bit1=bitMicros;
|
bit1=bitMicros;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// was "0" half bit, maybe the startbit
|
// was "0" half bit, maybe the startbit
|
||||||
halfBit = 4;
|
halfBit = 4;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1: // previous halfbit was '1'
|
case 1: // previous halfbit was '1'
|
||||||
if ( DccBitVal ) {
|
if (DccBitVal)
|
||||||
|
{
|
||||||
// its a '1' halfBit -> we are still in the preamble
|
// its a '1' halfBit -> we are still in the preamble
|
||||||
halfBit = 0;
|
halfBit = 0;
|
||||||
bit2=bitMicros;
|
bit2=bitMicros;
|
||||||
preambleBitCount++;
|
preambleBitCount++;
|
||||||
if( abs(bit2-bit1) > MAX_BITDIFF ) {
|
if (abs (bit2-bit1) > MAX_BITDIFF)
|
||||||
|
{
|
||||||
// the length of the 2 halfbits differ too much -> wrong protokoll
|
// the length of the 2 halfbits differ too much -> wrong protokoll
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
@@ -490,18 +518,20 @@ void ExternalInterruptHandler(void)
|
|||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt (DccProcState.ExtIntNum);
|
detachInterrupt (DccProcState.ExtIntNum);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#if defined(ESP32)
|
||||||
ISRWatch = ISREdge;
|
ISRWatch = ISREdge;
|
||||||
#else
|
#else
|
||||||
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
||||||
|
#endif
|
||||||
// enable level checking ( with direct port reading @ AVR )
|
// enable level checking ( with direct port reading @ AVR )
|
||||||
ISRChkMask = DccProcState.ExtIntMask;
|
ISRChkMask = DccProcState.ExtIntMask;
|
||||||
ISRLevel = (ISREdge==RISING) ? DccProcState.ExtIntMask : 0 ;
|
ISRLevel = (ISREdge==RISING) ? DccProcState.ExtIntMask : 0 ;
|
||||||
#endif
|
|
||||||
SET_TP3;
|
SET_TP3;
|
||||||
CLR_TP4;
|
CLR_TP4;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// first '0' half detected in second halfBit
|
// first '0' half detected in second halfBit
|
||||||
// wrong sync or not a DCC protokoll
|
// wrong sync or not a DCC protokoll
|
||||||
CLR_TP3;
|
CLR_TP3;
|
||||||
@@ -510,18 +540,23 @@ void ExternalInterruptHandler(void)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: // previous halfbit was '0' in second halfbit
|
case 3: // previous halfbit was '0' in second halfbit
|
||||||
if ( DccBitVal ) {
|
if (DccBitVal)
|
||||||
|
{
|
||||||
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
preambleBitCount = 0;
|
preambleBitCount = 0;
|
||||||
// SET_TP2; CLR_TP2;
|
// SET_TP2; CLR_TP2;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// we got two '0' halfbits -> it's the startbit
|
// we got two '0' halfbits -> it's the startbit
|
||||||
// but sync is NOT ok, change IRQ edge.
|
// but sync is NOT ok, change IRQ edge.
|
||||||
CLR_TP2;CLR_TP1;
|
CLR_TP2;
|
||||||
if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING;
|
CLR_TP1;
|
||||||
|
if (ISREdge == RISING) ISREdge = FALLING;
|
||||||
|
else ISREdge = RISING;
|
||||||
DccRx.State = WAIT_DATA ;
|
DccRx.State = WAIT_DATA ;
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
@@ -540,7 +575,7 @@ void ExternalInterruptHandler(void)
|
|||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt (DccProcState.ExtIntNum);
|
detachInterrupt (DccProcState.ExtIntNum);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
#if defined(ESP32)
|
||||||
ISRWatch = ISREdge;
|
ISRWatch = ISREdge;
|
||||||
#else
|
#else
|
||||||
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
||||||
@@ -552,17 +587,22 @@ void ExternalInterruptHandler(void)
|
|||||||
break;
|
break;
|
||||||
case 4: // previous (first) halfbit was 0
|
case 4: // previous (first) halfbit was 0
|
||||||
// if this halfbit is 0 too, we got the startbit
|
// if this halfbit is 0 too, we got the startbit
|
||||||
if ( DccBitVal ) {
|
if (DccBitVal)
|
||||||
|
{
|
||||||
// second halfbit is 1 -> unknown protokoll
|
// second halfbit is 1 -> unknown protokoll
|
||||||
DccRx.State = WAIT_PREAMBLE;
|
DccRx.State = WAIT_PREAMBLE;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
preambleBitCount = 0;
|
preambleBitCount = 0;
|
||||||
CLR_TP2;CLR_TP1;
|
CLR_TP2;
|
||||||
|
CLR_TP1;
|
||||||
DccRx.BitCount = 0;
|
DccRx.BitCount = 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// we got the startbit
|
// we got the startbit
|
||||||
CLR_TP2;CLR_TP1;
|
CLR_TP2;
|
||||||
|
CLR_TP1;
|
||||||
DccRx.State = WAIT_DATA ;
|
DccRx.State = WAIT_DATA ;
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
bitMax = MAX_ONEBITFULL;
|
bitMax = MAX_ONEBITFULL;
|
||||||
@@ -583,7 +623,8 @@ void ExternalInterruptHandler(void)
|
|||||||
#if defined ( __STM32F1__ )
|
#if defined ( __STM32F1__ )
|
||||||
detachInterrupt (DccProcState.ExtIntNum);
|
detachInterrupt (DccProcState.ExtIntNum);
|
||||||
#endif
|
#endif
|
||||||
#ifdef ESP32
|
|
||||||
|
#if defined(ESP32)
|
||||||
ISRWatch = ISREdge;
|
ISRWatch = ISREdge;
|
||||||
#else
|
#else
|
||||||
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
attachInterrupt (DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge);
|
||||||
@@ -624,16 +665,20 @@ void ExternalInterruptHandler(void)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WAIT_END_BIT:
|
case WAIT_END_BIT:
|
||||||
SET_TP2;CLR_TP2;
|
SET_TP2;
|
||||||
|
CLR_TP2;
|
||||||
DccRx.BitCount++;
|
DccRx.BitCount++;
|
||||||
if( DccBitVal ) { // End of packet?
|
if (DccBitVal) // End of packet?
|
||||||
CLR_TP3; SET_TP4;
|
{
|
||||||
|
CLR_TP3;
|
||||||
|
SET_TP4;
|
||||||
DccRx.State = WAIT_PREAMBLE ;
|
DccRx.State = WAIT_PREAMBLE ;
|
||||||
DccRx.BitCount = 0 ;
|
DccRx.BitCount = 0 ;
|
||||||
bitMax = MAX_PRAEAMBEL;
|
bitMax = MAX_PRAEAMBEL;
|
||||||
bitMin = MIN_ONEBITFULL;
|
bitMin = MIN_ONEBITFULL;
|
||||||
SET_TP1;
|
SET_TP1;
|
||||||
if ( DccRx.chkSum == 0 ) {
|
if (DccRx.chkSum == 0)
|
||||||
|
{
|
||||||
// Packet is valid
|
// Packet is valid
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
portENTER_CRITICAL_ISR (&mux);
|
portENTER_CRITICAL_ISR (&mux);
|
||||||
@@ -645,7 +690,9 @@ void ExternalInterruptHandler(void)
|
|||||||
#endif
|
#endif
|
||||||
// SET_TP2; CLR_TP2;
|
// SET_TP2; CLR_TP2;
|
||||||
preambleBitCount = 0 ;
|
preambleBitCount = 0 ;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Wrong checksum
|
// Wrong checksum
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
#ifdef DCC_DBGVAR
|
#ifdef DCC_DBGVAR
|
||||||
@@ -654,8 +701,11 @@ void ExternalInterruptHandler(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_TP3; CLR_TP4;
|
SET_TP3;
|
||||||
} else { // Get next Byte
|
CLR_TP4;
|
||||||
|
}
|
||||||
|
else // Get next Byte
|
||||||
|
{
|
||||||
// KGW - Abort immediately if packet is too long.
|
// KGW - Abort immediately if packet is too long.
|
||||||
if (DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN) // Packet is too long - abort
|
if (DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN) // Packet is too long - abort
|
||||||
{
|
{
|
||||||
@@ -678,18 +728,23 @@ void ExternalInterruptHandler(void)
|
|||||||
// we always search for a preamble ( ( 10 or more consecutive 1 bits )
|
// we always search for a preamble ( ( 10 or more consecutive 1 bits )
|
||||||
// if we found it within a packet, the packet decoding is aborted because
|
// if we found it within a packet, the packet decoding is aborted because
|
||||||
// that much one bits cannot be valid in a packet.
|
// that much one bits cannot be valid in a packet.
|
||||||
if ( DccRx.State != WAIT_START_BIT ) {
|
if (DccRx.State != WAIT_START_BIT)
|
||||||
|
{
|
||||||
if (DccBitVal)
|
if (DccBitVal)
|
||||||
{
|
{
|
||||||
preambleBitCount++;
|
preambleBitCount++;
|
||||||
//SET_TP2;
|
//SET_TP2;
|
||||||
if( preambleBitCount > 10 ) {
|
if (preambleBitCount > 10)
|
||||||
|
{
|
||||||
CLR_TP2;
|
CLR_TP2;
|
||||||
#ifndef SYNC_ALWAYS
|
#ifndef SYNC_ALWAYS
|
||||||
if ( DccRx.chkSum == 0 ) {
|
if (DccRx.chkSum == 0)
|
||||||
|
{
|
||||||
// sync must be correct if chksum was ok, no need to check sync
|
// sync must be correct if chksum was ok, no need to check sync
|
||||||
DccRx.State = WAIT_START_BIT_FULL;
|
DccRx.State = WAIT_START_BIT_FULL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
DccRx.State = WAIT_START_BIT ;
|
DccRx.State = WAIT_START_BIT ;
|
||||||
SET_TP2;
|
SET_TP2;
|
||||||
@@ -714,7 +769,9 @@ void ExternalInterruptHandler(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
CLR_TP1;
|
CLR_TP1;
|
||||||
preambleBitCount = 0 ;
|
preambleBitCount = 0 ;
|
||||||
// SET_TP2; CLR_TP2;
|
// SET_TP2; CLR_TP2;
|
||||||
@@ -755,11 +812,10 @@ uint8_t readEEPROM( unsigned int CV )
|
|||||||
void writeEEPROM (unsigned int CV, uint8_t Value)
|
void writeEEPROM (unsigned int CV, uint8_t Value)
|
||||||
{
|
{
|
||||||
EEPROM.write (CV, Value) ;
|
EEPROM.write (CV, Value) ;
|
||||||
#if defined(ESP8266)
|
|
||||||
EEPROM.commit();
|
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
#endif
|
DccProcState.eepromChanged = true;
|
||||||
#if defined(ESP32)
|
DccProcState.millisSinceEEPromWrite = 0;
|
||||||
EEPROM.commit();
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -846,7 +902,7 @@ uint16_t getMyAddr(void)
|
|||||||
|
|
||||||
if (DccProcState.cv29Value & CV29_ACCESSORY_DECODER) // Accessory Decoder?
|
if (DccProcState.cv29Value & CV29_ACCESSORY_DECODER) // Accessory Decoder?
|
||||||
{
|
{
|
||||||
if( DccProcState.cv29Value & CV29_OUTPUT_ADDRESS_MODE )
|
if (DccProcState.cv29Value & (CV29_OUTPUT_ADDRESS_MODE | CV29_EXT_ADDRESSING))
|
||||||
DccProcState.myDccAddress = (readCV (CV_ACCESSORY_DECODER_ADDRESS_MSB) << 8) | readCV (CV_ACCESSORY_DECODER_ADDRESS_LSB);
|
DccProcState.myDccAddress = (readCV (CV_ACCESSORY_DECODER_ADDRESS_MSB) << 8) | readCV (CV_ACCESSORY_DECODER_ADDRESS_LSB);
|
||||||
else
|
else
|
||||||
DccProcState.myDccAddress = ( (readCV (CV_ACCESSORY_DECODER_ADDRESS_MSB) & 0b00000111) << 6) | (readCV (CV_ACCESSORY_DECODER_ADDRESS_LSB) & 0b00111111) ;
|
DccProcState.myDccAddress = ( (readCV (CV_ACCESSORY_DECODER_ADDRESS_MSB) & 0b00000111) << 6) | (readCV (CV_ACCESSORY_DECODER_ADDRESS_LSB) & 0b00111111) ;
|
||||||
@@ -1295,7 +1351,7 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
|
|
||||||
BoardAddress = ( ( (~pDccMsg->Data[1]) & 0b01110000) << 2) | (pDccMsg->Data[0] & 0b00111111) ;
|
BoardAddress = ( ( (~pDccMsg->Data[1]) & 0b01110000) << 2) | (pDccMsg->Data[0] & 0b00111111) ;
|
||||||
TurnoutPairIndex = ( pDccMsg->Data[1] & 0b00000110) >> 1;
|
TurnoutPairIndex = ( pDccMsg->Data[1] & 0b00000110) >> 1;
|
||||||
DB_PRINT("eDP: BAddr:%d, Index:%d", BoardAddress, TurnoutPairIndex);
|
DB_PRINT ("eDP: Board Address: %d, Index: %d", BoardAddress, TurnoutPairIndex);
|
||||||
|
|
||||||
// First check for Legacy Accessory Decoder Configuration Variable Access Instruction
|
// First check for Legacy Accessory Decoder Configuration Variable Access Instruction
|
||||||
// as it's got a different format to the others
|
// as it's got a different format to the others
|
||||||
@@ -1317,16 +1373,15 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OutputAddress = ( ( (BoardAddress - 1) << 2) | TurnoutPairIndex) + 1 ; //decoder output addresses start with 1, packet address range starts with 0
|
OutputAddress = ( ( (BoardAddress - 1) << 2) | TurnoutPairIndex) + 1 ; //decoder output addresses start with 1, packet address range starts with 0
|
||||||
// ( according to NMRA 9.2.2 )
|
// ( according to NMRA 9.2.2 )
|
||||||
DB_PRINT("eDP: OAddr:%d", OutputAddress);
|
DB_PRINT ("eDP: Output Address: %d", OutputAddress);
|
||||||
|
|
||||||
if (DccProcState.inAccDecDCCAddrNextReceivedMode)
|
if (DccProcState.inAccDecDCCAddrNextReceivedMode)
|
||||||
{
|
{
|
||||||
if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE )
|
if (DccProcState.Flags & (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_EXTENDED_ADDRESS_MODE))
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Set OAddr:%d", OutputAddress);
|
DB_PRINT ("eDP: 11-bit Accessory Address: %d", OutputAddress);
|
||||||
//uint16_t storedOutputAddress = OutputAddress + 1; // The value stored in CV1 & 9 for Output Addressing Mode is + 1
|
//uint16_t storedOutputAddress = OutputAddress + 1; // The value stored in CV1 & 9 for Output Addressing Mode is + 1
|
||||||
writeCV (CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t) (OutputAddress % 256));
|
writeCV (CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t) (OutputAddress % 256));
|
||||||
writeCV (CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t) (OutputAddress / 256));
|
writeCV (CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t) (OutputAddress / 256));
|
||||||
@@ -1336,7 +1391,7 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Set BAddr:%d", BoardAddress);
|
DB_PRINT ("eDP: Set 9-bit Board Address: %d", BoardAddress);
|
||||||
writeCV (CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t) (BoardAddress % 64));
|
writeCV (CV_ACCESSORY_DECODER_ADDRESS_LSB, (uint8_t) (BoardAddress % 64));
|
||||||
writeCV (CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t) (BoardAddress / 64));
|
writeCV (CV_ACCESSORY_DECODER_ADDRESS_MSB, (uint8_t) (BoardAddress / 64));
|
||||||
|
|
||||||
@@ -1350,18 +1405,24 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
// If we're filtering addresses, does the address match our address or is it a broadcast address? If NOT then return
|
// If we're filtering addresses, does the address match our address or is it a broadcast address? If NOT then return
|
||||||
if (DccProcState.Flags & FLAGS_MY_ADDRESS_ONLY)
|
if (DccProcState.Flags & FLAGS_MY_ADDRESS_ONLY)
|
||||||
{
|
{
|
||||||
if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE ) {
|
DB_PRINT ("eDP: Check if the Address matches");
|
||||||
DB_PRINT(" AddrChk: OAddr:%d, BAddr:%d, myAddr:%d Chk=%d", OutputAddress, BoardAddress, getMyAddr(), OutputAddress != getMyAddr() );
|
if (DccProcState.Flags & (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_EXTENDED_ADDRESS_MODE))
|
||||||
if ( OutputAddress != getMyAddr() && OutputAddress < 2045 ) {
|
{
|
||||||
|
if (OutputAddress != getMyAddr() && OutputAddress < 2045)
|
||||||
|
{
|
||||||
DB_PRINT ("eDP: OAddr: %d, myAddr: %d - no match", OutputAddress, getMyAddr());
|
DB_PRINT ("eDP: OAddr: %d, myAddr: %d - no match", OutputAddress, getMyAddr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if( ( BoardAddress != getMyAddr() ) && ( BoardAddress < 511 ) ) {
|
else
|
||||||
|
{
|
||||||
|
if ( (BoardAddress != getMyAddr()) && (BoardAddress < 511))
|
||||||
|
{
|
||||||
DB_PRINT ("eDP: BAddr: %d, myAddr: %d - no match", BoardAddress, getMyAddr());
|
DB_PRINT ("eDP: BAddr: %d, myAddr: %d - no match", BoardAddress, getMyAddr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DB_PRINT ("eDP: Address Matched");
|
DB_PRINT ("eDP: Address Matched");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1371,7 +1432,7 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
// According to the NMRA Dcc Spec the Signal State should only use the lower 5 Bits,
|
// According to the NMRA Dcc Spec the Signal State should only use the lower 5 Bits,
|
||||||
// however some manufacturers seem to allow/use all 8 bits, so we'll relax that constraint for now
|
// however some manufacturers seem to allow/use all 8 bits, so we'll relax that constraint for now
|
||||||
uint8_t state = pDccMsg->Data[2] ;
|
uint8_t state = pDccMsg->Data[2] ;
|
||||||
DB_PRINT("eDP: OAddr:%d Extended State:%0X", OutputAddress, state);
|
DB_PRINT ("eDP: Output Address: %d Extended State: %0X", OutputAddress, state);
|
||||||
if (notifyDccSigOutputState)
|
if (notifyDccSigOutputState)
|
||||||
notifyDccSigOutputState (OutputAddress, state);
|
notifyDccSigOutputState (OutputAddress, state);
|
||||||
|
|
||||||
@@ -1389,9 +1450,9 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
if (notifyDccAccState)
|
if (notifyDccAccState)
|
||||||
notifyDccAccState (OutputAddress, BoardAddress, pDccMsg->Data[1] & 0b00000111, outputPower);
|
notifyDccAccState (OutputAddress, BoardAddress, pDccMsg->Data[1] & 0b00000111, outputPower);
|
||||||
|
|
||||||
if( DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE )
|
if (DccProcState.Flags & FLAGS_EXTENDED_ADDRESS_MODE)
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: OAddr:%d Turnout Dir:%d Output Power:%d", OutputAddress, direction, outputPower);
|
DB_PRINT ("eDP: Output Address: %d Turnout Dir: %d Output Power: %d", OutputAddress, direction, outputPower);
|
||||||
if (notifyDccAccTurnoutOutput)
|
if (notifyDccAccTurnoutOutput)
|
||||||
notifyDccAccTurnoutOutput (OutputAddress, direction, outputPower);
|
notifyDccAccTurnoutOutput (OutputAddress, direction, outputPower);
|
||||||
}
|
}
|
||||||
@@ -1404,33 +1465,70 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
|||||||
}
|
}
|
||||||
else if (pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming
|
else if (pDccMsg->Size == 6) // Accessory Decoder OPS Mode Programming
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: OPS Mode CV Programming Command");
|
DB_PRINT ("eDP: Accessory OPS Mode CV Programming Command");
|
||||||
// Check for unsupported OPS Mode Addressing mode
|
// If its a "Basic Accessory Decoder Packet" OPS Command
|
||||||
if(((pDccMsg->Data[1] & 0b10001001) != 1) && ((pDccMsg->Data[1] & 0b10001111) != 0x80))
|
if (pDccMsg->Data[1] & 0x80)
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Unsupported OPS Mode CV Addressing Mode");
|
DB_PRINT ("eDP: Handle Basic OPS Command");
|
||||||
|
|
||||||
|
if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Ignore Basic OPS Command in Signal Address Mode");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this command is for our address or the broadcast address
|
if(pDccMsg->Data[1] & 0b00001111)
|
||||||
if(DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE)
|
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Check Output Address:%d", OutputAddress);
|
DB_PRINT ("eDP: Handle 11-bit Basic OPS Command");
|
||||||
|
if((DccProcState.Flags & FLAGS_EXTENDED_ADDRESS_MODE) == 0)
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Ignore 11-bit Basic OPS Command in Board Address Mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if((OutputAddress != getMyAddr()) && (OutputAddress < 2045))
|
if((OutputAddress != getMyAddr()) && (OutputAddress < 2045))
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Output Address Not Matched");
|
DB_PRINT ("eDP: Extended Address Not Matched");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DB_PRINT("eDP: Check Board Address:%d", BoardAddress);
|
DB_PRINT ("eDP: Handle 9-bit Basic OPS Command");
|
||||||
|
if(DccProcState.Flags & FLAGS_EXTENDED_ADDRESS_MODE)
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Ignore 9-bit Basic OPS Command in Extended Address Mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (BoardAddress != getMyAddr()) && (BoardAddress < 511))
|
if ( (BoardAddress != getMyAddr()) && (BoardAddress < 511))
|
||||||
{
|
{
|
||||||
DB_PRINT ("eDP: Board Address Not Matched");
|
DB_PRINT ("eDP: Board Address Not Matched");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If its a "Extended (Signal) Decoder OPS Command
|
||||||
|
else if ((pDccMsg->Data[1] & 0x81) == 0x01)
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Handle Signal Decoder OPS Command");
|
||||||
|
|
||||||
|
// If we're not in FLAGS_OUTPUT_ADDRESS_MODE then return as this isn't for us
|
||||||
|
if ((DccProcState.Flags & FLAGS_OUTPUT_ADDRESS_MODE) == 0)
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Ignore Signal Decoder OPS Command in Board or Extended Address Mode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this command is for our Output Address or the broadcast address
|
||||||
|
DB_PRINT ("eDP: Compare Signal Address: %d to MyAddr: %d", OutputAddress, getMyAddr());
|
||||||
|
if ( (OutputAddress != getMyAddr()) && (OutputAddress < 2045))
|
||||||
|
{
|
||||||
|
DB_PRINT ("eDP: Signal Address Not Matched");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t cvAddress = ( (pDccMsg->Data[2] & 0b00000011) << 8) + pDccMsg->Data[3] + 1;
|
uint16_t cvAddress = ( (pDccMsg->Data[2] & 0b00000011) << 8) + pDccMsg->Data[3] + 1;
|
||||||
uint8_t cvValue = pDccMsg->Data[4];
|
uint8_t cvValue = pDccMsg->Data[4];
|
||||||
@@ -1510,7 +1608,8 @@ void NmraDcc::pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup
|
|||||||
// because STM32F1 has a NVIC we must set interuptpriorities
|
// because STM32F1 has a NVIC we must set interuptpriorities
|
||||||
const nvic_irq_num irqNum2nvic[] = { NVIC_EXTI0, NVIC_EXTI1, NVIC_EXTI2, NVIC_EXTI3, NVIC_EXTI4,
|
const nvic_irq_num irqNum2nvic[] = { NVIC_EXTI0, NVIC_EXTI1, NVIC_EXTI2, NVIC_EXTI3, NVIC_EXTI4,
|
||||||
NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5,
|
NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5, NVIC_EXTI_9_5,
|
||||||
NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10 };
|
NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10, NVIC_EXTI_15_10
|
||||||
|
};
|
||||||
exti_num irqNum = (exti_num) (PIN_MAP[ExtIntPinNum].gpio_bit);
|
exti_num irqNum = (exti_num) (PIN_MAP[ExtIntPinNum].gpio_bit);
|
||||||
|
|
||||||
// DCC-Input IRQ must be able to interrupt other long low priority ( level15 ) IRQ's
|
// DCC-Input IRQ must be able to interrupt other long low priority ( level15 ) IRQ's
|
||||||
@@ -1542,10 +1641,7 @@ void NmraDcc::initAccessoryDecoder( uint8_t ManufacturerId, uint8_t VersionId, u
|
|||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
void NmraDcc::init (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV)
|
void NmraDcc::init (uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV)
|
||||||
{
|
{
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
EEPROM.begin(MAXCV);
|
|
||||||
#endif
|
|
||||||
#if defined(ESP32)
|
|
||||||
EEPROM.begin (MAXCV);
|
EEPROM.begin (MAXCV);
|
||||||
#endif
|
#endif
|
||||||
// Clear all the static member variables
|
// Clear all the static member variables
|
||||||
@@ -1674,6 +1770,15 @@ uint8_t NmraDcc::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
|
if(DccProcState.eepromChanged && (DccProcState.millisSinceEEPromWrite >= EEPROM_COMMIT_DELAY_MS))
|
||||||
|
{
|
||||||
|
EEPROM.commit();
|
||||||
|
DccProcState.eepromChanged = false;
|
||||||
|
DB_PRINT ("process: EEPROM Commit");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (DccRx.DataReady)
|
if (DccRx.DataReady)
|
||||||
{
|
{
|
||||||
// We need to do this check with interrupts disabled
|
// We need to do this check with interrupts disabled
|
||||||
@@ -1703,5 +1808,7 @@ uint8_t NmraDcc::process()
|
|||||||
return 1 ;
|
return 1 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0 ;
|
return 0 ;
|
||||||
};
|
};
|
||||||
@@ -81,6 +81,10 @@ typedef struct
|
|||||||
#define MAN_ID_DIY 0x0D
|
#define MAN_ID_DIY 0x0D
|
||||||
#define MAN_ID_SILICON_RAILWAY 0x21
|
#define MAN_ID_SILICON_RAILWAY 0x21
|
||||||
|
|
||||||
|
#if defined(ESP8266) || defined(ESP32) || defined(ARDUINO_ARCH_RP2040)
|
||||||
|
#define EEPROM_COMMIT_DELAY_MS 3000
|
||||||
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
// This section contains the Product/Version Id Codes for projects
|
// This section contains the Product/Version Id Codes for projects
|
||||||
//
|
//
|
||||||
@@ -94,6 +98,10 @@ typedef struct
|
|||||||
|
|
||||||
// Product/Version Id Codes allocated under: MAN_ID_DIY
|
// Product/Version Id Codes allocated under: MAN_ID_DIY
|
||||||
|
|
||||||
|
#define DEFAULT_MULTIFUNCTION_DECODER_ADDRESS 3
|
||||||
|
#define DEFAULT_ACCESSORY_DECODER_ADDRESS 1
|
||||||
|
|
||||||
|
|
||||||
// Standard CV Addresses
|
// Standard CV Addresses
|
||||||
#define CV_ACCESSORY_DECODER_ADDRESS_LSB 1
|
#define CV_ACCESSORY_DECODER_ADDRESS_LSB 1
|
||||||
#define CV_ACCESSORY_DECODER_ADDRESS_MSB 9
|
#define CV_ACCESSORY_DECODER_ADDRESS_MSB 9
|
||||||
@@ -102,9 +110,14 @@ typedef struct
|
|||||||
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB 17
|
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB 17
|
||||||
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB 18
|
#define CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB 18
|
||||||
|
|
||||||
|
#define CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(x) (x & 0xFF)
|
||||||
|
#define CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(x) (((x>>8) & 0x7F) + 192)
|
||||||
|
|
||||||
#define CV_VERSION_ID 7
|
#define CV_VERSION_ID 7
|
||||||
#define CV_MANUFACTURER_ID 8
|
#define CV_MANUFACTURER_ID 8
|
||||||
#define CV_29_CONFIG 29
|
#define CV_29_CONFIG 29
|
||||||
|
#define CV_MANUFACTURER_START 33
|
||||||
|
|
||||||
|
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
#include <esp_spi_flash.h>
|
#include <esp_spi_flash.h>
|
||||||
@@ -118,11 +131,15 @@ typedef struct
|
|||||||
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
|
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
|
||||||
#define PRIO_DCC_IRQ 9
|
#define PRIO_DCC_IRQ 9
|
||||||
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
|
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
|
||||||
|
#elif defined(ARDUINO_ARCH_RP2040)
|
||||||
|
#define MAXCV 256 // todo: maybe somebody knows a good define for it
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
|
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
|
CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
|
||||||
CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
|
CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
|
||||||
CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
|
CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
|
||||||
@@ -133,7 +150,8 @@ typedef enum {
|
|||||||
CV29_ACCESSORY_DECODER = 0b10000000, /** bit 7: "0" = Multi-Function Decoder Mode "1" = Accessory Decoder Mode */
|
CV29_ACCESSORY_DECODER = 0b10000000, /** bit 7: "0" = Multi-Function Decoder Mode "1" = Accessory Decoder Mode */
|
||||||
} CV_29_BITS;
|
} CV_29_BITS;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||||
SPEED_STEP_14 = 15, /**< ESTOP=0, 1 to 15 */
|
SPEED_STEP_14 = 15, /**< ESTOP=0, 1 to 15 */
|
||||||
#endif
|
#endif
|
||||||
@@ -141,12 +159,14 @@ typedef enum {
|
|||||||
SPEED_STEP_128 = 127 /**< ESTOP=0, 1 to 127 */
|
SPEED_STEP_128 = 127 /**< ESTOP=0, 1 to 127 */
|
||||||
} DCC_SPEED_STEPS;
|
} DCC_SPEED_STEPS;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
DCC_DIR_REV = 0, /** The locomotive to go in the reverse direction */
|
DCC_DIR_REV = 0, /** The locomotive to go in the reverse direction */
|
||||||
DCC_DIR_FWD = 1, /** The locomotive should move in the forward direction */
|
DCC_DIR_FWD = 1, /** The locomotive should move in the forward direction */
|
||||||
} DCC_DIRECTION;
|
} DCC_DIRECTION;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum
|
||||||
|
{
|
||||||
DCC_ADDR_SHORT, /** Short address is used. The range is 0 to 127. */
|
DCC_ADDR_SHORT, /** Short address is used. The range is 0 to 127. */
|
||||||
DCC_ADDR_LONG, /** Long Address is used. The range is 1 to 10239 */
|
DCC_ADDR_LONG, /** Long Address is used. The range is 1 to 10239 */
|
||||||
} DCC_ADDR_TYPE;
|
} DCC_ADDR_TYPE;
|
||||||
@@ -199,7 +219,8 @@ typedef enum
|
|||||||
|
|
||||||
// #define DCC_DBGVAR
|
// #define DCC_DBGVAR
|
||||||
#ifdef DCC_DBGVAR
|
#ifdef DCC_DBGVAR
|
||||||
typedef struct countOf_t {
|
typedef struct countOf_t
|
||||||
|
{
|
||||||
unsigned long Tel;
|
unsigned long Tel;
|
||||||
unsigned long Err;
|
unsigned long Err;
|
||||||
} countOf_t ;
|
} countOf_t ;
|
||||||
@@ -219,11 +240,17 @@ class NmraDcc
|
|||||||
#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
|
#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
|
||||||
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
|
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
|
||||||
#define FLAGS_SETCV_CALLED 0x10 // only used internally !!
|
#define FLAGS_SETCV_CALLED 0x10 // only used internally !!
|
||||||
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6
|
#define FLAGS_EXTENDED_ADDRESS_MODE 0x20 // CV 29/541 bit 5 0 = 9-bit Board or Decoder Addressing mode, 1 = 11-bit Extended Address using middle 2 DD of the CDDD bits for the extra 2 bits
|
||||||
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7
|
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 0 = Board or Extended Addressing Mode, 1 = Signal Decoder Output Addressing Mode
|
||||||
|
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 0 = Multifunction Decoder, 1 = Accessory Decoder
|
||||||
|
|
||||||
|
#define FLAGS_MULTIFUNCTION_DECODER ()
|
||||||
|
#define FLAGS_BASIC_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER)
|
||||||
|
#define FLAGS_EXTENDED_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER | FLAGS_EXTENDED_ADDRESS_MODE)
|
||||||
|
#define FLAGS_SIGNAL_ACCESSORY_DECODER (FLAGS_DCC_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE)
|
||||||
|
|
||||||
// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder
|
// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder
|
||||||
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
|
#define FLAGS_CV29_BITS (FLAGS_EXTENDED_ACCESSORY_DECODER | FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
|
||||||
|
|
||||||
|
|
||||||
/*+
|
/*+
|
||||||
@@ -493,7 +520,7 @@ extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP Fu
|
|||||||
|
|
||||||
/*+
|
/*+
|
||||||
* notifyDccAccTurnoutBoard() Board oriented callback for a turnout accessory decoder.
|
* notifyDccAccTurnoutBoard() Board oriented callback for a turnout accessory decoder.
|
||||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
* Most useful when CV29_OUTPUT_ADDRESS_MODE is NOT set.
|
||||||
* Decoders of this type have 4 paired turnout outputs per board.
|
* Decoders of this type have 4 paired turnout outputs per board.
|
||||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||||
*
|
*
|
||||||
@@ -514,8 +541,7 @@ extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP Fu
|
|||||||
extern void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower) __attribute__ ( (weak));
|
extern void notifyDccAccTurnoutBoard (uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower) __attribute__ ( (weak));
|
||||||
/*+
|
/*+
|
||||||
* notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder.
|
* notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder.
|
||||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
* Most useful when CV29_OUTPUT_ADDRESS_MODE IS set.
|
||||||
* Decoders of this type have 4 paired turnout outputs per board.
|
|
||||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||||
*
|
*
|
||||||
* Inputs:
|
* Inputs:
|
||||||
|
|||||||
@@ -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 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)
|
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'
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
#include <AccelStepper.h>
|
#include <AccelStepper.h>
|
||||||
#include <NmraDcc.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
|
// The lines below define the pins used to connect to the A4988 driver module
|
||||||
#define A4988_STEP_PIN 4
|
#define A4988_STEP_PIN 4
|
||||||
#define A4988_DIRECTION_PIN 5
|
#define A4988_DIRECTION_PIN 5
|
||||||
@@ -244,7 +247,13 @@ void setupDCCDecoder()
|
|||||||
Serial.println(F("Setting up DCC Decorder..."));
|
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
|
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||||
Dcc.pin(0, 2, 1);
|
// 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
|
// 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 );
|
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
|
||||||
|
|||||||
@@ -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.
+735
@@ -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.
|
||||||
|
*/
|
||||||
+735
@@ -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.
|
||||||
|
*/
|
||||||
+1149
File diff suppressed because it is too large.
Load diff
+1149
File diff suppressed because it is too large.
Load diff
+1149
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
@@ -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 ;
|
NmraDcc Dcc ;
|
||||||
DCC_MSG Packet ;
|
DCC_MSG Packet ;
|
||||||
|
|
||||||
|
// Define the Arduino input Pin number for the DCC Signal
|
||||||
|
#define DCC_PIN 2
|
||||||
|
|
||||||
struct CVPair
|
struct CVPair
|
||||||
{
|
{
|
||||||
uint16_t CV;
|
uint16_t CV;
|
||||||
@@ -15,8 +18,8 @@ struct CVPair
|
|||||||
|
|
||||||
CVPair FactoryDefaultCVs [] =
|
CVPair FactoryDefaultCVs [] =
|
||||||
{
|
{
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
|
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t FactoryDefaultCVIndex = 0;
|
uint8_t FactoryDefaultCVIndex = 0;
|
||||||
@@ -92,6 +95,8 @@ void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
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
|
// Configure the DCC CV Programing ACK pin for an output
|
||||||
pinMode( DccAckPin, OUTPUT );
|
pinMode( DccAckPin, OUTPUT );
|
||||||
@@ -99,7 +104,13 @@ void setup()
|
|||||||
Serial.println("NMRA DCC Example 1");
|
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
|
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||||
Dcc.pin(0, 2, 1);
|
// 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
|
// 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 );
|
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
|
// 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 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 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
|
#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 [] =
|
CVPair FactoryDefaultCVs [] =
|
||||||
{
|
{
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1}, // CV 1 Board Address (lower 6 bits)
|
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, // CV 9 Board Address (Upper 3 bits)
|
{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_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_CDU_RECHARGE_TIME, 30}, // x 10mS for the CDU recharge delay time
|
||||||
{CV_ACCESSORY_DECODER_ACTIVE_STATE, ACTIVE_OUTPUT_STATE},
|
{CV_ACCESSORY_DECODER_ACTIVE_STATE, ACTIVE_OUTPUT_STATE},
|
||||||
@@ -119,7 +122,13 @@ void setup()
|
|||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
// 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
|
||||||
Dcc.pin(0, 2, 1);
|
// 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
|
// Call the main DCC Init function to enable the DCC Receiver
|
||||||
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, CV29_ACCESSORY_DECODER, 0 );
|
Dcc.init( MAN_ID_DIY, DCC_DECODER_VERSION_NUM, CV29_ACCESSORY_DECODER, 0 );
|
||||||
|
|||||||
+377
@@ -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>
|
#include <NmraDcc.h>
|
||||||
|
|
||||||
#define This_Decoder_Address 3
|
// Define the Arduino input Pin number for the DCC Signal
|
||||||
|
#define DCC_PIN 2
|
||||||
|
|
||||||
struct CVPair
|
struct CVPair
|
||||||
{
|
{
|
||||||
@@ -11,11 +12,11 @@ struct CVPair
|
|||||||
CVPair FactoryDefaultCVs [] =
|
CVPair FactoryDefaultCVs [] =
|
||||||
{
|
{
|
||||||
// The CV Below defines the Short DCC Address
|
// 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
|
// These two CVs define the Long DCC Address
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_MULTIFUNCTION_DECODER_ADDRESS)},
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, This_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
|
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||||
@@ -170,7 +171,13 @@ void setup()
|
|||||||
digitalWrite( DccAckPin, LOW );
|
digitalWrite( DccAckPin, LOW );
|
||||||
|
|
||||||
// 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
|
||||||
Dcc.pin(0, 2, 0);
|
// 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
|
// 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 );
|
//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
|
// This section defines the Arduino UNO Pins to use
|
||||||
#ifdef __AVR_ATmega328P__
|
#ifdef __AVR_ATmega328P__
|
||||||
|
|
||||||
|
// Define the Arduino input Pin number for the DCC Signal
|
||||||
#define DCC_PIN 2
|
#define DCC_PIN 2
|
||||||
|
|
||||||
#define LED_PIN_FWD 5
|
#define LED_PIN_FWD 5
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
// This section defines the Arduino ATTiny85 Pins to use
|
// This section defines the Arduino ATTiny85 Pins to use
|
||||||
#elif ARDUINO_AVR_ATTINYX5
|
#elif ARDUINO_AVR_ATTINYX5
|
||||||
|
|
||||||
|
// Define the Arduino input Pin number for the DCC Signal
|
||||||
#define DCC_PIN 2
|
#define DCC_PIN 2
|
||||||
|
|
||||||
#define LED_PIN_FWD 0
|
#define LED_PIN_FWD 0
|
||||||
@@ -89,8 +91,8 @@ CVPair FactoryDefaultCVs [] =
|
|||||||
{CV_VHIGH, 255},
|
{CV_VHIGH, 255},
|
||||||
|
|
||||||
// These two CVs define the Long DCC Address
|
// These two CVs define the Long DCC Address
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_DECODER_ADDRESS)},
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 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
|
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||||
@@ -218,7 +220,13 @@ void setup()
|
|||||||
|
|
||||||
|
|
||||||
// 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);
|
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 );
|
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
||||||
|
|
||||||
@@ -292,8 +300,8 @@ void loop()
|
|||||||
#ifdef DEBUG_FUNCTIONS
|
#ifdef DEBUG_FUNCTIONS
|
||||||
Serial.println("LED On");
|
Serial.println("LED On");
|
||||||
#endif
|
#endif
|
||||||
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
|
digitalWrite(LED_PIN_FWD, newDirection ? HIGH : LOW);
|
||||||
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
|
digitalWrite(LED_PIN_REV, newDirection ? LOW : HIGH);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#include <NmraDcc.h>
|
|
||||||
|
|
||||||
// This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
|
// 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
|
// 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
|
// JP6 - Boards without VIO - User Choice
|
||||||
// JP7 - Enable Programming ACK - 1-2 ON 3-4 ON
|
// 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
|
// 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
|
// you can also print every DCC packet by uncommenting the "#define NOTIFY_DCC_MSG" line below
|
||||||
#define NOTIFY_DCC_MSG
|
#define NOTIFY_DCC_MSG
|
||||||
@@ -26,6 +27,9 @@
|
|||||||
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
|
// 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 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 ;
|
NmraDcc Dcc ;
|
||||||
|
|
||||||
struct CVPair
|
struct CVPair
|
||||||
@@ -36,8 +40,8 @@ struct CVPair
|
|||||||
|
|
||||||
CVPair FactoryDefaultCVs [] =
|
CVPair FactoryDefaultCVs [] =
|
||||||
{
|
{
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
|
{CV_ACCESSORY_DECODER_ADDRESS_LSB, DEFAULT_ACCESSORY_DECODER_ADDRESS & 0xFF},
|
||||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
{CV_ACCESSORY_DECODER_ADDRESS_MSB, DEFAULT_ACCESSORY_DECODER_ADDRESS >> 8},
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t FactoryDefaultCVIndex = 0;
|
uint8_t FactoryDefaultCVIndex = 0;
|
||||||
@@ -98,11 +102,19 @@ void notifyCVChange(uint16_t CV, uint8_t Value)
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
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");
|
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
|
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||||
Dcc.pin(0, 2, 1);
|
// 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
|
// Call the main DCC Init function to enable the DCC Receiver
|
||||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
|
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ CVPair FactoryDefaultCVs [] =
|
|||||||
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
|
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
|
||||||
|
|
||||||
// These two CVs define the Long DCC Address
|
// These two CVs define the Long DCC Address
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // Extended address MSB.
|
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DECODER_ADDR)},
|
||||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DECODER_ADDR}, // Extended address LSB.
|
{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_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
||||||
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
|
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
name=NmraDcc
|
name=NmraDcc
|
||||||
version=2.0.6
|
version=2.0.11
|
||||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
|
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>
|
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
||||||
sentence=Enables NMRA DCC Communication
|
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.
|
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.
|
||||||
|
|||||||
Executable
+20
@@ -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
|
||||||
Reference in new issue
Block a user