Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5efcaaeb6b | |||
| d1e4a2b83d | |||
| 3e7ac4967c | |||
| 29e90c7c9c | |||
| a8d3a32d07 | |||
| 644fe9abff | |||
| 771d2ae722 | |||
| 8184159c87 | |||
| 6d23aa0993 | |||
| b0ac4a4f6f | |||
| 3bbdad9f8f | |||
| c18ed5b703 | |||
| 37bb3f8e66 | |||
| 70b5530bb4 | |||
| 8574dda01c | |||
| 90e40f8f91 | |||
| 6ed5a97e30 | |||
| e0ceeafcb9 | |||
| 8ca2e03264 | |||
| e6a9f9a825 | |||
| 06999ee778 | |||
| 0277afd827 | |||
| 209256ff44 | |||
| 84fb903af2 | |||
| fd5246040f | |||
| e9e9684c08 | |||
| 1a51b94ad3 |
@@ -1,2 +0,0 @@
|
||||
.development
|
||||
*.zip
|
||||
+162
-420
@@ -2,21 +2,11 @@
|
||||
//
|
||||
// Model Railroading with Arduino - NmraDcc.cpp
|
||||
//
|
||||
// Copyright (c) 2008 - 2020 Alex Shepherd
|
||||
// Copyright (c) 2008 - 2017 Alex Shepherd
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// This source file is subject of the GNU general public license 2,
|
||||
// that is available at the world-wide-web at
|
||||
// http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
@@ -35,9 +25,7 @@
|
||||
// 2017-01-19 added STM32F1 support by Franz-Peter
|
||||
// 2017-11-29 Ken West (kgw4449@gmail.com):
|
||||
// Minor fixes to pass NMRA Baseline Conformance Tests.
|
||||
// 2018-12-17 added ESP32 support by Trusty (thierry@lapajaparis.net)
|
||||
// 2019-02-17 added ESP32 specific changes by Hans Tanner
|
||||
// 2020-05-15 changes to pass NMRA Tests ( always search for preamble )
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// purpose: Provide a simplified interface to decode NMRA DCC packets
|
||||
@@ -46,10 +34,12 @@
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include "NmraDcc.h"
|
||||
#include "EEPROM.h"
|
||||
#ifdef __AVR_MEGA__
|
||||
#include <avr/eeprom.h>
|
||||
#endif
|
||||
|
||||
// Uncomment to print DEBUG messages
|
||||
// #define DEBUG_PRINT
|
||||
//#define DEBUG_PRINT
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// DCC Receive Routine
|
||||
@@ -82,33 +72,26 @@
|
||||
// DCC 1: _________XXXXXXXXX_________XXXXXXXXX_________
|
||||
// |<--------146us------>|
|
||||
// ^-INTx ^-INTx
|
||||
// less than 146us: its a one-Bit
|
||||
// less than 138us: its a one-Bit
|
||||
//
|
||||
//
|
||||
// |<-----------------232us----------->|
|
||||
// DCC 0: _________XXXXXXXXXXXXXXXXXX__________________XXXXXXXX__________
|
||||
// |<--------146us------->|
|
||||
// ^-INTx ^-INTx
|
||||
// greater than 146us: its a zero bit
|
||||
// greater than 138us: its a zero bit
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// if this is commented out, bit synchronisation is only done after a wrong checksum
|
||||
#define SYNC_ALWAYS
|
||||
|
||||
// if this is commented out, Zero-Bit_Stretching is not supported
|
||||
// ( Bits longer than 2* MAX ONEBIT are treated as error )
|
||||
#define SUPPORT_ZERO_BIT_STRETCHING
|
||||
|
||||
#define MAX_ONEBITFULL 146
|
||||
#define MAX_PRAEAMBEL 146
|
||||
#define MAX_ONEBITHALF 82
|
||||
#define MIN_ONEBITFULL 82
|
||||
#define MIN_ONEBITHALF 35
|
||||
#define MAX_BITDIFF 24
|
||||
#define MAX_BITDIFF 18
|
||||
|
||||
|
||||
// Debug-Ports
|
||||
@@ -191,22 +174,9 @@
|
||||
#define MODE_TP3 pinMode( D7,OUTPUT ) ; // GPIO 13
|
||||
#define SET_TP3 GPOS = (1 << D7);
|
||||
#define CLR_TP3 GPOC = (1 << D7);
|
||||
#define MODE_TP4 pinMode( D8,OUTPUT ) ; // GPIO 15
|
||||
#define SET_TP4 GPOS = (1 << D8);
|
||||
#define MODE_TP4 pinMode( D7,OUTPUT ); // GPIO 15
|
||||
#define SET_TP4 GPOC = (1 << D8);
|
||||
#define CLR_TP4 GPOC = (1 << D8);
|
||||
#elif defined(ESP32)
|
||||
#define MODE_TP1 pinMode( 33,OUTPUT ) ; // GPIO 33
|
||||
#define SET_TP1 GPOS = (1 << 33);
|
||||
#define CLR_TP1 GPOC = (1 << 33);
|
||||
#define MODE_TP2 pinMode( 25,OUTPUT ) ; // GPIO 25
|
||||
#define SET_TP2 GPOS = (1 << 25);
|
||||
#define CLR_TP2 GPOC = (1 << 25);
|
||||
#define MODE_TP3 pinMode( 26,OUTPUT ) ; // GPIO 26
|
||||
#define SET_TP3 GPOS = (1 << 26);
|
||||
#define CLR_TP3 GPOC = (1 << 26);
|
||||
#define MODE_TP4 pinMode( 27,OUTPUT ) ; // GPIO 27
|
||||
#define SET_TP4 GPOS = (1 << 27);
|
||||
#define CLR_TP4 GPOC = (1 << 27);
|
||||
|
||||
|
||||
//#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
|
||||
@@ -232,12 +202,18 @@
|
||||
#define MODE_TP2
|
||||
#define SET_TP2
|
||||
#define CLR_TP2
|
||||
//#define MODE_TP2 DDRC |= (1<<2) // A2
|
||||
//#define SET_TP2 PORTC |= (1<<2)
|
||||
//#define CLR_TP2 PORTC &= ~(1<<2)
|
||||
#define MODE_TP3
|
||||
#define SET_TP3
|
||||
#define CLR_TP3
|
||||
#define MODE_TP4
|
||||
#define SET_TP4
|
||||
#define CLR_TP4
|
||||
//#define MODE_TP4 DDRC |= (1<<4) //A4
|
||||
//#define SET_TP4 PORTC |= (1<<4)
|
||||
//#define CLR_TP4 PORTC &= ~(1<<4)
|
||||
|
||||
#endif
|
||||
#ifdef DEBUG_PRINT
|
||||
@@ -254,24 +230,15 @@ struct countOf_t countOf;
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
static ExtIntTriggerMode ISREdge;
|
||||
#elif defined ( ESP32 )
|
||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||
#else
|
||||
static byte ISREdge; // Holder of the Next Edge we're looking for: RISING or FALLING
|
||||
static byte ISRWatch; // Interrupt Handler Edge Filter
|
||||
static byte ISREdge; // RISING or FALLING
|
||||
#endif
|
||||
byte ISRLevel; // expected Level at DCC input during ISR ( to detect glitches )
|
||||
byte ISRChkMask; // Flag if Level must be checked
|
||||
static word bitMax, bitMin;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WAIT_PREAMBLE = 0,
|
||||
WAIT_START_BIT,
|
||||
#ifndef SYNC_ALWAYS
|
||||
WAIT_START_BIT_FULL,
|
||||
#endif
|
||||
WAIT_DATA,
|
||||
WAIT_END_BIT
|
||||
}
|
||||
@@ -292,7 +259,6 @@ struct DccRx_t
|
||||
uint8_t DataReady ;
|
||||
uint8_t BitCount ;
|
||||
uint8_t TempByte ;
|
||||
uint8_t chkSum;
|
||||
DCC_MSG PacketBuf;
|
||||
DCC_MSG PacketCopy;
|
||||
}
|
||||
@@ -309,11 +275,8 @@ typedef struct
|
||||
DCC_MSG LastMsg ;
|
||||
uint8_t ExtIntNum;
|
||||
uint8_t ExtIntPinNum;
|
||||
volatile uint8_t *ExtIntPort; // use port and bitmask to read input at AVR in ISR
|
||||
uint8_t ExtIntMask; // digitalRead is too slow on AVR
|
||||
int16_t myDccAddress; // Cached value of DCC Address from CVs
|
||||
uint8_t inAccDecDCCAddrNextReceivedMode;
|
||||
uint8_t cv29Value;
|
||||
uint8_t inAccDecDCCAddrNextReceivedMode;
|
||||
#ifdef DCC_DEBUG
|
||||
uint8_t IntCount;
|
||||
uint8_t TickCount;
|
||||
@@ -324,48 +287,14 @@ DCC_PROCESSOR_STATE ;
|
||||
|
||||
DCC_PROCESSOR_STATE DccProcState ;
|
||||
|
||||
#ifdef ESP32
|
||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
void IRAM_ATTR ExternalInterruptHandler(void)
|
||||
#elif defined(ESP8266)
|
||||
void ICACHE_RAM_ATTR ExternalInterruptHandler(void)
|
||||
#else
|
||||
void ExternalInterruptHandler(void)
|
||||
#endif
|
||||
{
|
||||
SET_TP3;
|
||||
|
||||
#ifdef ESP32
|
||||
// switch (ISRWatch)
|
||||
// {
|
||||
// case RISING: if (digitalRead(DccProcState.ExtIntPinNum)) break;
|
||||
// case FALLING: if (digitalRead(DccProcState.ExtIntPinNum)) return; break;
|
||||
// }
|
||||
// First compare the edge we're looking for to the pin state
|
||||
switch (ISRWatch)
|
||||
{
|
||||
case CHANGE:
|
||||
break;
|
||||
|
||||
case RISING:
|
||||
if (digitalRead(DccProcState.ExtIntPinNum) != HIGH)
|
||||
return;
|
||||
break;
|
||||
|
||||
case FALLING:
|
||||
if (digitalRead(DccProcState.ExtIntPinNum) != LOW)
|
||||
return;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// Bit evaluation without Timer 0 ------------------------------
|
||||
uint8_t DccBitVal;
|
||||
static int8_t bit1, bit2 ;
|
||||
static unsigned int lastMicros = 0;
|
||||
static byte halfBit, DCC_IrqRunning, preambleBitCount;
|
||||
static word lastMicros;
|
||||
static byte halfBit, DCC_IrqRunning;
|
||||
unsigned int actMicros, bitMicros;
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
if ( DCC_IrqRunning ) {
|
||||
// nested DCC IRQ - obviously there are glitches
|
||||
// ignore this interrupt and increment glitchcounter
|
||||
@@ -376,94 +305,57 @@ void ExternalInterruptHandler(void)
|
||||
SET_TP3;
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
#endif
|
||||
SET_TP3;
|
||||
actMicros = micros();
|
||||
bitMicros = actMicros-lastMicros;
|
||||
|
||||
CLR_TP3; SET_TP3;
|
||||
#ifdef __AVR_MEGA__
|
||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && (*DccProcState.ExtIntPort & DccProcState.ExtIntMask) != (ISRLevel) ) ) {
|
||||
#else
|
||||
if ( bitMicros < bitMin || ( DccRx.State != WAIT_START_BIT && digitalRead( DccProcState.ExtIntPinNum ) != (ISRLevel) ) ) {
|
||||
#endif
|
||||
// too short - my be false interrupt due to glitch or false protocol or level does not match RISING / FALLING edge -> ignore this IRQ
|
||||
if ( bitMicros < bitMin ) {
|
||||
// too short - my be false interrupt due to glitch or false protocol -> ignore
|
||||
CLR_TP3;
|
||||
SET_TP4; /*delayMicroseconds(1); */ CLR_TP4;
|
||||
SET_TP4; CLR_TP4;
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
CLR_TP3; SET_TP3;
|
||||
|
||||
lastMicros = actMicros;
|
||||
#ifndef SUPPORT_ZERO_BIT_STRETCHING
|
||||
//if ( bitMicros > MAX_ZEROBITFULL ) {
|
||||
if ( bitMicros > (bitMax*2) ) {
|
||||
// too long - my be false protocol -> start over
|
||||
DccRx.State = WAIT_PREAMBLE ;
|
||||
DccRx.BitCount = 0 ;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
CLR_TP3;
|
||||
//CLR_TP3;
|
||||
return; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> abort IRQ
|
||||
}
|
||||
CLR_TP3;
|
||||
SET_TP3;
|
||||
#endif
|
||||
|
||||
DccBitVal = ( bitMicros < bitMax );
|
||||
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
lastMicros = actMicros;
|
||||
#ifdef debug
|
||||
if(DccBitVal) {SET_TP2;} else {CLR_TP2;};
|
||||
#endif
|
||||
DCC_IrqRunning = true;
|
||||
interrupts(); // time critical is only the micros() command,so allow nested irq's
|
||||
#endif
|
||||
|
||||
#ifdef DCC_DEBUG
|
||||
DccProcState.TickCount++;
|
||||
#endif
|
||||
|
||||
switch( DccRx.State )
|
||||
{
|
||||
case WAIT_PREAMBLE:
|
||||
// We don't have to do anything special - looking for a preamble condition is done always
|
||||
SET_TP2;
|
||||
break;
|
||||
|
||||
#ifndef SYNC_ALWAYS
|
||||
case WAIT_START_BIT_FULL:
|
||||
// wait for startbit without level checking
|
||||
if ( !DccBitVal ) {
|
||||
// we got the startbit
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
if( DccBitVal )
|
||||
{
|
||||
SET_TP1;
|
||||
DccRx.BitCount++;
|
||||
if( DccRx.BitCount > 10 ) {
|
||||
DccRx.State = WAIT_START_BIT ;
|
||||
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
||||
// sync and detect whether we see a false (e.g. motorola) protocol
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||
halfBit = 0;
|
||||
bitMax = MAX_ONEBITHALF;
|
||||
bitMin = MIN_ONEBITHALF;
|
||||
CLR_TP1;
|
||||
// initialize packet buffer
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
}
|
||||
} else {
|
||||
SET_TP1;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
CLR_TP1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case WAIT_START_BIT:
|
||||
// we are looking for first half "0" bit after preamble
|
||||
switch ( halfBit ) {
|
||||
case 0:
|
||||
case 0: //SET_TP1;
|
||||
// check first part
|
||||
if ( DccBitVal ) {
|
||||
// is still 1-bit (Preamble)
|
||||
@@ -471,135 +363,108 @@ void ExternalInterruptHandler(void)
|
||||
bit1=bitMicros;
|
||||
} else {
|
||||
// was "0" half bit, maybe the startbit
|
||||
halfBit = 4;
|
||||
}
|
||||
SET_TP1;
|
||||
halfBit = 4;
|
||||
CLR_TP1;
|
||||
}
|
||||
break;
|
||||
case 1: // previous halfbit was '1'
|
||||
case 1: //SET_TP1; // previous halfbit was '1'
|
||||
if ( DccBitVal ) {
|
||||
// its a '1' halfBit -> we are still in the preamble
|
||||
halfBit = 0;
|
||||
bit2=bitMicros;
|
||||
preambleBitCount++;
|
||||
DccRx.BitCount++;
|
||||
if( abs(bit2-bit1) > MAX_BITDIFF ) {
|
||||
// the length of the 2 halfbits differ too much -> wrong protokoll
|
||||
CLR_TP2;
|
||||
CLR_TP3;
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
#if defined ( __STM32F1__ )
|
||||
DccRx.BitCount = 0;
|
||||
SET_TP4;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
// enable level checking ( with direct port reading @ AVR )
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
#endif
|
||||
SET_TP3;
|
||||
CLR_TP4;
|
||||
CLR_TP4;
|
||||
}
|
||||
} else {
|
||||
// first '0' half detected in second halfBit
|
||||
// wrong sync or not a DCC protokoll
|
||||
CLR_TP3;
|
||||
halfBit = 3;
|
||||
SET_TP3;
|
||||
CLR_TP3;
|
||||
halfBit = 3;
|
||||
SET_TP3;
|
||||
}
|
||||
break;
|
||||
case 3: // previous halfbit was '0' in second halfbit
|
||||
case 3: //SET_TP1; // previous halfbit was '0' in second halfbit
|
||||
if ( DccBitVal ) {
|
||||
// its a '1' halfbit -> we got only a half '0' bit -> cannot be DCC
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
// SET_TP2; CLR_TP2;
|
||||
DccRx.BitCount = 0;
|
||||
} else {
|
||||
// we got two '0' halfbits -> it's the startbit
|
||||
// but sync is NOT ok, change IRQ edge.
|
||||
CLR_TP2;CLR_TP1;
|
||||
if ( ISREdge == RISING ) ISREdge = FALLING; else ISREdge = RISING;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
CLR_TP1;
|
||||
bitMax = MAX_ONEBITFULL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
}
|
||||
//SET_TP4;
|
||||
DccRx.PacketBuf.PreambleBits = 0;
|
||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
//CLR_TP4;
|
||||
DccRx.PacketBuf.PreambleBits = DccRx.BitCount;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
}
|
||||
SET_TP4;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
CLR_TP1;
|
||||
CLR_TP4;
|
||||
break;
|
||||
case 4: // previous (first) halfbit was 0
|
||||
case 4: SET_TP1; // previous (first) halfbit was 0
|
||||
// if this halfbit is 0 too, we got the startbit
|
||||
if ( DccBitVal ) {
|
||||
// second halfbit is 1 -> unknown protokoll
|
||||
DccRx.State = WAIT_PREAMBLE;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
preambleBitCount = 0;
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.BitCount = 0;
|
||||
} else {
|
||||
// we got the startbit
|
||||
CLR_TP2;CLR_TP1;
|
||||
DccRx.State = WAIT_DATA ;
|
||||
CLR_TP1;
|
||||
bitMax = MAX_ONEBITFULL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
// initialize packet buffer
|
||||
DccRx.PacketBuf.Size = 0;
|
||||
/*for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;*/
|
||||
DccRx.PacketBuf.PreambleBits = preambleBitCount;
|
||||
DccRx.PacketBuf.PreambleBits = 0;
|
||||
for(uint8_t i = 0; i< MAX_DCC_MESSAGE_LEN; i++ )
|
||||
DccRx.PacketBuf.Data[i] = 0;
|
||||
|
||||
DccRx.PacketBuf.PreambleBits = DccRx.BitCount;
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.chkSum = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
//SET_TP1;
|
||||
}
|
||||
|
||||
//SET_TP4;
|
||||
|
||||
CLR_TP1;
|
||||
SET_TP4;
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, ISREdge );
|
||||
#endif
|
||||
// enable level-checking
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
ISRLevel = (ISREdge==RISING)? DccProcState.ExtIntMask : 0 ;
|
||||
|
||||
//CLR_TP4;
|
||||
CLR_TP4;
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_DATA:
|
||||
CLR_TP2;
|
||||
DccRx.BitCount++;
|
||||
DccRx.TempByte = ( DccRx.TempByte << 1 ) ;
|
||||
if( DccBitVal )
|
||||
@@ -618,44 +483,23 @@ void ExternalInterruptHandler(void)
|
||||
{
|
||||
DccRx.State = WAIT_END_BIT ;
|
||||
DccRx.PacketBuf.Data[ DccRx.PacketBuf.Size++ ] = DccRx.TempByte ;
|
||||
DccRx.chkSum ^= DccRx.TempByte;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WAIT_END_BIT:
|
||||
SET_TP2;CLR_TP2;
|
||||
DccRx.BitCount++;
|
||||
if( DccBitVal ) { // End of packet?
|
||||
CLR_TP3; SET_TP4;
|
||||
if( DccBitVal ) // End of packet?
|
||||
{
|
||||
CLR_TP3;
|
||||
DccRx.State = WAIT_PREAMBLE ;
|
||||
DccRx.BitCount = 0 ;
|
||||
bitMax = MAX_PRAEAMBEL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
SET_TP1;
|
||||
if ( DccRx.chkSum == 0 ) {
|
||||
// Packet is valid
|
||||
#ifdef ESP32
|
||||
portENTER_CRITICAL_ISR(&mux);
|
||||
#endif
|
||||
DccRx.PacketCopy = DccRx.PacketBuf ;
|
||||
DccRx.DataReady = 1 ;
|
||||
#ifdef ESP32
|
||||
portEXIT_CRITICAL_ISR(&mux);
|
||||
#endif
|
||||
// SET_TP2; CLR_TP2;
|
||||
preambleBitCount = 0 ;
|
||||
} else {
|
||||
// Wrong checksum
|
||||
CLR_TP1;
|
||||
#ifdef DCC_DBGVAR
|
||||
DB_PRINT("Cerr");
|
||||
countOf.Err++;
|
||||
#endif
|
||||
}
|
||||
|
||||
SET_TP3; CLR_TP4;
|
||||
} else { // Get next Byte
|
||||
DccRx.PacketCopy = DccRx.PacketBuf ;
|
||||
DccRx.DataReady = 1 ;
|
||||
SET_TP3;
|
||||
}
|
||||
else // Get next Byte
|
||||
// KGW - Abort immediately if packet is too long.
|
||||
if( DccRx.PacketBuf.Size == MAX_DCC_MESSAGE_LEN ) // Packet is too long - abort
|
||||
{
|
||||
@@ -671,109 +515,38 @@ void ExternalInterruptHandler(void)
|
||||
DccRx.BitCount = 0 ;
|
||||
DccRx.TempByte = 0 ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unless we're already looking for the start bit
|
||||
// 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
|
||||
// that much one bits cannot be valid in a packet.
|
||||
if ( DccRx.State != WAIT_START_BIT ) {
|
||||
if( DccBitVal )
|
||||
{
|
||||
preambleBitCount++;
|
||||
//SET_TP2;
|
||||
if( preambleBitCount > 10 ) {
|
||||
CLR_TP2;
|
||||
#ifndef SYNC_ALWAYS
|
||||
if ( DccRx.chkSum == 0 ) {
|
||||
// sync must be correct if chksum was ok, no need to check sync
|
||||
DccRx.State = WAIT_START_BIT_FULL;
|
||||
} else {
|
||||
#endif
|
||||
DccRx.State = WAIT_START_BIT ;
|
||||
SET_TP2;
|
||||
// While waiting for the start bit, detect halfbit lengths. We will detect the correct
|
||||
// sync and detect whether we see a false (e.g. motorola) protocol
|
||||
|
||||
#if defined ( __STM32F1__ )
|
||||
detachInterrupt( DccProcState.ExtIntNum );
|
||||
#endif
|
||||
#ifdef ESP32
|
||||
ISRWatch = CHANGE;
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||
#endif
|
||||
ISRChkMask = 0; // AVR level check is always true with this settings
|
||||
ISRLevel = 0; // ( there cannot be false edge IRQ's with CHANGE )
|
||||
halfBit = 0;
|
||||
bitMax = MAX_ONEBITHALF;
|
||||
bitMin = MIN_ONEBITHALF;
|
||||
//CLR_TP1;
|
||||
#ifndef SYNC_ALWAYS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
CLR_TP1;
|
||||
preambleBitCount = 0 ;
|
||||
// SET_TP2; CLR_TP2;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ALLOW_NESTED_IRQ
|
||||
DCC_IrqRunning = false;
|
||||
#endif
|
||||
//CLR_TP1;
|
||||
CLR_TP1;
|
||||
CLR_TP3;
|
||||
DCC_IrqRunning = false;
|
||||
}
|
||||
|
||||
void ackCV(void)
|
||||
{
|
||||
if( notifyCVAck )
|
||||
{
|
||||
DB_PRINT("ackCV: Send Basic ACK");
|
||||
notifyCVAck() ;
|
||||
}
|
||||
}
|
||||
|
||||
void ackAdvancedCV(void)
|
||||
{
|
||||
if( notifyAdvancedCVAck && (DccProcState.cv29Value & CV29_RAILCOM_ENABLE) )
|
||||
{
|
||||
DB_PRINT("ackAdvancedCV: Send RailCom ACK");
|
||||
notifyAdvancedCVAck() ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t readEEPROM( unsigned int CV )
|
||||
{
|
||||
uint8_t readEEPROM( unsigned int CV ) {
|
||||
return EEPROM.read(CV) ;
|
||||
}
|
||||
|
||||
void writeEEPROM( unsigned int CV, uint8_t Value )
|
||||
{
|
||||
void writeEEPROM( unsigned int CV, uint8_t Value ) {
|
||||
EEPROM.write(CV, Value) ;
|
||||
#if defined(ESP8266)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool readyEEPROM()
|
||||
{
|
||||
#if defined ARDUINO_ARCH_MEGAAVR
|
||||
return bit_is_clear(NVMCTRL.STATUS,NVMCTRL_EEBUSY_bp);
|
||||
#elif defined __AVR_MEGA__
|
||||
return eeprom_is_ready();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
bool readyEEPROM() {
|
||||
#ifdef __AVR_MEGA__
|
||||
return eeprom_is_ready();
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint8_t validCV( uint16_t CV, uint8_t Writable )
|
||||
{
|
||||
if( notifyCVResetFactoryDefault && (CV == CV_MANUFACTURER_ID ) && Writable )
|
||||
@@ -810,9 +583,6 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
|
||||
{
|
||||
case CV_29_CONFIG:
|
||||
// copy addressmode Bit to Flags
|
||||
Value = Value & ~CV29_RAILCOM_ENABLE; // Bidi (RailCom) Bit must not be enabled,
|
||||
// because you cannot build a Bidi decoder with this lib.
|
||||
DccProcState.cv29Value = Value;
|
||||
DccProcState.Flags = ( DccProcState.Flags & ~FLAGS_CV29_BITS) | (Value & FLAGS_CV29_BITS);
|
||||
// no break, because myDccAdress must also be reset
|
||||
case CV_ACCESSORY_DECODER_ADDRESS_LSB: // Also same CV for CV_MULTIFUNCTION_PRIMARY_ADDRESS
|
||||
@@ -841,19 +611,23 @@ uint8_t writeCV( unsigned int CV, uint8_t Value)
|
||||
|
||||
uint16_t getMyAddr(void)
|
||||
{
|
||||
uint8_t CV29Value ;
|
||||
|
||||
if( DccProcState.myDccAddress != -1 ) // See if we can return the cached value
|
||||
return( DccProcState.myDccAddress );
|
||||
|
||||
if( DccProcState.cv29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder?
|
||||
CV29Value = readCV( CV_29_CONFIG ) ;
|
||||
|
||||
if( CV29Value & CV29_ACCESSORY_DECODER ) // Accessory Decoder?
|
||||
{
|
||||
if( DccProcState.cv29Value & CV29_OUTPUT_ADDRESS_MODE )
|
||||
if( CV29Value & CV29_OUTPUT_ADDRESS_MODE )
|
||||
DccProcState.myDccAddress = ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) << 8 ) | readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB );
|
||||
else
|
||||
DccProcState.myDccAddress = ( ( readCV( CV_ACCESSORY_DECODER_ADDRESS_MSB ) & 0b00000111) << 6 ) | ( readCV( CV_ACCESSORY_DECODER_ADDRESS_LSB ) & 0b00111111) ;
|
||||
}
|
||||
else // Multi-Function Decoder?
|
||||
{
|
||||
if( DccProcState.cv29Value & CV29_EXT_ADDRESSING ) // Two Byte Address?
|
||||
if( CV29Value & CV29_EXT_ADDRESSING ) // Two Byte Address?
|
||||
DccProcState.myDccAddress = ( ( readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB ) - 192 ) << 8 ) | readCV( CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB ) ;
|
||||
|
||||
else
|
||||
@@ -863,7 +637,7 @@ uint16_t getMyAddr(void)
|
||||
return DccProcState.myDccAddress ;
|
||||
}
|
||||
|
||||
void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void (*ackFunction)() )
|
||||
void processDirectOpsOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value )
|
||||
{
|
||||
// is it a Byte Operation
|
||||
if( Cmd & 0x04 )
|
||||
@@ -873,9 +647,8 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
{
|
||||
if( validCV( CVAddr, 1 ) )
|
||||
{
|
||||
DB_PRINT("CV: %d Byte Write: %02X", CVAddr, Value)
|
||||
if( writeCV( CVAddr, Value ) == Value )
|
||||
ackFunction();
|
||||
ackCV();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,9 +656,8 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
{
|
||||
if( validCV( CVAddr, 0 ) )
|
||||
{
|
||||
DB_PRINT("CV: %d Byte Read: %02X", CVAddr, Value)
|
||||
if( readCV( CVAddr ) == Value )
|
||||
ackFunction();
|
||||
ackCV();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -898,8 +670,6 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
|
||||
uint8_t tempValue = readCV( CVAddr ) ; // Read the Current CV Value
|
||||
|
||||
DB_PRINT("CV: %d Current Value: %02X Bit-Wise Mode: %s Mask: %02X Value: %02X", CVAddr, tempValue, BitWrite ? "Write":"Read", BitMask, BitValue);
|
||||
|
||||
// Perform the Bit Write Operation
|
||||
if( BitWrite )
|
||||
{
|
||||
@@ -912,7 +682,7 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
tempValue &= ~BitMask ; // Turn the Bit Off
|
||||
|
||||
if( writeCV( CVAddr, tempValue ) == tempValue )
|
||||
ackFunction() ;
|
||||
ackCV() ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -924,12 +694,12 @@ void processDirectCVOperation( uint8_t Cmd, uint16_t CVAddr, uint8_t Value, void
|
||||
if( BitValue )
|
||||
{
|
||||
if( tempValue & BitMask )
|
||||
ackFunction() ;
|
||||
ackCV() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !( tempValue & BitMask) )
|
||||
ackFunction() ;
|
||||
ackCV() ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,8 +742,9 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
switch( Cmd & 0b00001110 )
|
||||
{
|
||||
case 0b00000000:
|
||||
if( notifyDccReset)
|
||||
notifyDccReset( Cmd & 0b00000001 ) ;
|
||||
if( notifyDccReset && ( Cmd & 0b00000001 ) ) // Hard Reset
|
||||
if( notifyDccReset)
|
||||
notifyDccReset( 1 ) ;
|
||||
break ;
|
||||
|
||||
case 0b00000010: // Factory Test
|
||||
@@ -1022,7 +793,7 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
case 0b01100000:
|
||||
//TODO should we cache this info in DCC_PROCESSOR_STATE.Flags ?
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
speedSteps = (DccProcState.cv29Value & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ;
|
||||
speedSteps = (readCV( CV_29_CONFIG ) & CV29_F0_LOCATION) ? SPEED_STEP_28 : SPEED_STEP_14 ;
|
||||
#else
|
||||
speedSteps = SPEED_STEP_28 ;
|
||||
#endif
|
||||
@@ -1106,7 +877,7 @@ void processMultiFunctionMessage( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t
|
||||
case 0b11100000: // CV Access
|
||||
CVAddr = ( ( ( Cmd & 0x03 ) << 8 ) | Data1 ) + 1 ;
|
||||
|
||||
processDirectCVOperation( Cmd, CVAddr, Data2, ackAdvancedCV) ;
|
||||
processDirectOpsOperation( Cmd, CVAddr, Data2 ) ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1121,7 +892,7 @@ void processServiceModeOperation( DCC_MSG * pDccMsg )
|
||||
if( pDccMsg->Size == 3) // 3 Byte Packets are for Address Only, Register and Paged Mode
|
||||
{
|
||||
uint8_t RegisterAddr ;
|
||||
DB_PRINT("CV Address, Register & Paged Mode Operation");
|
||||
DB_PRINT("3-BytePkt");
|
||||
RegisterAddr = pDccMsg->Data[0] & 0x07 ;
|
||||
Value = pDccMsg->Data[1] ;
|
||||
|
||||
@@ -1164,11 +935,11 @@ void processServiceModeOperation( DCC_MSG * pDccMsg )
|
||||
|
||||
else if( pDccMsg->Size == 4) // 4 Byte Packets are for Direct Byte & Bit Mode
|
||||
{
|
||||
DB_PRINT("CV Direct Byte and Bit Mode Mode Operation");
|
||||
DB_PRINT("BB-Mode");
|
||||
CVAddr = ( ( ( pDccMsg->Data[0] & 0x03 ) << 8 ) | pDccMsg->Data[1] ) + 1 ;
|
||||
Value = pDccMsg->Data[2] ;
|
||||
|
||||
processDirectCVOperation( pDccMsg->Data[0] & 0b00001100, CVAddr, Value, ackCV) ;
|
||||
|
||||
processDirectOpsOperation( pDccMsg->Data[0] & 0b00001100, CVAddr, Value ) ;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1245,13 +1016,12 @@ void execDccProcessor( DCC_MSG * pDccMsg )
|
||||
{
|
||||
resetServiceModeTimer( 1 ) ;
|
||||
|
||||
//Only check the DCC Packet "Size" and "Data" fields and ignore the "PreambleBits" as they can be different to the previous packet
|
||||
if(pDccMsg->Size != DccProcState.LastMsg.Size || memcmp( pDccMsg->Data, &DccProcState.LastMsg.Data, pDccMsg->Size ) != 0 )
|
||||
if( memcmp( pDccMsg, &DccProcState.LastMsg, sizeof( DCC_MSG ) ) )
|
||||
{
|
||||
DccProcState.DuplicateCount = 0 ;
|
||||
memcpy( &DccProcState.LastMsg, pDccMsg, sizeof( DCC_MSG ) ) ;
|
||||
}
|
||||
// Wait until you see 2 identical packets before acting on a Service Mode Packet
|
||||
// Wait until you see 2 identicle packets before acting on a Service Mode Packet
|
||||
else
|
||||
{
|
||||
DccProcState.DuplicateCount++ ;
|
||||
@@ -1507,30 +1277,14 @@ void NmraDcc::pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup
|
||||
#if defined ( __STM32F1__ )
|
||||
// with STM32F1 the interuptnumber is equal the pin number
|
||||
DccProcState.ExtIntNum = ExtIntPinNum;
|
||||
// because STM32F1 has a NVIC we must set interuptpriorities
|
||||
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_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);
|
||||
|
||||
// DCC-Input IRQ must be able to interrupt other long low priority ( level15 ) IRQ's
|
||||
nvic_irq_set_priority ( irqNum2nvic[irqNum], PRIO_DCC_IRQ);
|
||||
|
||||
// Systic must be able to interrupt DCC-IRQ to always get correct micros() values
|
||||
nvic_irq_set_priority(NVIC_SYSTICK, PRIO_SYSTIC);
|
||||
#else
|
||||
DccProcState.ExtIntNum = ExtIntNum;
|
||||
#endif
|
||||
DccProcState.ExtIntPinNum = ExtIntPinNum;
|
||||
#ifdef __AVR_MEGA__
|
||||
// because digitalRead at AVR is slow, we will read the dcc input in the ISR
|
||||
// by direct port access.
|
||||
DccProcState.ExtIntPort = portInputRegister( digitalPinToPort(ExtIntPinNum) );
|
||||
DccProcState.ExtIntMask = digitalPinToBitMask( ExtIntPinNum );
|
||||
#else
|
||||
DccProcState.ExtIntMask = 1;
|
||||
#endif
|
||||
pinMode( ExtIntPinNum, EnablePullup ? INPUT_PULLUP : INPUT );
|
||||
|
||||
pinMode( ExtIntPinNum, INPUT );
|
||||
if( EnablePullup )
|
||||
digitalWrite(ExtIntPinNum, HIGH);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -1545,9 +1299,6 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
||||
#if defined(ESP8266)
|
||||
EEPROM.begin(MAXCV);
|
||||
#endif
|
||||
#if defined(ESP32)
|
||||
EEPROM.begin(MAXCV);
|
||||
#endif
|
||||
// Clear all the static member variables
|
||||
memset( &DccRx, 0, sizeof( DccRx) );
|
||||
|
||||
@@ -1555,30 +1306,20 @@ void NmraDcc::init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, ui
|
||||
MODE_TP2;
|
||||
MODE_TP3;
|
||||
MODE_TP4;
|
||||
ISREdge = RISING;
|
||||
bitMax = MAX_ONEBITFULL;
|
||||
bitMin = MIN_ONEBITFULL;
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
||||
|
||||
DccProcState.Flags = Flags ;
|
||||
DccProcState.OpsModeAddressBaseCV = OpsModeAddressBaseCV ;
|
||||
DccProcState.myDccAddress = -1;
|
||||
DccProcState.inAccDecDCCAddrNextReceivedMode = 0;
|
||||
|
||||
ISREdge = RISING;
|
||||
// level checking to detect false IRQ's fired by glitches
|
||||
ISRLevel = DccProcState.ExtIntMask;
|
||||
ISRChkMask = DccProcState.ExtIntMask;
|
||||
|
||||
#ifdef ESP32
|
||||
ISRWatch = ISREdge;
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, CHANGE);
|
||||
#else
|
||||
attachInterrupt( DccProcState.ExtIntNum, ExternalInterruptHandler, RISING);
|
||||
#endif
|
||||
|
||||
// Set the Bits that control Multifunction or Accessory behaviour
|
||||
// and if the Accessory decoder optionally handles Output Addressing
|
||||
// we need to peal off the top two bits
|
||||
DccProcState.cv29Value = writeCV( CV_29_CONFIG, ( readCV( CV_29_CONFIG ) & ~FLAGS_CV29_BITS ) | (Flags & FLAGS_CV29_BITS) ) ;
|
||||
writeCV( CV_29_CONFIG, ( readCV( CV_29_CONFIG ) & ~FLAGS_CV29_BITS ) | (Flags & FLAGS_CV29_BITS) ) ;
|
||||
|
||||
uint8_t doAutoFactoryDefault = 0;
|
||||
if((Flags & FLAGS_AUTO_FACTORY_DEFAULT) && (readCV(CV_VERSION_ID) == 255) && (readCV(CV_MANUFACTURER_ID) == 255))
|
||||
@@ -1677,29 +1418,30 @@ uint8_t NmraDcc::process()
|
||||
if( DccRx.DataReady )
|
||||
{
|
||||
// We need to do this check with interrupts disabled
|
||||
#ifdef ESP32
|
||||
portENTER_CRITICAL(&mux);
|
||||
#else
|
||||
//SET_TP4;
|
||||
noInterrupts();
|
||||
#endif
|
||||
Msg = DccRx.PacketCopy ;
|
||||
DccRx.DataReady = 0 ;
|
||||
|
||||
#ifdef ESP32
|
||||
portEXIT_CRITICAL(&mux);
|
||||
#else
|
||||
interrupts();
|
||||
#endif
|
||||
// Checking of the XOR-byte is now done in the ISR already
|
||||
#ifdef DCC_DBGVAR
|
||||
countOf.Tel++;
|
||||
#endif
|
||||
// Clear trailing bytes
|
||||
for ( byte i=Msg.Size; i< MAX_DCC_MESSAGE_LEN; i++ ) Msg.Data[i] = 0;
|
||||
#ifdef DCC_DBGVAR
|
||||
countOf.Tel++;
|
||||
#endif
|
||||
|
||||
if( notifyDccMsg ) notifyDccMsg( &Msg );
|
||||
uint8_t xorValue = 0 ;
|
||||
|
||||
for(uint8_t i = 0; i < DccRx.PacketCopy.Size; i++)
|
||||
xorValue ^= DccRx.PacketCopy.Data[i];
|
||||
if(xorValue) {
|
||||
#ifdef DCC_DBGVAR
|
||||
DB_PRINT("Cerr");
|
||||
countOf.Err++;
|
||||
#endif
|
||||
return 0 ;
|
||||
} else {
|
||||
if( notifyDccMsg ) notifyDccMsg( &Msg );
|
||||
|
||||
execDccProcessor( &Msg );
|
||||
execDccProcessor( &Msg );
|
||||
}
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,21 +2,11 @@
|
||||
//
|
||||
// Model Railroading with Arduino - NmraDcc.h
|
||||
//
|
||||
// Copyright (c) 2008 - 2020 Alex Shepherd
|
||||
// Copyright (c) 2008 - 2018 Alex Shepherd
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 2.1 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// This source file is subject of the GNU general public license 2,
|
||||
// that is available at the world-wide-web at
|
||||
// http://www.gnu.org/licenses/gpl.txt
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
@@ -42,7 +32,7 @@
|
||||
// Uncomment the following Line to Enable Service Mode CV Programming
|
||||
#define NMRA_DCC_PROCESS_SERVICEMODE
|
||||
|
||||
// Uncomment the following line to Enable MultiFunction Decoder Operations
|
||||
// Uncomment the following line to Enable MutliFunction Decoder Operations
|
||||
#define NMRA_DCC_PROCESS_MULTIFUNCTION
|
||||
|
||||
// Uncomment the following line to Enable 14 Speed Step Support
|
||||
@@ -54,15 +44,15 @@
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "EEPROM.h"
|
||||
|
||||
#ifndef NMRADCC_IS_IN
|
||||
#define NMRADCC_IS_IN
|
||||
|
||||
#define NMRADCC_VERSION 206 // Version 2.0.6
|
||||
#define NMRADCC_VERSION 200 // Version 2.0.0
|
||||
|
||||
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
|
||||
|
||||
//#define ALLOW_NESTED_IRQ // uncomment to enable nested IRQ's ( only for AVR! )
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t Size ;
|
||||
@@ -106,27 +96,21 @@ typedef struct
|
||||
#define CV_MANUFACTURER_ID 8
|
||||
#define CV_29_CONFIG 29
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <esp_spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#elif defined(ESP8266)
|
||||
#include <spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#if defined(ESP8266)
|
||||
#include <spi_flash.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#elif defined( __STM32F1__)
|
||||
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
|
||||
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
|
||||
// because STM32 uses virtual adresses)
|
||||
#undef ALLOW_NESTED_IRQ // This is done with NVIC on STM32
|
||||
#define PRIO_DCC_IRQ 9
|
||||
#define PRIO_SYSTIC 8 // MUST be higher priority than DCC Irq
|
||||
#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
|
||||
|
||||
typedef enum {
|
||||
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_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
|
||||
CV29_RAILCOM_ENABLE = 0b00001000, /** bit 3: BiDi ( RailCom ) is active */
|
||||
CV29_ADV_ACK = 0b00001000, /** bit 3: ACK, Advanced Acknowledge mode enabled if 1, disabled if 0 */
|
||||
CV29_SPEED_TABLE_ENABLE = 0b00010000, /** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */
|
||||
CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */
|
||||
CV29_OUTPUT_ADDRESS_MODE = 0b01000000, /** bit 6: "0" = Decoder Address Mode "1" = Output Address Mode */
|
||||
@@ -667,7 +651,7 @@ extern uint8_t notifyIsSetCVReady(void) __attribute__ ((weak));
|
||||
* notifyCVChange() Called when a CV value is changed.
|
||||
* This is called whenever a CV's value is changed.
|
||||
* notifyDccCVChange() Called only when a CV value is changed by a Dcc packet or a internal lib function.
|
||||
* it is NOT called if the CV is changed by means of the setCV() method.
|
||||
* it is NOT called if the CV is chaged by means of the setCV() method.
|
||||
* Note: It is not called if notifyCVWrite() is defined
|
||||
* or if the value in the EEPROM is the same as the value
|
||||
* in the write command.
|
||||
@@ -711,17 +695,6 @@ extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVAck(void) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyAdvancedCVAck() Called when a CV write must be acknowledged via Advanced Acknowledgement.
|
||||
* This callback must send the Advanced Acknowledgement via RailComm.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
* *
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyAdvancedCVAck(void) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
|
||||
*
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// DCC Stepper Motor Controller ( A4988 ) Example for Model Railroad Turntable Control
|
||||
//
|
||||
// See: https://www.dccinterface.com/product/arduino-model-railway-dcc-stepper-motor-controller-a4988-assembled/
|
||||
// See: https://www.dccinterface.com/how-to/assemblyguide/
|
||||
//
|
||||
// Author: Alex Shepherd 2020-06-01
|
||||
// Author: Alex Shepherd 2017-12-04
|
||||
//
|
||||
// This example requires two Arduino Libraries:
|
||||
//
|
||||
@@ -22,22 +22,12 @@
|
||||
// The lines below define the pins used to connect to the A4988 driver module
|
||||
#define A4988_STEP_PIN 4
|
||||
#define A4988_DIRECTION_PIN 5
|
||||
#define A4988_ENABLE_PIN 6
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
// Uncomment the next line to enable Powering-Off the Stepper when its not running to reduce heating the motor and driver
|
||||
#define DISABLE_OUTPUTS_IDLE
|
||||
#endif
|
||||
|
||||
// By default the stepper motor will move the shortest distance to the desired position.
|
||||
// If you need the turntable to only move in the Positive/Increasing or Negative/Decreasing step numbers to better handle backlash in the mechanism
|
||||
// Then uncomment the appropriate line below
|
||||
//#define ALWAYS_MOVE_POSITIVE
|
||||
//#define ALWAYS_MOVE_NEGATIVE
|
||||
#define A4988_ENABLE_PIN 6
|
||||
|
||||
// The lines below define the stepping speed and acceleration, which you may need to tune for your application
|
||||
#define STEPPER_MAX_SPEED 800 // Sets the maximum permitted speed
|
||||
#define STEPPER_ACCELARATION 1000 // Sets the acceleration/deceleration rate
|
||||
#define STEPPER_ACCELARATION 1000 // Sets the acceleration/deceleration rate
|
||||
#define STEPPER_SPEED 300 // Sets the desired constant speed for use with runSpeed()
|
||||
|
||||
// The line below defines the number of "Full Steps" your stepper motor does for a full rotation
|
||||
@@ -102,9 +92,6 @@ TurnoutPosition turnoutPositions[] = {
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// You shouldn't need to edit anything below this line unless you're needing to make big changes... ;)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
#if defined(ALWAYS_MOVE_POSITIVE) && defined(ALWAYS_MOVE_NEGATIVE)
|
||||
#error ONLY uncomment one of ALWAYS_MOVE_POSITIVE or ALWAYS_MOVE_NEGATIVE but NOT both
|
||||
#endif
|
||||
|
||||
#define MAX_TURNOUT_POSITIONS (sizeof(turnoutPositions) / sizeof(TurnoutPosition))
|
||||
|
||||
@@ -117,12 +104,11 @@ NmraDcc Dcc ;
|
||||
// Variables to store the last DCC Turnout message Address and Direction
|
||||
uint16_t lastAddr = 0xFFFF ;
|
||||
uint8_t lastDirection = 0xFF;
|
||||
int lastStep = 0;
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
Serial.print(F("notifyDccAccTurnoutOutput: "));
|
||||
Serial.print("notifyDccAccTurnoutOutput: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
@@ -145,50 +131,23 @@ void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t Output
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
int newStep;
|
||||
if(Direction)
|
||||
newStep = turnoutPositions[i].positionFront;
|
||||
if (Direction)
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionFront, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionFront);
|
||||
break;
|
||||
}
|
||||
else
|
||||
newStep = turnoutPositions[i].positionBack;
|
||||
|
||||
Serial.print(newStep, DEC);
|
||||
|
||||
Serial.print(F(" Last Step: "));
|
||||
Serial.print(lastStep, DEC);
|
||||
|
||||
int diffStep = newStep - lastStep;
|
||||
Serial.print(F(" Diff Step: "));
|
||||
Serial.print(diffStep, DEC);
|
||||
|
||||
#if defined ALWAYS_MOVE_POSITIVE
|
||||
Serial.print(F(" Positive"));
|
||||
if(diffStep < 0)
|
||||
diffStep += FULL_TURN_STEPS;
|
||||
|
||||
#elif defined ALWAYS_MOVE_NEGATIVE
|
||||
Serial.print(F(" Negative"));
|
||||
if(diffStep > 0)
|
||||
diffStep -= FULL_TURN_STEPS;
|
||||
#else
|
||||
if(diffStep > HALF_TURN_STEPS)
|
||||
diffStep = diffStep - FULL_TURN_STEPS;
|
||||
|
||||
else if(diffStep < -HALF_TURN_STEPS)
|
||||
diffStep = diffStep + FULL_TURN_STEPS;
|
||||
#endif
|
||||
|
||||
Serial.print(F(" Move: "));
|
||||
Serial.println(diffStep, DEC);
|
||||
stepper1.move(diffStep);
|
||||
|
||||
lastStep = newStep;
|
||||
break;
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionBack, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionBack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
bool lastIsRunningState ;
|
||||
#endif
|
||||
|
||||
@@ -202,12 +161,8 @@ void setupStepperDriver()
|
||||
stepper1.setMaxSpeed(STEPPER_MAX_SPEED); // Sets the maximum permitted speed
|
||||
stepper1.setAcceleration(STEPPER_ACCELARATION); // Sets the acceleration/deceleration rate
|
||||
stepper1.setSpeed(STEPPER_SPEED); // Sets the desired constant speed for use with runSpeed()
|
||||
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
#endif
|
||||
}
|
||||
@@ -218,19 +173,14 @@ bool moveToHomePosition()
|
||||
|
||||
pinMode(HOME_SENSOR_PIN, INPUT_PULLUP);
|
||||
|
||||
#ifdef ALWAYS_MOVE_NEGATIVE
|
||||
stepper1.move(0 - (FULL_TURN_STEPS * 2));
|
||||
#else
|
||||
stepper1.move(FULL_TURN_STEPS * 2);
|
||||
#endif
|
||||
while(digitalRead(HOME_SENSOR_PIN) != HOME_SENSOR_ACTIVE_STATE)
|
||||
stepper1.run();
|
||||
|
||||
if(digitalRead(HOME_SENSOR_PIN) == HOME_SENSOR_ACTIVE_STATE)
|
||||
{
|
||||
stepper1.stop();
|
||||
stepper1.setCurrentPosition(0);
|
||||
Serial.println(F("Found Home Position - Setting Current Position to 0"));
|
||||
stepper1.setCurrentPosition(0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -260,32 +210,28 @@ void setup()
|
||||
Serial.print(F("Full Rotation Steps: "));
|
||||
Serial.println(FULL_TURN_STEPS);
|
||||
|
||||
Serial.print(F("Movement Strategy: "));
|
||||
#if defined ALWAYS_MOVE_POSITIVE
|
||||
Serial.println(F("Positive Direction Only"));
|
||||
#elif defined ALWAYS_MOVE_NEGATIVE
|
||||
Serial.println(F("Negative Direction Only"));
|
||||
#else
|
||||
Serial.println(F("Shortest Distance"));
|
||||
#endif
|
||||
|
||||
for(uint8_t i = 0; i < MAX_TURNOUT_POSITIONS; i++)
|
||||
{
|
||||
Serial.print(F("DCC Addr: "));
|
||||
Serial.print("DCC Addr: ");
|
||||
Serial.print(turnoutPositions[i].dccAddress);
|
||||
|
||||
Serial.print(F(" Front: "));
|
||||
Serial.print(" Front: ");
|
||||
Serial.print(turnoutPositions[i].positionFront);
|
||||
|
||||
Serial.print(F(" Back: "));
|
||||
Serial.print(" Back: ");
|
||||
Serial.println(turnoutPositions[i].positionBack);
|
||||
}
|
||||
|
||||
setupStepperDriver();
|
||||
|
||||
if(moveToHomePosition());
|
||||
{
|
||||
setupDCCDecoder();
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
|
||||
// Fake a DCC Packet to cause the Turntable to move to Position 1
|
||||
notifyDccAccTurnoutOutput(POSITION_01_DCC_ADDRESS, 1, 1);
|
||||
}
|
||||
@@ -299,7 +245,7 @@ void loop()
|
||||
// Process the Stepper Library
|
||||
stepper1.run();
|
||||
|
||||
#ifdef DISABLE_OUTPUTS_IDLE
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
if(stepper1.isRunning() != lastIsRunningState)
|
||||
{
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
|
||||
@@ -1,765 +0,0 @@
|
||||
// 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.
|
||||
*/
|
||||
@@ -1,264 +0,0 @@
|
||||
// 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
|
||||
@@ -1,301 +0,0 @@
|
||||
// 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
|
||||
@@ -1,344 +0,0 @@
|
||||
// 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
@@ -1,735 +0,0 @@
|
||||
// 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
@@ -1,735 +0,0 @@
|
||||
// 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
@@ -1,32 +0,0 @@
|
||||
/* 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);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
// 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.
|
||||
*/
|
||||
@@ -1,314 +0,0 @@
|
||||
// NMRA Dcc Multifunction Motor Decoder Demo
|
||||
//
|
||||
// Author: Alex Shepherd 2019-03-30
|
||||
//
|
||||
// This example requires these Arduino Libraries:
|
||||
//
|
||||
// 1) The NmraDcc Library from: http://mrrwa.org/download/
|
||||
//
|
||||
// These libraries can be found and installed via the Arduino IDE Library Manager
|
||||
//
|
||||
// This is a simple demo of how to drive and motor speed and direction using PWM and a motor H-Bridge
|
||||
// It uses vStart and vHigh CV values to customise the PWM values to the motor response
|
||||
// It also uses the Headling Function to drive 2 LEDs for Directional Headlights
|
||||
// Apart from that there's nothing fancy like Lighting Effects or a function matrix or Speed Tables - its just the basics...
|
||||
//
|
||||
|
||||
#include <NmraDcc.h>
|
||||
// Uncomment any of the lines below to enable debug messages for different parts of the code
|
||||
//#define DEBUG_FUNCTIONS
|
||||
//#define DEBUG_SPEED
|
||||
//#define DEBUG_PWM
|
||||
//#define DEBUG_DCC_ACK
|
||||
//#define DEBUG_DCC_MSG
|
||||
|
||||
#if defined(DEBUG_FUNCTIONS) or defined(DEBUG_SPEED) or defined(DEBUG_PWM) or defined(DEBUG_DCC_ACK) or defined(DEBUG_DCC_MSG)
|
||||
#define DEBUG_PRINT
|
||||
#endif
|
||||
|
||||
// This is the default DCC Address
|
||||
#define DEFAULT_DECODER_ADDRESS 3
|
||||
|
||||
// This section defines the Arduino UNO Pins to use
|
||||
#ifdef __AVR_ATmega328P__
|
||||
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define LED_PIN_FWD 5
|
||||
#define LED_PIN_REV 6
|
||||
#define MOTOR_DIR_PIN 12
|
||||
#define MOTOR_PWM_PIN 3
|
||||
|
||||
// This section defines the Arduino ATTiny85 Pins to use
|
||||
#elif ARDUINO_AVR_ATTINYX5
|
||||
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define LED_PIN_FWD 0
|
||||
#define LED_PIN_REV 1
|
||||
#define MOTOR_DIR_PIN 3
|
||||
#define MOTOR_PWM_PIN 4
|
||||
|
||||
#else
|
||||
#error "Unsupported CPU, you need to add another configuration section for your CPU"
|
||||
#endif
|
||||
|
||||
// Some global state variables
|
||||
uint8_t newLedState = 0;
|
||||
uint8_t lastLedState = 0;
|
||||
|
||||
uint8_t newDirection = 0;
|
||||
uint8_t lastDirection = 0;
|
||||
|
||||
uint8_t newSpeed = 0;
|
||||
uint8_t lastSpeed = 0;
|
||||
uint8_t numSpeedSteps = SPEED_STEP_128;
|
||||
|
||||
uint8_t vStart;
|
||||
uint8_t vHigh;
|
||||
|
||||
// Structure for CV Values Table
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
// CV Addresses we will be using
|
||||
#define CV_VSTART 2
|
||||
#define CV_VHIGH 5
|
||||
|
||||
// Default CV Values Table
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
// The CV Below defines the Short DCC Address
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_DECODER_ADDRESS},
|
||||
|
||||
// Three Step Speed Table
|
||||
{CV_VSTART, 120},
|
||||
{CV_VHIGH, 255},
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DEFAULT_DECODER_ADDRESS},
|
||||
|
||||
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||
// {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
|
||||
};
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
|
||||
// This call-back function is called when a CV Value changes so we can update CVs we're using
|
||||
void notifyCVChange( uint16_t CV, uint8_t Value)
|
||||
{
|
||||
switch(CV)
|
||||
{
|
||||
case CV_VSTART:
|
||||
vStart = Value;
|
||||
break;
|
||||
|
||||
case CV_VHIGH:
|
||||
vHigh = Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 call-back function is called whenever we receive a DCC Speed packet for our address
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
|
||||
{
|
||||
#ifdef DEBUG_SPEED
|
||||
Serial.print("notifyDccSpeed: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
|
||||
Serial.print(" Speed: ");
|
||||
Serial.print(Speed,DEC);
|
||||
Serial.print(" Steps: ");
|
||||
Serial.print(SpeedSteps,DEC);
|
||||
Serial.print(" Dir: ");
|
||||
Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
|
||||
#endif
|
||||
|
||||
newDirection = Dir;
|
||||
newSpeed = Speed;
|
||||
numSpeedSteps = SpeedSteps;
|
||||
};
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Function packet for our address
|
||||
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
|
||||
{
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("notifyDccFunc: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
|
||||
Serial.print(" Function Group: ");
|
||||
Serial.print(FuncGrp,DEC);
|
||||
#endif
|
||||
|
||||
if(FuncGrp == FN_0_4)
|
||||
{
|
||||
newLedState = (FuncState & FN_BIT_00) ? 1 : 0;
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FN 0: ");
|
||||
Serial.print(newLedState);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Packet
|
||||
#ifdef DEBUG_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
|
||||
|
||||
// This call-back 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
|
||||
// So we will just turn the motor on for 8ms and then turn it off again.
|
||||
|
||||
void notifyCVAck(void)
|
||||
{
|
||||
#ifdef DEBUG_DCC_ACK
|
||||
Serial.println("notifyCVAck") ;
|
||||
#endif
|
||||
|
||||
digitalWrite(MOTOR_DIR_PIN, HIGH);
|
||||
digitalWrite(MOTOR_PWM_PIN, HIGH);
|
||||
|
||||
delay( 8 );
|
||||
|
||||
digitalWrite(MOTOR_DIR_PIN, LOW);
|
||||
digitalWrite(MOTOR_PWM_PIN, LOW);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
Serial.begin(115200);
|
||||
Serial.println("NMRA Dcc Multifunction Motor Decoder Demo");
|
||||
#endif
|
||||
|
||||
// Setup the Pins for the Fwd/Rev LED for Function 0 Headlight
|
||||
pinMode(LED_PIN_FWD, OUTPUT);
|
||||
pinMode(LED_PIN_REV, OUTPUT);
|
||||
|
||||
// Setup the Pins for the Motor H-Bridge Driver
|
||||
pinMode(MOTOR_DIR_PIN, OUTPUT);
|
||||
pinMode(MOTOR_PWM_PIN, OUTPUT);
|
||||
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
|
||||
Dcc.init( MAN_ID_DIY, 10, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
||||
|
||||
// Uncomment to force CV Reset to Factory Defaults
|
||||
// notifyCVResetFactoryDefault();
|
||||
|
||||
// Read the current CV values for vStart and vHigh
|
||||
vStart = Dcc.getCV(CV_VSTART);
|
||||
vHigh = Dcc.getCV(CV_VHIGH);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
|
||||
// Handle Speed changes
|
||||
if(lastSpeed != newSpeed)
|
||||
{
|
||||
lastSpeed = newSpeed;
|
||||
|
||||
// Stop if speed = 0 or 1
|
||||
|
||||
if(newSpeed <= 1)
|
||||
digitalWrite(MOTOR_PWM_PIN, LOW);
|
||||
|
||||
// Calculate PWM value in the range 1..255
|
||||
else
|
||||
{
|
||||
uint8_t vScaleFactor;
|
||||
|
||||
if((vHigh > 1) && (vHigh > vStart))
|
||||
vScaleFactor = vHigh - vStart;
|
||||
else
|
||||
vScaleFactor = 255 - vStart;
|
||||
|
||||
uint8_t modSpeed = newSpeed - 1;
|
||||
uint8_t modSteps = numSpeedSteps - 1;
|
||||
|
||||
uint8_t newPwm = (uint8_t) vStart + modSpeed * vScaleFactor / modSteps;
|
||||
|
||||
#ifdef DEBUG_PWM
|
||||
Serial.print("New Speed: vStart: ");
|
||||
Serial.print(vStart);
|
||||
Serial.print(" vHigh: ");
|
||||
Serial.print(vHigh);
|
||||
Serial.print(" modSpeed: ");
|
||||
Serial.print(modSpeed);
|
||||
Serial.print(" vScaleFactor: ");
|
||||
Serial.print(vScaleFactor);
|
||||
Serial.print(" modSteps: ");
|
||||
Serial.print(modSteps);
|
||||
Serial.print(" newPwm: ");
|
||||
Serial.println(newPwm);
|
||||
#endif
|
||||
|
||||
analogWrite(MOTOR_PWM_PIN, newPwm);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Direction and Headlight changes
|
||||
if((lastDirection != newDirection) || (lastLedState != newLedState))
|
||||
{
|
||||
lastDirection = newDirection;
|
||||
lastLedState = newLedState;
|
||||
|
||||
digitalWrite(MOTOR_DIR_PIN, newDirection);
|
||||
|
||||
if(newLedState)
|
||||
{
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.println("LED On");
|
||||
#endif
|
||||
digitalWrite(LED_PIN_FWD, newDirection ? LOW : HIGH);
|
||||
digitalWrite(LED_PIN_REV, newDirection ? HIGH : LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.println("LED Off");
|
||||
#endif
|
||||
digitalWrite(LED_PIN_FWD, LOW);
|
||||
digitalWrite(LED_PIN_REV, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle resetting CVs back to Factory Defaults
|
||||
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
|
||||
{
|
||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
name=NmraDcc
|
||||
version=2.0.6
|
||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda), Hans Tanner
|
||||
version=2.0.0
|
||||
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda)
|
||||
maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
|
||||
sentence=Enables NMRA DCC Communication
|
||||
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
|
||||
|
||||
Reference in New Issue
Block a user