Compare commits
43 Commits
1.3.0
...
ESP8266-IC
Author | SHA1 | Date | |
---|---|---|---|
|
6a7e206032 | ||
|
6d12e6cd3f | ||
|
b249762550 | ||
|
5cee0d28ed | ||
|
5ba1ee3e8e | ||
|
bb2a659ebe | ||
|
865d919802 | ||
|
ff3e24dff4 | ||
|
6dca23bc27 | ||
|
15da83c411 | ||
|
7a3845cbdf | ||
|
1717a2efb0 | ||
|
32c5597870 | ||
|
2de91bd4fd | ||
|
5a1e0b2997 | ||
|
2b12179152 | ||
|
c2de60b8cb | ||
|
f171dd3894 | ||
|
778de8ce74 | ||
|
ba3264bd87 | ||
|
0fbe2a13d1 | ||
|
369786325f | ||
|
ec801bf463 | ||
|
90470987a8 | ||
|
9294aa29e5 | ||
|
844171f2ac | ||
|
0656f58c5b | ||
|
0d2e8daeaf | ||
|
92dd2e6ac5 | ||
|
07933e42a8 | ||
|
f8f106962f | ||
|
8c782d5f15 | ||
|
dafa1c9964 | ||
|
dcbd20ef7e | ||
|
e622a596d7 | ||
|
4c1d5fd6e4 | ||
|
3a5986d10d | ||
|
9035e55930 | ||
|
3eee73f6cd | ||
|
d3059d2f4e | ||
|
0c3385b27d | ||
|
e0d46ff9b9 | ||
|
0bab98c838 |
@@ -1,103 +0,0 @@
|
||||
------------------------------------------------------------------------
|
||||
|
||||
OpenDCC - NmraDcc
|
||||
|
||||
Copyright (c) 2008 Alex Shepherd
|
||||
|
||||
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
|
||||
------------------------------------------------------------------------
|
||||
|
||||
file: Description NmraDcc.txt
|
||||
author:
|
||||
webpage:
|
||||
history:
|
||||
------------------------------------------------------------------------
|
||||
Call the DCC pin function to define which External Interrupt and Pin to use and also to enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
|
||||
Call the main DCC Init function to enable the DCC Receiver
|
||||
|
||||
Dcc.init( MAN_ID_DIY, 10, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 )
|
||||
|
||||
MAN_ID_DIY = 0x0D (CV8 defined in NmraDcc.h)
|
||||
FLAGS_OUTPUT_ADDRESS_MODE = 0x40 (CV29/541 bit 6 defined in NmraDcc.h)
|
||||
FLAGS_DCC_ACCESSORY_DECODER = 0x80 (CV 29/541 bit 7 defined in NmraDcc.h)
|
||||
------------------------------------------------------------------------
|
||||
You MUST call the NmraDcc.process() method frequently from the Arduino loop()
|
||||
function for correct library operation
|
||||
|
||||
Dcc.process();
|
||||
------------------------------------------------------------------------
|
||||
This function is called whenever a normal DCC Turnout Packet is received
|
||||
|
||||
notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)
|
||||
|
||||
Addr = Decoder address
|
||||
BoardAddr = Address of this decoder
|
||||
OutputAddr = Address of Turnout on this decoder
|
||||
State =
|
||||
------------------------------------------------------------------------
|
||||
This function is called whenever a DCC Signal Aspect Packet is received
|
||||
|
||||
notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State)
|
||||
|
||||
Addr = Decoder address
|
||||
OutputIndex = Address of Signal Aspect
|
||||
State =
|
||||
------------------------------------------------------------------------
|
||||
notifyDccFunc( uint16_t Addr, uint8_t FuncNum, uint8_t FuncState)
|
||||
|
||||
Addr = Decoder address
|
||||
FuncNum =
|
||||
FuncState =
|
||||
------------------------------------------------------------------------
|
||||
Perform a decoder total reset
|
||||
|
||||
notifyDccReset(uint8_t hardReset )
|
||||
|
||||
hardReset =
|
||||
------------------------------------------------------------------------
|
||||
The decoder receives a Idle packet and should do nothing
|
||||
|
||||
notifyDccIdle(void)
|
||||
------------------------------------------------------------------------
|
||||
A locomotive packet is received
|
||||
|
||||
notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed )
|
||||
|
||||
Addr = Address received
|
||||
Speed = Requested speed
|
||||
ForwardDir = True if loco moves forward
|
||||
MaxSpeed =
|
||||
------------------------------------------------------------------------
|
||||
Checks if a CV is present in the table and is writable
|
||||
|
||||
notifyCVValid( uint16_t CV, uint8_t Writable )
|
||||
|
||||
CV = The number of the requested CV
|
||||
Writable = True is CV is writable
|
||||
------------------------------------------------------------------------
|
||||
Read a CV value from the decoder table
|
||||
|
||||
notifyCVRead( uint16_t CV)
|
||||
|
||||
CV = The number of the requested CV
|
||||
------------------------------------------------------------------------
|
||||
Write a CV with Value to the decoder table
|
||||
|
||||
notifyCVWrite( uint16_t CV, uint8_t Value)
|
||||
|
||||
CV = The number of the requested CV
|
||||
Value = Value to be written into the requested CV
|
||||
------------------------------------------------------------------------
|
||||
Check if the CV written to the table has the correct value
|
||||
|
||||
notifyCVChange( uint16_t CV, uint8_t Value)
|
||||
|
||||
CV = The number of the requested CV
|
||||
Value = Value of the changed requested CV
|
||||
------------------------------------------------------------------------
|
||||
notifyCVAck(void)
|
||||
|
2612
NmraDcc.cpp
2612
NmraDcc.cpp
File diff suppressed because it is too large
Load Diff
520
NmraDcc.h
520
NmraDcc.h
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Model Railroading with Arduino - NmraDcc.h
|
||||
//
|
||||
// Copyright (c) 2008 - 2105 Alex Shepherd
|
||||
// Copyright (c) 2008 - 2018 Alex Shepherd
|
||||
//
|
||||
// This source file is subject of the GNU general public license 2,
|
||||
// that is available at the world-wide-web at
|
||||
@@ -19,6 +19,8 @@
|
||||
// 2015-11-06 Martin Pischky (martin@pischky.de):
|
||||
// Experimental Version to support 14 speed steps
|
||||
// and new signature of notifyDccSpeed and notifyDccFunc
|
||||
// 2017-11-29 Ken West (kgw4449@gmail.com):
|
||||
// Added method and callback headers.
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
@@ -30,7 +32,7 @@
|
||||
// Uncomment the following Line to Enable Service Mode CV Programming
|
||||
#define NMRA_DCC_PROCESS_SERVICEMODE
|
||||
|
||||
// Uncomment the following line to Enable MutliFunction Decoder Operations
|
||||
// Uncomment the following line to Enable MultiFunction Decoder Operations
|
||||
#define NMRA_DCC_PROCESS_MULTIFUNCTION
|
||||
|
||||
// Uncomment the following line to Enable 14 Speed Step Support
|
||||
@@ -42,9 +44,13 @@
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
#include "EEPROM.h"
|
||||
|
||||
#ifndef NMRADCC_IS_IN
|
||||
#define NMRADCC_IS_IN
|
||||
|
||||
#define NMRADCC_VERSION 201 // Version 2.0.1
|
||||
|
||||
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
|
||||
|
||||
typedef struct
|
||||
@@ -89,12 +95,24 @@ typedef struct
|
||||
#define CV_VERSION_ID 7
|
||||
#define CV_MANUFACTURER_ID 8
|
||||
#define CV_29_CONFIG 29
|
||||
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <esp_log.h>
|
||||
#define MAXCV SPI_FLASH_SEC_SIZE
|
||||
#elif 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
|
||||
// because STM32 uses virtual adresses)
|
||||
#else
|
||||
#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_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
|
||||
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 */
|
||||
@@ -185,24 +203,189 @@ class NmraDcc
|
||||
NmraDcc();
|
||||
|
||||
// Flag values to be logically ORed together and passed into the init() method
|
||||
#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
|
||||
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6
|
||||
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7
|
||||
void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
#define FLAGS_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
|
||||
#define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
|
||||
#define FLAGS_SETCV_CALLED 0x10 // only used internally !!
|
||||
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6
|
||||
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7
|
||||
|
||||
// Flag Bits that are cloned from CV29 relating the DCC Accessory Decoder
|
||||
#define FLAGS_CV29_BITS (FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER)
|
||||
|
||||
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntNum - Interrupt number of the pin. Use digitalPinToInterrupt(ExtIntPinNum).
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
|
||||
/*+
|
||||
* pin() is called from setup() and sets up the pin used to receive DCC packets.
|
||||
* This relies on the internal function: digitalPinToInterrupt() to map the input pin number to the right interrupt
|
||||
*
|
||||
* Inputs:
|
||||
* ExtIntPinNum - Input pin number.
|
||||
* EnablePullup - Set true to enable the pins pullup resistor.
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
#ifdef digitalPinToInterrupt
|
||||
void pin( uint8_t ExtIntPinNum, uint8_t EnablePullup);
|
||||
#endif
|
||||
|
||||
/*+
|
||||
* init() is called from setup() after the pin() command is called.
|
||||
* It initializes the NmDcc object and makes it ready to process packets.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_MY_ADDRESS_ONLY - Only process packets with My Address.
|
||||
* FLAGS_DCC_ACCESSORY_DECODER - Decoder is an accessory decoder.
|
||||
* FLAGS_OUTPUT_ADDRESS_MODE - This flag applies to accessory decoders only.
|
||||
* Accessory decoders normally have 4 paired outputs
|
||||
* and a single address refers to all 4 outputs.
|
||||
* Setting FLAGS_OUTPUT_ADDRESS_MODE causes each
|
||||
* address to refer to a single output.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void init( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
|
||||
|
||||
/*+
|
||||
* initAccessoryDecoder() is called from setup() for accessory decoders.
|
||||
* It calls init() with FLAGS_DCC_ACCESSORY_DECODER ORed into Flags.
|
||||
*
|
||||
* Inputs:
|
||||
* ManufacturerId - Manufacturer ID returned in CV 8.
|
||||
* Commonly MAN_ID_DIY.
|
||||
* VersionId - Version ID returned in CV 7.
|
||||
* Flags - ORed flags beginning with FLAGS_...
|
||||
* FLAGS_DCC_ACCESSORY_DECODER will be set for init() call.
|
||||
* OpsModeAddressBaseCV - Ops Mode base address. Set it to 0?
|
||||
*
|
||||
* Returns:
|
||||
* None.
|
||||
*/
|
||||
void initAccessoryDecoder( uint8_t ManufacturerId, uint8_t VersionId, uint8_t Flags, uint8_t OpsModeAddressBaseCV );
|
||||
|
||||
/*+
|
||||
* process() is called from loop() to process DCC packets.
|
||||
* It must be called very frequently to keep up with the packets.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - Packet succesfully parsed on this call to process().
|
||||
* 0 - Packet not ready or received packet had an error.
|
||||
*/
|
||||
uint8_t process();
|
||||
|
||||
/*+
|
||||
* getCV() returns the selected CV value.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value. Invalid CV numbers will return an undefined result
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVRead() if it is defined.
|
||||
*/
|
||||
uint8_t getCV( uint16_t CV );
|
||||
|
||||
/*+
|
||||
* setCV() sets the value of a CV.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* Value - CV value set by this call.
|
||||
* since nothing will have been set in that EEPROM position.
|
||||
* Calls notifyCVWrite() if it is defined.
|
||||
* Calls notifyCVChange() if the value is changed by this call.
|
||||
*/
|
||||
uint8_t setCV( uint16_t CV, uint8_t Value);
|
||||
uint8_t isSetCVReady( void );
|
||||
uint16_t getAddr(void);
|
||||
|
||||
/*+
|
||||
* setAccDecDCCAddrNextReceived() enables/disables the setting of the board address from the next received turnout command
|
||||
*
|
||||
* Inputs:
|
||||
* enable- boolean to enable or disable the mode
|
||||
*
|
||||
* Returns:
|
||||
*/
|
||||
void setAccDecDCCAddrNextReceived(uint8_t enable);
|
||||
|
||||
/*+
|
||||
* isSetCVReady() returns 1 if EEPROM is ready to write.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number. It must point to a valid CV.
|
||||
* Value - CV value.
|
||||
*
|
||||
* Returns:
|
||||
* ready - 1 if ready to write, 0 otherwise. AVR processor will block
|
||||
* for several ms. for each write cycle so you should check this to avoid blocks.
|
||||
* Note: It returns the value returned by notifyIsSetCVReady() if it is defined.
|
||||
* Calls notifyIsSetCVReady() if it is defined.
|
||||
*/
|
||||
uint8_t isSetCVReady( void );
|
||||
|
||||
/*+
|
||||
* getAddr() return the currently active decoder address.
|
||||
* based on decoder type and current address size.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Adr - The current decoder address based on decoder type(Multifunction, Accessory)
|
||||
* and short or long address selection for Multifunction decoders.
|
||||
*/
|
||||
uint16_t getAddr(void);
|
||||
|
||||
/*+
|
||||
* getX() return debugging data if DCC_DEBUG is defined.
|
||||
* You would really need to be modifying the library to need them.
|
||||
*
|
||||
* Inputs:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* getIntCount - Init to 0 and apparently never incremented?
|
||||
* getTickCount - Init to 0 and incremented each time interrupt handler
|
||||
* completes without an error.
|
||||
* getBitCount - Bit count of valid packet, 0 otherwise. Only valid until
|
||||
* start of the next packet.
|
||||
* getState - Current WAIT_... state as defined by DccRxWaitState in NmraDcc.cpp.
|
||||
* getNestedIrqCount - Init to 0 and incremented each time the interrupt handler
|
||||
* is called before the previous interrupt was complete.
|
||||
* This is an error indication and may indicate the system
|
||||
* is not handling packets fast enough or some other error is occurring.
|
||||
*/
|
||||
// #define DCC_DEBUG
|
||||
#ifdef DCC_DEBUG
|
||||
uint8_t getIntCount(void);
|
||||
uint8_t getTickCount(void);
|
||||
uint8_t getBitCount(void);
|
||||
uint8_t getState(void);
|
||||
uint8_t getIntCount(void);
|
||||
uint8_t getTickCount(void);
|
||||
uint8_t getBitCount(void);
|
||||
uint8_t getState(void);
|
||||
uint8_t getNestedIrqCount(void);
|
||||
#endif
|
||||
|
||||
};
|
||||
@@ -215,30 +398,321 @@ class NmraDcc
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak));
|
||||
extern void notifyDccIdle(void) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyDccReset(uint8_t hardReset) Callback for a DCC reset command.
|
||||
*
|
||||
* Inputs:
|
||||
* hardReset - 0 normal reset command.
|
||||
* 1 hard reset command.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccReset(uint8_t hardReset ) __attribute__ ((weak));
|
||||
|
||||
extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) __attribute__ ((weak));
|
||||
extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyDccIdle() Callback for a DCC idle command.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccIdle(void) __attribute__ ((weak));
|
||||
|
||||
extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak));
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak));
|
||||
extern void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyDccSpeed() Callback for a multifunction decoder speed command.
|
||||
* The received speed and direction are unpacked to separate values.
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Active decoder address.
|
||||
* AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG.
|
||||
* Speed - Decoder speed. 0 = Emergency stop
|
||||
* 1 = Regular stop
|
||||
* 2 to SpeedSteps = Speed step 1 to max.
|
||||
* Dir - DCC_DIR_REV or DCC_DIR_FWD
|
||||
* SpeedSteps - Highest speed, SPEED_STEP_14 = 15
|
||||
* SPEED_STEP_28 = 29
|
||||
* SPEED_STEP_128 = 127
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps ) __attribute__ ((weak));
|
||||
|
||||
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyDccSpeedRaw() Callback for a multifunction decoder speed command.
|
||||
* The value in Raw is the unpacked speed command.
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Active decoder address.
|
||||
* AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG.
|
||||
* Raw - Raw decoder speed command.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSpeedRaw( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Raw) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccFunc() Callback for a multifunction decoder function command.
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Active decoder address.
|
||||
* AddrType - DCC_ADDR_SHORT or DCC_ADDR_LONG.
|
||||
* FuncGrp - Function group. FN_0 - 14 speed step headlight function.
|
||||
* Mask FN_BIT_00.
|
||||
* FN_0_4 - Functions 0 to 4. Mask FN_BIT_00 - FN_BIT_04
|
||||
* FN_5_8 - Functions 5 to 8. Mask FN_BIT_05 - FN_BIT_08
|
||||
* FN_9_12 - Functions 9 to 12. Mask FN_BIT_09 - FN_BIT_12
|
||||
* FN_13_20 - Functions 13 to 20. Mask FN_BIT_13 - FN_BIT_20
|
||||
* FN_21_28 - Functions 21 to 28. Mask FN_BIT_21 - FN_BIT_28
|
||||
* FuncState - Function state. Bitmask where active functions have a 1 at that bit.
|
||||
* You must & FuncState with the appropriate
|
||||
* FN_BIT_nn value to isolate a given bit.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccTurnoutBoard() Board oriented callback for a turnout accessory decoder.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
||||
* Decoders of this type have 4 paired turnout outputs per board.
|
||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||
*
|
||||
* Inputs:
|
||||
* BoardAddr - Per board address. Equivalent to CV 1 LSB & CV 9 MSB.
|
||||
* OutputPair - Output pair number. It has a range of 0 to 3.
|
||||
* Equivalent to upper 2 bits of the 3 DDD bits in the accessory packet.
|
||||
* Direction - Turnout direction. It has a value of 0 or 1.
|
||||
* It is equivalent to bit 0 of the 3 DDD bits in the accessory packet.
|
||||
* OutputPower - Output On/Off. Equivalent to packet C bit. It has these values:
|
||||
* 0 - Output pair is off.
|
||||
* 1 - Output pair is on.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
|
||||
extern void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyDccAccTurnoutOutput() Output oriented callback for a turnout accessory decoder.
|
||||
* Most useful when CV29_OUTPUT_ADDRESS_MODE is not set.
|
||||
* Decoders of this type have 4 paired turnout outputs per board.
|
||||
* OutputPower is 1 if the power is on, and 0 otherwise.
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Per output address. There will be 4 Addr addresses
|
||||
* per board for a standard accessory decoder with 4 output pairs.
|
||||
* Direction - Turnout direction. It has a value of 0 or 1.
|
||||
* Equivalent to bit 0 of the 3 DDD bits in the accessory packet.
|
||||
* OutputPower - Output On/Off. Equivalent to packet C bit. It has these values:
|
||||
* 0 - Output is off.
|
||||
* 1 - Output is on.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccBoardAddrSet() Board oriented callback for a turnout accessory decoder.
|
||||
* This notification is when a new Board Address is set to the
|
||||
* address of the next DCC Turnout Packet that is received
|
||||
*
|
||||
* This is enabled via the setAccDecDCCAddrNextReceived() method above
|
||||
*
|
||||
* Inputs:
|
||||
* BoardAddr - Per board address. Equivalent to CV 1 LSB & CV 9 MSB.
|
||||
* per board for a standard accessory decoder with 4 output pairs.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccBoardAddrSet( uint16_t BoardAddr) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccAccOutputAddrSet() Output oriented callback for a turnout accessory decoder.
|
||||
* This notification is when a new Output Address is set to the
|
||||
* address of the next DCC Turnout Packet that is received
|
||||
*
|
||||
* This is enabled via the setAccDecDCCAddrNextReceived() method above
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Per output address. There will be 4 Addr addresses
|
||||
* per board for a standard accessory decoder with 4 output pairs.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccAccOutputAddrSet( uint16_t Addr) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccSigOutputState() Callback for a signal aspect accessory decoder.
|
||||
* Defined in S-9.2.1 as the Extended Accessory Decoder Control Packet.
|
||||
*
|
||||
* Inputs:
|
||||
* Addr - Decoder address.
|
||||
* State - 6 bit command equivalent to S-9.2.1 00XXXXXX.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccSigOutputState( uint16_t Addr, uint8_t State) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyDccMsg() Raw DCC packet callback.
|
||||
* Called with raw DCC packet bytes.
|
||||
*
|
||||
* Inputs:
|
||||
* Msg - Pointer to DCC_MSG structure. The values are:
|
||||
* Msg->Size - Number of Data bytes in the packet.
|
||||
* Msg->PreambleBits - Number of preamble bits in the packet.
|
||||
* Msg->Data[] - Array of data bytes in the packet.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyDccMsg( DCC_MSG * Msg ) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyCVValid() Callback to determine if a given CV is valid.
|
||||
* This is called when the library needs to determine
|
||||
* if a CV is valid. Note: If defined, this callback
|
||||
* MUST determine if a CV is valid and return the
|
||||
* appropriate value. If this callback is not defined,
|
||||
* the library will determine validity.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number.
|
||||
* Writable - 1 for CV writes. 0 for CV reads.
|
||||
*
|
||||
* Returns:
|
||||
* 1 - CV is valid.
|
||||
* 0 - CV is not valid.
|
||||
*/
|
||||
extern uint8_t notifyCVValid( uint16_t CV, uint8_t Writable ) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyCVRead() Callback to read a CV.
|
||||
* This is called when the library needs to read
|
||||
* a CV. Note: If defined, this callback
|
||||
* MUST return the value of the CV.
|
||||
* If this callback is not defined,
|
||||
* the library will read the CV from EEPROM.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number.
|
||||
*
|
||||
* Returns:
|
||||
* Value - Value of the CV.
|
||||
*/
|
||||
extern uint8_t notifyCVRead( uint16_t CV) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyCVWrite() Callback to write a value to a CV.
|
||||
* This is called when the library needs to write
|
||||
* a CV. Note: If defined, this callback
|
||||
* MUST write the Value to the CV and return the value of the CV.
|
||||
* If this callback is not defined,
|
||||
* the library will read the CV from EEPROM.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number.
|
||||
* Value - Value of the CV.
|
||||
*
|
||||
* Returns:
|
||||
* Value - Value of the CV.
|
||||
*/
|
||||
extern uint8_t notifyCVWrite( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyIsSetCVReady() Callback to to determine if CVs can be written.
|
||||
* This is called when the library needs to determine
|
||||
* is ready to write without blocking or failing.
|
||||
* Note: If defined, this callback
|
||||
* MUST determine if a CV write would block or fail
|
||||
* return the appropriate value.
|
||||
* If this callback is not defined,
|
||||
* the library determines if a write to the EEPROM
|
||||
* would block.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
*
|
||||
* Returns:
|
||||
* 1 - CV is ready to be written.
|
||||
* 0 - CV is not ready to be written.
|
||||
*/
|
||||
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.
|
||||
* 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.
|
||||
*
|
||||
* Inputs:
|
||||
* CV - CV number.
|
||||
* Value - Value of the CV.
|
||||
*
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
extern void notifyDccCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyCVResetFactoryDefault() Called when CVs must be reset.
|
||||
* This is called when CVs must be reset
|
||||
* to their factory defaults. This callback
|
||||
* should write the factory default value of
|
||||
* relevent CVs using the setCV() method.
|
||||
* setCV() must not block whens this is called.
|
||||
* Test with isSetCVReady() prior to calling setCV()
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
* *
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVResetFactoryDefault(void) __attribute__ ((weak));
|
||||
|
||||
/*+
|
||||
* notifyCVAck() Called when a CV write must be acknowledged.
|
||||
* This callback must increase the current drawn by this
|
||||
* decoder by at least 60mA for 6ms +/- 1ms.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
* *
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyCVAck(void) __attribute__ ((weak));
|
||||
/*+
|
||||
* notifyServiceMode(bool) Called when state of 'inServiceMode' changes
|
||||
*
|
||||
* Inputs:
|
||||
* bool state of inServiceMode
|
||||
* *
|
||||
* Returns:
|
||||
* None
|
||||
*/
|
||||
extern void notifyServiceMode(bool) __attribute__ ((weak));
|
||||
|
||||
// Deprecated, only for backward compatibility with version 1.4.2.
|
||||
// Don't use in new designs. These functions may be dropped in future versions
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State ) __attribute__ ((weak));
|
||||
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State) __attribute__ ((weak));
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
10
README.md
10
README.md
@@ -1,2 +1,12 @@
|
||||
# NmraDcc
|
||||
NMRA Digital Command Control (DCC) Library
|
||||
|
||||
This library allows you to interface to a NMRA DCC track signal and receive DCC commands.
|
||||
|
||||
The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 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.
|
||||
|
||||
**Warning** as of version 1.4.4 support has been removed for the following two call-back functions, which will cause your sketch to silently stop working:
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State )
|
||||
extern void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State)
|
||||
|
||||
|
@@ -0,0 +1,259 @@
|
||||
// DCC Stepper Motor Controller ( A4988 ) Example for Model Railroad Turntable Control
|
||||
//
|
||||
// See: https://www.dccinterface.com/how-to/assemblyguide/
|
||||
//
|
||||
// Author: Alex Shepherd 2017-12-04
|
||||
//
|
||||
// This example requires two Arduino Libraries:
|
||||
//
|
||||
// 1) The AccelStepper library from: http://www.airspayce.com/mikem/arduino/AccelStepper/index.html
|
||||
//
|
||||
// 2) The NmraDcc Library from: http://mrrwa.org/download/
|
||||
//
|
||||
// Both libraries can be found and installed via the Arduino IDE Library Manager
|
||||
//
|
||||
// Also checkout the artical I wrote in this project here:
|
||||
// http://mrrwa.org/2017/12/23/dcc-controlled-turntable-stepper-motor-driver/
|
||||
//
|
||||
|
||||
#include <AccelStepper.h>
|
||||
#include <NmraDcc.h>
|
||||
|
||||
// The lines below define the pins used to connect to the A4988 driver module
|
||||
#define A4988_STEP_PIN 4
|
||||
#define A4988_DIRECTION_PIN 5
|
||||
// Uncomment the next line to enable Powering-Off the Stepper when its not running to reduce heating the motor and driver
|
||||
#define A4988_ENABLE_PIN 6
|
||||
|
||||
// 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_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
|
||||
#define MOTOR_FULL_STEPS_PER_REVOLUTION 200
|
||||
|
||||
// The line below defines any reduction gearbox multiplier. No gearbox = 1
|
||||
#define REDUCTION_GEARBOX_RATIO 1
|
||||
|
||||
#define STEPS_PER_REVOLUTION (MOTOR_FULL_STEPS_PER_REVOLUTION * REDUCTION_GEARBOX_RATIO)
|
||||
|
||||
// The A4988 Driver Board has 3 pins that set the Stepping Mode which are connected to 3 jumpers on the board.
|
||||
// Uncomment the line below to match the Boards jumper setting MS1, MS2, MS3
|
||||
// --------------------------------------------------------------------------------------------
|
||||
//#define FULL_TURN_STEPS (STEPS_PER_REVOLUTION) // full steps - MS1=OFF, MS2=OFF, MS3=OFF
|
||||
//#define FULL_TURN_STEPS (STEPS_PER_REVOLUTION * 2) // 1/2 steps - MS1=ON, MS2=OFF, MS3=OFF
|
||||
#define FULL_TURN_STEPS (STEPS_PER_REVOLUTION * 4) // 1/4 steps - MS1=OFF, MS2=ON, MS3=OFF
|
||||
//#define FULL_TURN_STEPS (STEPS_PER_REVOLUTION * 8) // 1/8 steps - MS1=ON, MS2=ON, MS3=OFF
|
||||
//#define FULL_TURN_STEPS (STEPS_PER_REVOLUTION * 16) // 1/16 steps - MS1=ON, MS2=ON, MS3=ON
|
||||
|
||||
#ifndef FULL_TURN_STEPS
|
||||
#error You need to select one of the FULL_TURN_STEPS to match the A4988 Driver Board jumper settings
|
||||
#endif
|
||||
|
||||
// This constant is useful to know the number of steps to rotate the turntable 180 degrees for the back entrance position
|
||||
#define HALF_TURN_STEPS (FULL_TURN_STEPS / 2)
|
||||
|
||||
// Home Position Sensor Input
|
||||
#define HOME_SENSOR_PIN 3
|
||||
#define HOME_SENSOR_ACTIVE_STATE HIGH
|
||||
|
||||
// This structure holds the values for a turntable position wiht the DCC Address, Front Position in Steps from Home Sensor
|
||||
typedef struct
|
||||
{
|
||||
int dccAddress;
|
||||
int positionFront;
|
||||
int positionBack;
|
||||
}
|
||||
TurnoutPosition;
|
||||
|
||||
// The constant HOME_POSITION_DCC_ADDRESS is the base DCC Accessory Decoder Address for the Home Position
|
||||
// with each subsequent position numbered sequentially from there
|
||||
#define POSITION_01_DCC_ADDRESS 200
|
||||
|
||||
// I decided to divide the turntable up into 10 Positions using #defines and mathc so it all scales with changes
|
||||
// to the MS1,MS2,MS3 stepping jumpers above and to make the math tidy, but you assign positions how ever you like
|
||||
#define POSITION_01 (HALF_TURN_STEPS / 10)
|
||||
|
||||
// This array contains the Turnout Positions which can have lines added/removed to suit your turntable
|
||||
TurnoutPosition turnoutPositions[] = {
|
||||
{POSITION_01_DCC_ADDRESS + 0, POSITION_01 * 1, POSITION_01 * 1 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 1, POSITION_01 * 2, POSITION_01 * 2 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 2, POSITION_01 * 3, POSITION_01 * 3 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 3, POSITION_01 * 4, POSITION_01 * 4 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 4, POSITION_01 * 5, POSITION_01 * 5 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 5, POSITION_01 * 6, POSITION_01 * 6 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 6, POSITION_01 * 7, POSITION_01 * 7 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 7, POSITION_01 * 8, POSITION_01 * 8 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 8, POSITION_01 * 9, POSITION_01 * 9 + HALF_TURN_STEPS },
|
||||
{POSITION_01_DCC_ADDRESS + 9, POSITION_01 *10, POSITION_01 *10 + HALF_TURN_STEPS },
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// You shouldn't need to edit anything below this line unless you're needing to make big changes... ;)
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
#define MAX_TURNOUT_POSITIONS (sizeof(turnoutPositions) / sizeof(TurnoutPosition))
|
||||
|
||||
// Setup the AccelStepper object for the A4988 Stepper Motor Driver
|
||||
AccelStepper stepper1(AccelStepper::DRIVER, A4988_STEP_PIN, A4988_DIRECTION_PIN);
|
||||
|
||||
// Dcc Accessory Decoder object
|
||||
NmraDcc Dcc ;
|
||||
|
||||
// Variables to store the last DCC Turnout message Address and Direction
|
||||
uint16_t lastAddr = 0xFFFF ;
|
||||
uint8_t lastDirection = 0xFF;
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
Serial.print("notifyDccAccTurnoutOutput: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
|
||||
for (int i = 0; i < MAX_TURNOUT_POSITIONS ; i++)
|
||||
{
|
||||
if ((Addr == turnoutPositions[i].dccAddress) && ((Addr != lastAddr) || (Direction != lastDirection)) && OutputPower)
|
||||
{
|
||||
lastAddr = Addr ;
|
||||
lastDirection = Direction ;
|
||||
|
||||
Serial.print(F("Moving to "));
|
||||
Serial.print(Direction ? F("Front") : F("Back"));
|
||||
Serial.print(F(" Position: "));
|
||||
Serial.print(i, DEC);
|
||||
Serial.print(F(" @ Step: "));
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.enableOutputs();
|
||||
#endif
|
||||
if (Direction)
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionFront, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionFront);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println(turnoutPositions[i].positionBack, DEC);
|
||||
stepper1.moveTo(turnoutPositions[i].positionBack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
bool lastIsRunningState ;
|
||||
#endif
|
||||
|
||||
void setupStepperDriver()
|
||||
{
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
stepper1.setPinsInverted(false, false, true); // Its important that these commands are in this order
|
||||
stepper1.setEnablePin(A4988_ENABLE_PIN); // otherwise the Outputs are NOT enabled initially
|
||||
#endif
|
||||
|
||||
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
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool moveToHomePosition()
|
||||
{
|
||||
Serial.println(F("Finding Home Sensor...."));
|
||||
|
||||
pinMode(HOME_SENSOR_PIN, INPUT_PULLUP);
|
||||
|
||||
stepper1.move(FULL_TURN_STEPS * 2);
|
||||
while(digitalRead(HOME_SENSOR_PIN) != HOME_SENSOR_ACTIVE_STATE)
|
||||
stepper1.run();
|
||||
|
||||
if(digitalRead(HOME_SENSOR_PIN) == HOME_SENSOR_ACTIVE_STATE)
|
||||
{
|
||||
Serial.println(F("Found Home Position - Setting Current Position to 0"));
|
||||
stepper1.setCurrentPosition(0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
Serial.println(F("Home Position NOT FOUND - Check Sensor Hardware"));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void setupDCCDecoder()
|
||||
{
|
||||
Serial.println(F("Setting up DCC Decorder..."));
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 1);
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER | CV29_OUTPUT_ADDRESS_MODE, 0 );
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while(!Serial); // Wait for the USB Device to Enumerate
|
||||
|
||||
Serial.println(F("\nExample Stepper Motor Driver for DCC Turntable Control"));
|
||||
|
||||
Serial.print(F("Full Rotation Steps: "));
|
||||
Serial.println(FULL_TURN_STEPS);
|
||||
|
||||
for(uint8_t i = 0; i < MAX_TURNOUT_POSITIONS; i++)
|
||||
{
|
||||
Serial.print("DCC Addr: ");
|
||||
Serial.print(turnoutPositions[i].dccAddress);
|
||||
|
||||
Serial.print(" Front: ");
|
||||
Serial.print(turnoutPositions[i].positionFront);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
|
||||
// Process the Stepper Library
|
||||
stepper1.run();
|
||||
|
||||
#ifdef A4988_ENABLE_PIN
|
||||
if(stepper1.isRunning() != lastIsRunningState)
|
||||
{
|
||||
lastIsRunningState = stepper1.isRunning();
|
||||
if(!lastIsRunningState)
|
||||
{
|
||||
stepper1.disableOutputs();
|
||||
Serial.println(F("Disable Stepper Outputs"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
@@ -56,20 +56,7 @@ void notifyDccMsg( DCC_MSG * Msg)
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State)
|
||||
{
|
||||
Serial.print("notifyDccAccState: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(BoardAddr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(OutputAddr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(State, HEX) ;
|
||||
}
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
// This function is called whenever a normal DCC Turnout Packet is received and we're in Board Addressing Mode
|
||||
void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
Serial.print("notifyDccAccTurnoutBoard: ") ;
|
||||
@@ -82,7 +69,7 @@ void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t D
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
}
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
// This function is called whenever a normal DCC Turnout Packet is received and we're in Output Addressing Mode
|
||||
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
Serial.print("notifyDccAccTurnoutOutput: ") ;
|
||||
@@ -94,13 +81,11 @@ void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t Output
|
||||
}
|
||||
|
||||
// This function is called whenever a DCC Signal Aspect Packet is received
|
||||
void notifyDccSigState( uint16_t Addr, uint8_t OutputIndex, uint8_t State)
|
||||
void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
|
||||
{
|
||||
Serial.print("notifyDccSigState: ") ;
|
||||
Serial.print("notifyDccSigOutputState: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(OutputIndex,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(State, HEX) ;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,314 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
438
examples/NmraValidation/Accessory_Test/Accessory_Test.ino
Executable file
438
examples/NmraValidation/Accessory_Test/Accessory_Test.ino
Executable file
@@ -0,0 +1,438 @@
|
||||
/***********************************************************************************************
|
||||
*
|
||||
* This sketch test the NmraDcc library as an accessory decoder.
|
||||
* Author: Kenneth West
|
||||
* kgw4449@gmail.com
|
||||
*
|
||||
* This sketch has added the printf() function to the Print class.
|
||||
* You can find instructions for doing this here:
|
||||
* http://playground.arduino.cc/Main/Printf
|
||||
*
|
||||
* It is based on NmraDcc library NmraDccAccessoryDecoder_1 example.
|
||||
* You can find the library here:
|
||||
* https://github.com/mrrwa/NmraDcc
|
||||
*
|
||||
* This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
|
||||
* You can find out more about this DCC Interface here:
|
||||
* http://www.iascaled.com/store/ARD-DCCSHIELD
|
||||
*
|
||||
* For more information refer to the file: README.md here:
|
||||
* https://github.com/IowaScaledEngineering/ard-dccshield
|
||||
*
|
||||
* This demo assumes the following Jumper settings on the ARD-DCCSHIELD
|
||||
*
|
||||
* JP1 - I2C Pull-Up Resistors - Don't Care
|
||||
* JP2 - (Pins 1-2) I2C /IORST JP2 - Don't-Care
|
||||
* JP2 - (Pins 3-4) - DCC Signal to Arduino Pin - OFF
|
||||
* JP3 - I2C /INT and /OE - Don't-Care
|
||||
* JP4 - DCC Signal to Arduino Pin - D2 ON
|
||||
* JP5 - Arduino Powered from DCC - User Choice
|
||||
* JP6 - Boards without VIO - User Choice
|
||||
* JP7 - Enable Programming ACK - 1-2 ON 3-4 ON
|
||||
*
|
||||
* The connections are as follows:
|
||||
*
|
||||
* Pin Name Mode Description
|
||||
* ----------------------------------------------------------------------------------
|
||||
* D2 DCC_PIN INPUT_PULLUP DCC input signal.
|
||||
* A1 ACK_PIN OUTPUT CV acknowledge control.
|
||||
* A0 ACC_A_PIN OUTPUT Accessory output A.
|
||||
* D13 ACC_B_PIN OUTPUT Accessory output B.
|
||||
* D4 SCOPE_PIN OUTPUT SCOPE trigger pin.
|
||||
*
|
||||
***********************************************************************************************
|
||||
*/
|
||||
|
||||
#include <NmraDcc.h>
|
||||
|
||||
// Uncomment this line to print out minimal status information.
|
||||
#define DCC_STATUS
|
||||
|
||||
// Uncomment this line to issue scope trigger at beginning of motor callback.
|
||||
#define DO_SCOPE
|
||||
|
||||
// Uncomment this line to handle Basic Accessory decoders.
|
||||
#define ACCESSORY_DCC
|
||||
|
||||
// Uncomment this line to handle Signal decoders.
|
||||
#define SIGNAL_DCC
|
||||
|
||||
const byte VER_MAJOR = 2; // Major version in CV 7
|
||||
const byte VER_MINOR = 1; // Minor version in CV 112
|
||||
const byte DCC_PIN = 2; // DCC input pin.
|
||||
const int ACK_PIN = A1; // CV acknowledge pin.
|
||||
const byte SCOPE_PIN = 4; // Scope trigger pin.
|
||||
const byte ACC_A_PIN = A0; // Motor out A pin.
|
||||
const byte ACC_B_PIN = 13; // Motor out B pin.
|
||||
const byte CV_VERSION = 7; // Decoder version.
|
||||
const byte CV_MANUF = 8; // Manufacturer ID.
|
||||
const byte CV_MANUF_01 = 112; // Manufacturer Unique 01.
|
||||
const byte MANUF_ID = MAN_ID_DIY; // Manufacturer ID in CV 8.
|
||||
const unsigned long DELAY_TIME = 50; // Delay time in ms.
|
||||
|
||||
// The following constant is the 9 bit accessory address. It is followed by the 6 LSB bits that
|
||||
// go into CV1 and the 6 MBB bits that go into CV9.
|
||||
// Note: Set FORCE_CVS true to force CVs to update if just the address is changed.
|
||||
const bool FORCE_CVS = false; // Set true to force CV write.
|
||||
const uint16_t ACC_ADDR = 1; // 11 bit address:
|
||||
// 0 - broadcast, 1 to 2044 - specific.
|
||||
const uint16_t BD_ADDR = ((ACC_ADDR - 1) >> 2) + 1;
|
||||
// 9 bit board address:
|
||||
// 0 - broadcast, 1 to 511 - specific.
|
||||
const byte BD_LSB = BD_ADDR & 0x3f; // Board address LSB.
|
||||
const byte BD_MSB = BD_ADDR >> 6; // Board address MSB.
|
||||
|
||||
// CV29_DEFAULT is the factory hardware default for CV29.
|
||||
const byte CV29_DEFAULT = CV29_OUTPUT_ADDRESS_MODE |
|
||||
CV29_ACCESSORY_DECODER;
|
||||
|
||||
enum ACC_DIR {
|
||||
REV = 0, // Direction is reverse.
|
||||
NORM = 1, // Direction is normal.
|
||||
};
|
||||
|
||||
enum ShowTypes {
|
||||
S_IDLE = 0x01, // Show Idle packets.
|
||||
S_RESET = 0x02, // Show Reset packets.
|
||||
S_DCC = 0x04, // Show DCC information.
|
||||
S_ACK = 0x08, // Basic acknowledge off.
|
||||
S_ALL = 0x80, // Show raw packet data.
|
||||
};
|
||||
|
||||
ACC_DIR AccDir = REV; // Accessory direction.
|
||||
byte ShowData = 0x00; // Packet information to show.
|
||||
unsigned long EndTime = 0; // End time in ms.
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, BD_LSB}, // Accessory address LSB.
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, BD_MSB}, // Accessory address MSB.
|
||||
|
||||
// Reload these just in case they are writeen by accident.
|
||||
{CV_VERSION, VER_MAJOR}, // Decoder version.
|
||||
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
|
||||
|
||||
{CV_29_CONFIG, CV29_DEFAULT}, // Configuration CV.
|
||||
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
|
||||
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
|
||||
Serial.println(F("notifyCVResetFactoryDefault called."));
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
#define NOTITY_DCC_ACC_TURNOUT_BOARD
|
||||
#ifdef NOTITY_DCC_ACC_TURNOUT_BOARD
|
||||
void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print("notifyDccAccTurnoutBoard: ") ;
|
||||
Serial.print(BoardAddr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(OutputPair,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
}
|
||||
}
|
||||
#endif // NOTITY_DCC_ACC_TURNOUT_BOARD
|
||||
|
||||
// This function is called whenever a normal DCC Turnout Packet is received
|
||||
// if NOTIFY_DCC_ACC_TURNOUT and ACCESSORY_DCC are defined.
|
||||
#define NOTITY_DCC_ACC_TURNOUT_OUTPUT
|
||||
#if defined(NOTITY_DCC_ACC_TURNOUT_OUTPUT) && defined(ACCESSORY_DCC)
|
||||
void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
|
||||
{
|
||||
#ifdef DO_SCOPE
|
||||
digitalWrite(SCOPE_PIN, HIGH);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print("notifyDccAccTurnoutOutput: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.print(Direction,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(OutputPower, HEX) ;
|
||||
}
|
||||
|
||||
// Set the output to the given direction for just the ACC_ADDR output
|
||||
// since this callback is called for all 4 output addresses.
|
||||
if (Addr == ACC_ADDR) {
|
||||
setAcc(Direction ? REV : NORM);
|
||||
}
|
||||
}
|
||||
#endif // NOTITY_DCC_ACC_TURNOUT_OUTPUT
|
||||
|
||||
// This function is called whenever a DCC Signal Aspect Packet is received
|
||||
// if NOTIFY_DCC_SIG_STATE and SIGNAL_DCC are defined.
|
||||
#define NOTITY_DCC_SIG_STATE
|
||||
#if defined(NOTITY_DCC_SIG_STATE) && defined(SIGNAL_DCC)
|
||||
void notifyDccSigOutputState( uint16_t Addr, uint8_t State)
|
||||
{
|
||||
#ifdef DO_SCOPE
|
||||
digitalWrite(SCOPE_PIN, HIGH);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print("notifyDccSigOutputState: ") ;
|
||||
Serial.print(Addr,DEC) ;
|
||||
Serial.print(',');
|
||||
Serial.println(State, DEC) ;
|
||||
}
|
||||
|
||||
// Set the output to the given direction for 1st ACC_ADDR output.
|
||||
if (Addr == ACC_ADDR) {
|
||||
setAcc(State == 0 ? REV : NORM);
|
||||
}
|
||||
}
|
||||
#endif // NOTITY_DCC_SIG_STATE
|
||||
|
||||
// This function is called whenever a DCC Reset packet is received.
|
||||
// Uncomment to print Reset Packets
|
||||
#define NOTIFY_DCC_RESET
|
||||
#ifdef NOTIFY_DCC_RESET
|
||||
void notifyDccReset(uint8_t hardReset )
|
||||
{
|
||||
if (ShowData & S_RESET) { // Show Reset packets if S_RESET is set.
|
||||
Serial.printf(F("notifyDccReset: %6s.\n"), hardReset ? "HARD" : "NORMAL");
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_RESET
|
||||
|
||||
// This function is called whenever a DCC Idle packet is received.
|
||||
// Uncomment to print Idle Packets
|
||||
#define NOTIFY_DCC_IDLE
|
||||
#ifdef NOTIFY_DCC_IDLE
|
||||
void notifyDccIdle()
|
||||
{
|
||||
if (ShowData & S_IDLE) { // Show Idle packets if S_IDLE is set.
|
||||
Serial.println("notifyDccIdle: Idle received") ;
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_IDLE
|
||||
|
||||
// Uncomment the #define below to print changed CV values.
|
||||
#define NOTIFY_CV_CHANGE
|
||||
#ifdef NOTIFY_CV_CHANGE
|
||||
void notifyCVChange( uint16_t CV, uint8_t Value) {
|
||||
Serial.printf(F("notifyCVChange: CV %4u value changed to %3u 0x%02X.\n"), CV, Value, Value);
|
||||
}
|
||||
#endif // NOTIFY_CV_CHANGE
|
||||
|
||||
// This function is called when any DCC packet is received.
|
||||
// Uncomment to print all DCC Packets
|
||||
#define NOTIFY_DCC_MSG
|
||||
#ifdef NOTIFY_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
if (ShowData & S_ALL) { // Show all packets if S_ALL is set.
|
||||
Serial.print("notifyDccMsg: ") ;
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_MSG
|
||||
|
||||
// This function is called by the NmraDcc library when a DCC ACK needs to be sent.
|
||||
// Calling this function should cause an increased 60ma current drain on
|
||||
// the power supply for 6ms to ACK a CV Read
|
||||
void notifyCVAck(void)
|
||||
{
|
||||
#ifdef DO_SCOPE
|
||||
digitalWrite(SCOPE_PIN, HIGH);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
if ((ShowData & S_ACK) == 0x00) { // Send CV acknowledge current pulse. [
|
||||
Serial.println("notifyCVAck: Current pulse sent") ;
|
||||
|
||||
digitalWrite( ACK_PIN, HIGH );
|
||||
delay( 6 );
|
||||
digitalWrite( ACK_PIN, LOW );
|
||||
}
|
||||
else { // Suppress CV acknowledge current pulse.
|
||||
Serial.println("notifyCVAck: Current pulse NOT sent") ;
|
||||
}
|
||||
}
|
||||
|
||||
void setAcc(ACC_DIR dir) {
|
||||
bool on; // Output on/off.
|
||||
on = dir == NORM ? true : false;
|
||||
#ifdef DCC_STATUS
|
||||
if (AccDir != dir) {
|
||||
Serial.printf(F("Accessory changed to %4s.\n"), on ? "NORM" : "REV");
|
||||
}
|
||||
#endif // DCC_STATUS
|
||||
AccDir = dir;
|
||||
digitalWrite(ACC_A_PIN, on);
|
||||
digitalWrite(ACC_B_PIN, !on);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.printf(F("Starting Accessory_Test Version %d.%d, Build date %s %s\n"),
|
||||
VER_MAJOR,
|
||||
VER_MINOR,
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
Serial.printf(F("Default ACC_ADDR %4u "), ACC_ADDR);
|
||||
Serial.printf(F("BD_ADDR %4u 0x%04X, BD_LSB %3u 0x%02X, BD_MSB %3u 0x%02X.\n"),
|
||||
BD_ADDR,
|
||||
BD_ADDR,
|
||||
BD_LSB,
|
||||
BD_LSB,
|
||||
BD_MSB,
|
||||
BD_MSB);
|
||||
Serial.println(F("Cmds: a - All, d - DCC, i - Idle, r - Reset, c - CV Ack off,"));
|
||||
Serial.println(F(" <Other> - Everything off."));
|
||||
|
||||
// Set AccOn REV to force setAcc() to set the output.
|
||||
AccDir = REV;
|
||||
|
||||
// Configure motor and fuction output pin pairs.
|
||||
pinMode( ACC_A_PIN, OUTPUT);
|
||||
pinMode( ACC_B_PIN, OUTPUT);
|
||||
setAcc(NORM);
|
||||
|
||||
// Configure the DCC CV Programing ACK pin for an output
|
||||
pinMode( ACK_PIN, OUTPUT );
|
||||
digitalWrite( ACK_PIN, LOW);
|
||||
|
||||
// Configure Scope trigger output.
|
||||
#ifdef DO_SCOPE
|
||||
pinMode( SCOPE_PIN, OUTPUT);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);
|
||||
|
||||
// Reset the CVs to factory default if the decode type,manuf. ID or major version
|
||||
// do not match. Do this before init() since it sets these CVs.
|
||||
if ( (FORCE_CVS) ||
|
||||
(Dcc.getCV(CV_29_CONFIG) != CV29_DEFAULT) ||
|
||||
(Dcc.getCV(CV_MANUFACTURER_ID) != MANUF_ID) ||
|
||||
(Dcc.getCV(CV_VERSION_ID) != VER_MAJOR) ||
|
||||
(Dcc.getCV(CV_MANUF_01) != VER_MINOR))
|
||||
{
|
||||
notifyCVResetFactoryDefault();
|
||||
}
|
||||
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MANUF_ID, VER_MAJOR, // FLAGS_MY_ADDRESS_ONLY |
|
||||
CV29_DEFAULT, 0 );
|
||||
|
||||
// Make sure CV_MANUF_01 CV matches VER_MINOR.
|
||||
Dcc.setCV(CV_MANUF_01, VER_MINOR);
|
||||
|
||||
Serial.println(F("Init Done"));
|
||||
|
||||
// Flush serial prior to entering loop().
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
|
||||
if (Serial.available()) {
|
||||
// Get the new byte and process it.
|
||||
switch ((char)Serial.read()) {
|
||||
case 'a':
|
||||
if (ShowData & S_ALL) {
|
||||
ShowData &= ~S_ALL;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_ALL;
|
||||
}
|
||||
Serial.println(ShowData & S_ALL ? "All ON" : "All OFF");
|
||||
break;
|
||||
case 'd':
|
||||
if (ShowData & S_DCC) {
|
||||
ShowData &= ~S_DCC;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_DCC;
|
||||
}
|
||||
Serial.println(ShowData & S_DCC ? "DCC ON" : "DCC OFF");
|
||||
break;
|
||||
case 'i':
|
||||
if (ShowData & S_IDLE) {
|
||||
ShowData &= ~S_IDLE;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_IDLE;
|
||||
}
|
||||
Serial.println(ShowData & S_IDLE ? "Idle ON" : "Idle OFF");
|
||||
break;
|
||||
case 'r':
|
||||
if (ShowData & S_RESET) {
|
||||
ShowData &= ~S_RESET;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_RESET;
|
||||
}
|
||||
Serial.println(ShowData & S_RESET ? "Reset ON" : "Reset OFF");
|
||||
break;
|
||||
case 'c':
|
||||
if (ShowData & S_ACK) {
|
||||
ShowData &= ~S_ACK;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_ACK;
|
||||
}
|
||||
Serial.println(ShowData & S_ACK ? "Ack OFF" : "Ack ON");
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
if (ShowData != 0x00) {
|
||||
EndTime = millis() + DELAY_TIME;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((EndTime != 0) && (millis() > EndTime)) {
|
||||
Serial.printf(F("Clearing ShowData 0x%02X\n"), ShowData);
|
||||
ShowData = 0x00;
|
||||
EndTime = 0;
|
||||
}
|
||||
|
||||
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
|
||||
{
|
||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
||||
Serial.printf(F("CV %4u reset to factory default %3u 0x%02X.\n"),
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].CV,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
}
|
||||
}
|
||||
|
1388
examples/NmraValidation/Loco Cap 2.1/arlc_3n.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_3n.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_3n.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_3n.sum
Executable file
File diff suppressed because it is too large
Load Diff
1388
examples/NmraValidation/Loco Cap 2.1/arlc_3r.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_3r.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_3r.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_3r.sum
Executable file
File diff suppressed because it is too large
Load Diff
1388
examples/NmraValidation/Loco Cap 2.1/arlc_5n.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_5n.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_5n.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_5n.sum
Executable file
File diff suppressed because it is too large
Load Diff
1388
examples/NmraValidation/Loco Cap 2.1/arlc_5r.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_5r.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_5r.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_5r.sum
Executable file
File diff suppressed because it is too large
Load Diff
1388
examples/NmraValidation/Loco Cap 2.1/arlc_6n.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_6n.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_6n.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_6n.sum
Executable file
File diff suppressed because it is too large
Load Diff
1388
examples/NmraValidation/Loco Cap 2.1/arlc_6r.log
Executable file
1388
examples/NmraValidation/Loco Cap 2.1/arlc_6r.log
Executable file
File diff suppressed because it is too large
Load Diff
1383
examples/NmraValidation/Loco Cap 2.1/arlc_6r.sum
Executable file
1383
examples/NmraValidation/Loco Cap 2.1/arlc_6r.sum
Executable file
File diff suppressed because it is too large
Load Diff
486
examples/NmraValidation/Loco_Test/Loco_Test.ino
Executable file
486
examples/NmraValidation/Loco_Test/Loco_Test.ino
Executable file
@@ -0,0 +1,486 @@
|
||||
/***********************************************************************************************
|
||||
*
|
||||
* This sketch tests the NmraDcc library as a multifunction decoder.
|
||||
* Author: Kenneth West
|
||||
* kgw4449@gmail.com
|
||||
*
|
||||
* This sketch has added the printf() function to the Print class.
|
||||
* You can find instructions for doing this here:
|
||||
* http://playground.arduino.cc/Main/Printf
|
||||
*
|
||||
* This sketch is based on NmraDcc library NmraDccMultiFunctionDecoder_1 example.
|
||||
* You can find the library here:
|
||||
* https://github.com/mrrwa/NmraDcc
|
||||
*
|
||||
* This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
|
||||
* You can find out more about this DCC Interface here:
|
||||
* http://www.iascaled.com/store/ARD-DCCSHIELD
|
||||
*
|
||||
* For more information refer to the file: README.md here:
|
||||
* https://github.com/IowaScaledEngineering/ard-dccshield
|
||||
*
|
||||
* This demo assumes the following Jumper settings on the ARD-DCCSHIELD
|
||||
*
|
||||
* JP1 - I2C Pull-Up Resistors - Don't Care
|
||||
* JP2 - (Pins 1-2) I2C /IORST JP2 - Don't-Care
|
||||
* JP2 - (Pins 3-4) - DCC Signal to Arduino Pin - OFF
|
||||
* JP3 - I2C /INT and /OE - Don't-Care
|
||||
* JP4 - DCC Signal to Arduino Pin - D2 ON
|
||||
* JP5 - Arduino Powered from DCC - User Choice
|
||||
* JP6 - Boards without VIO - User Choice
|
||||
* JP7 - Enable Programming ACK - 1-2 ON 3-4 ON
|
||||
*
|
||||
* The connections are as follows:
|
||||
*
|
||||
* Pin Name Mode Description
|
||||
* ----------------------------------------------------------------------------------
|
||||
* D2 DCC_PIN INPUT_PULLUP DCC input signal.
|
||||
* A1 ACK_PIN OUTPUT CV acknowledge control.
|
||||
* A0 MOTOR_A_PIN OUTPUT Motor output A.
|
||||
* D13 MOTOR_B_PIN OUTPUT Motor output B.
|
||||
* D12 FUNC_A_PIN OUTPUT Function output A.
|
||||
* D11 FUNC_B_PIN OUTPUT Function output B.
|
||||
* D4 SCOPE_PIN OUTPUT SCOPE trigger.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
// Column locations.
|
||||
//3456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
|
||||
// 1 2 3 4 5 6 7 8 9 9
|
||||
//const unsigned long FAKE_LONG = 10000UL; // Fake variable for column positions.
|
||||
|
||||
#include <NmraDcc.h>
|
||||
|
||||
// Uncomment this line to print out minimal status information.
|
||||
#define DCC_STATUS
|
||||
|
||||
// Uncomment this line to issue scope trigger at beginning of motor callback.
|
||||
#define DO_SCOPE
|
||||
|
||||
const byte VER_MAJOR = 2; // Major version in CV 7
|
||||
const byte VER_MINOR = 1; // Minor version in CV 112
|
||||
const byte DCC_PIN = 2; // DCC input pin.
|
||||
const int ACK_PIN = A1; // CV acknowledge pin.
|
||||
const byte MOTOR_A_PIN = A0; // Motor out A pin.
|
||||
const byte MOTOR_B_PIN = 13; // Motor out B pin.
|
||||
const byte FUNC_A_PIN = 12; // Function A pin.
|
||||
const byte FUNC_B_PIN = 11; // Function B pin.
|
||||
const byte SCOPE_PIN = 4; // Scope trigger pin.
|
||||
const byte CV_VERSION = 7; // Decoder version.
|
||||
const byte CV_MANUF = 8; // Manufacturer ID.
|
||||
const byte CV_MANUF_01 = 112; // Manufacturer Unique 01.
|
||||
const byte MANUF_ID = MAN_ID_DIY; // Manufacturer ID in CV 8.
|
||||
const byte DECODER_ADDR = 3; // Decoder address.
|
||||
const byte SP_ESTOP = 0; // Emergency stop speed.
|
||||
const byte SP_STOP = 1; // Stop speed value.
|
||||
const unsigned long DELAY_TIME = 50; // Delay time in ms.
|
||||
|
||||
// Note: Set FORCE_CV_WRITE true to force CVs to update if just the address is changed.
|
||||
const bool FORCE_CV_WRITE = false; // Set true to force CV write.
|
||||
|
||||
enum ShowTypes {
|
||||
S_IDLE = 0x01, // Show Idle packets.
|
||||
S_RESET = 0x02, // Show Reset packets.
|
||||
S_DCC = 0x04, // Show DCC information.
|
||||
S_ACK = 0x08, // Basic acknowledge off.
|
||||
S_ALL = 0x80, // Show raw packet data.
|
||||
};
|
||||
|
||||
bool MotorFwd = false; // Motor direction.
|
||||
bool FuncOn = true; // Function on/off.
|
||||
byte ShowData = 0x00; // Packet information to show.
|
||||
unsigned long EndTime = 0; // End time in ms.
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
// The CV Below defines the Short DCC Address
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DECODER_ADDR}, // Short address.
|
||||
|
||||
// Reload these just in case they are writeen by accident.
|
||||
{CV_VERSION, VER_MAJOR}, // Decoder version.
|
||||
{CV_MANUF, MANUF_ID }, // Manufacturer ID.
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // Extended address MSB.
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, DECODER_ADDR}, // Extended address LSB.
|
||||
|
||||
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
||||
{CV_MANUF_01, VER_MINOR}, // Minor decoder version.
|
||||
};
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
|
||||
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
|
||||
Serial.println(F("notifyCVResetFactoryDefault called."));
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// Uncomment the #define below to print all Speed Packets
|
||||
#define NOTIFY_DCC_SPEED
|
||||
#ifdef NOTIFY_DCC_SPEED
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
|
||||
{
|
||||
#ifdef DO_SCOPE
|
||||
digitalWrite(SCOPE_PIN, HIGH);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
if (ShowData & S_DCC) {
|
||||
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" );
|
||||
}
|
||||
|
||||
if ((Speed > SP_STOP) && (Dir == DCC_DIR_REV)) {
|
||||
setMotor(false);
|
||||
}
|
||||
else {
|
||||
setMotor(true);
|
||||
}
|
||||
};
|
||||
#endif // NOTIFY_DCC_SPEED
|
||||
|
||||
// Uncomment the #define below to print all Function Packets
|
||||
#define NOTIFY_DCC_FUNC
|
||||
#ifdef NOTIFY_DCC_FUNC
|
||||
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
|
||||
{
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print("notifyDccFunc: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
|
||||
Serial.print(" Function Group: ");
|
||||
Serial.print(FuncGrp,DEC);
|
||||
}
|
||||
|
||||
switch( FuncGrp ) {
|
||||
#ifdef NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
case FN_0:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN0: ");
|
||||
Serial.println((FuncState & FN_BIT_00) ? "1 " : "0 ");
|
||||
}
|
||||
break;
|
||||
#endif // NMRA_DCC_ENABLE_14_SPEED_STEP_MODE
|
||||
|
||||
case FN_0_4:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN 0: ");
|
||||
Serial.print((FuncState & FN_BIT_00) ? "1 ": "0 ");
|
||||
Serial.print(" FN 1-4: ");
|
||||
Serial.print((FuncState & FN_BIT_01) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_02) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_03) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_04) ? "1 ": "0 ");
|
||||
}
|
||||
|
||||
if (FuncState & FN_BIT_00) {
|
||||
setFunc(true);
|
||||
}
|
||||
else {
|
||||
setFunc(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case FN_5_8:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN 5-8: ");
|
||||
Serial.print((FuncState & FN_BIT_05) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_06) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_07) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_08) ? "1 ": "0 ");
|
||||
}
|
||||
break;
|
||||
|
||||
case FN_9_12:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN 9-12: ");
|
||||
Serial.print((FuncState & FN_BIT_09) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_10) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_11) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_12) ? "1 ": "0 ");
|
||||
}
|
||||
break;
|
||||
|
||||
case FN_13_20:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN 13-20: ");
|
||||
Serial.print((FuncState & FN_BIT_13) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_14) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_15) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_16) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_17) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_18) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_19) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_20) ? "1 ": "0 ");
|
||||
}
|
||||
break;
|
||||
|
||||
case FN_21_28:
|
||||
if (ShowData & S_DCC) {
|
||||
Serial.print(" FN 21-28: ");
|
||||
Serial.print((FuncState & FN_BIT_21) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_22) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_23) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_24) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_25) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_26) ? "1 ": "0 ");
|
||||
Serial.print((FuncState & FN_BIT_27) ? "1 ": "0 ");
|
||||
Serial.println((FuncState & FN_BIT_28) ? "1 ": "0 ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_FUNC
|
||||
|
||||
// Uncomment the #define below to print all Reset Packets.
|
||||
#define NOTIFY_DCC_RESET
|
||||
#ifdef NOTIFY_DCC_RESET
|
||||
void notifyDccReset(uint8_t hardReset) {
|
||||
setMotor(true);
|
||||
setFunc(false);
|
||||
if (ShowData & S_RESET) {
|
||||
Serial.printf(F("notifyDccReset: %6s.\n"), hardReset ? "HARD" : "NORMAL");
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_RESET
|
||||
|
||||
// This function is called whenever a DCC Idle packet is received.
|
||||
// Uncomment to print Idle Packets
|
||||
#define NOTIFY_DCC_IDLE
|
||||
#ifdef NOTIFY_DCC_IDLE
|
||||
void notifyDccIdle()
|
||||
{
|
||||
if (ShowData & S_IDLE) { // Show Idle packets if S_IDLE is set.
|
||||
Serial.println("notifyDccIdle: Idle received") ;
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_IDLE
|
||||
|
||||
// Uncomment the #define below to print changed CV values.
|
||||
#define NOTIFY_CV_CHANGE
|
||||
#ifdef NOTIFY_CV_CHANGE
|
||||
void notifyCVChange( uint16_t CV, uint8_t Value) {
|
||||
Serial.printf(F("notifyCVChange: CV %4u value changed to %3u 0x%02X.\n"), CV, Value, Value);
|
||||
}
|
||||
#endif // NOTIFY_CV_CHANGE
|
||||
|
||||
// This function is called when any DCC packet is received.
|
||||
// Uncomment to print all DCC Packets
|
||||
#define NOTIFY_DCC_MSG
|
||||
#ifdef NOTIFY_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
if (ShowData & S_ALL) { // Show all packets if S_ALL is set.
|
||||
Serial.print("notifyDccMsg: ") ;
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
#endif // NOTIFY_DCC_MSG
|
||||
|
||||
// This function is called by the NmraDcc library when a DCC ACK needs to be sent.
|
||||
// Calling this function should cause an increased 60ma current drain on
|
||||
// the power supply for 6ms to ACK a CV Read
|
||||
void notifyCVAck(void)
|
||||
{
|
||||
#ifdef DO_SCOPE
|
||||
digitalWrite(SCOPE_PIN, HIGH);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
if ((ShowData & S_ACK) == 0x00) { // Send CV acknowledge current pulse. [
|
||||
Serial.println("notifyCVAck: Current pulse sent") ;
|
||||
|
||||
digitalWrite( ACK_PIN, HIGH );
|
||||
delay( 6 );
|
||||
digitalWrite( ACK_PIN, LOW );
|
||||
}
|
||||
else { // Suppress CV acknowledge current pulse.
|
||||
Serial.println("notifyCVAck: Current pulse NOT sent") ;
|
||||
}
|
||||
}
|
||||
|
||||
void setMotor(bool fwd) {
|
||||
#ifdef DCC_STATUS
|
||||
if (MotorFwd != fwd) {
|
||||
Serial.printf(F("Motor changed to %3s.\n"), fwd ? "FWD" : "REV");
|
||||
}
|
||||
#endif // DCC_STATUS
|
||||
MotorFwd = fwd;
|
||||
digitalWrite(MOTOR_A_PIN, fwd);
|
||||
digitalWrite(MOTOR_B_PIN, !fwd);
|
||||
}
|
||||
|
||||
void setFunc(bool on) {
|
||||
#ifdef DCC_STATUS
|
||||
if (FuncOn != on) {
|
||||
Serial.printf(F("Function changed to %3s.\n"), on ? "ON" : "OFF");
|
||||
}
|
||||
#endif // DCC_STATUS
|
||||
FuncOn = on;
|
||||
digitalWrite(FUNC_A_PIN, !on);
|
||||
digitalWrite(FUNC_B_PIN, on);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print(F("NMRA Dcc Loco_Test "));
|
||||
Serial.printf(F(" Version %d.%d, Build date %s %s\n"), VER_MAJOR,
|
||||
VER_MINOR,
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
Serial.println(F("Cmds: a - All, d - DCC, i - Idle, r - Reset, c - CV Ack off,"));
|
||||
Serial.println(F(" <Other> - Everything off."));
|
||||
|
||||
// Set MotorFwd false and FuncOn true to force the set the output.
|
||||
MotorFwd = false;
|
||||
FuncOn = true;
|
||||
|
||||
// Configure motor and fuction output pin pairs.
|
||||
pinMode( MOTOR_A_PIN, OUTPUT);
|
||||
pinMode( MOTOR_B_PIN, OUTPUT);
|
||||
setMotor(true);
|
||||
pinMode( FUNC_A_PIN, OUTPUT);
|
||||
pinMode( FUNC_B_PIN, OUTPUT);
|
||||
setFunc(false);
|
||||
|
||||
// Configure Scope trigger output.
|
||||
#ifdef DO_SCOPE
|
||||
pinMode( SCOPE_PIN, OUTPUT);
|
||||
digitalWrite(SCOPE_PIN, LOW);
|
||||
#endif // DO_SCOPE
|
||||
|
||||
// Configure the DCC CV Programing ACK and set it LOW to keep the ACK current off.
|
||||
pinMode( ACK_PIN, OUTPUT );
|
||||
digitalWrite(ACK_PIN, LOW );
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using
|
||||
// and enable the Pull-Up.
|
||||
Dcc.pin(digitalPinToInterrupt(DCC_PIN), DCC_PIN, 1);
|
||||
|
||||
// Reset the CVs to factory default if the manuf. ID or major version do not match.
|
||||
// Do this before init() since it sets these CVs.
|
||||
if ( ( FORCE_CV_WRITE) ||
|
||||
((Dcc.getCV(CV_29_CONFIG) & CV29_ACCESSORY_DECODER) != 0) ||
|
||||
( Dcc.getCV(CV_MANUFACTURER_ID) != MANUF_ID) ||
|
||||
( Dcc.getCV(CV_VERSION_ID) != VER_MAJOR) ||
|
||||
( Dcc.getCV(CV_MANUF_01) != VER_MINOR))
|
||||
{
|
||||
notifyCVResetFactoryDefault();
|
||||
}
|
||||
|
||||
Dcc.init( MANUF_ID, VER_MAJOR, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
|
||||
// Make sure CV_MANUF_01 CV matches VER_MINOR.
|
||||
Dcc.setCV(CV_MANUF_01, VER_MINOR);
|
||||
|
||||
Serial.println(F("Init Done"));
|
||||
|
||||
// Flush serial prior to entering loop().
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
|
||||
if (Serial.available()) {
|
||||
// Get the new byte and process it.
|
||||
switch ((char)Serial.read()) {
|
||||
case 'a':
|
||||
if (ShowData & S_ALL) {
|
||||
ShowData &= ~S_ALL;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_ALL;
|
||||
}
|
||||
Serial.println(ShowData & S_ALL ? "All ON" : "All OFF");
|
||||
break;
|
||||
case 'd':
|
||||
if (ShowData & S_DCC) {
|
||||
ShowData &= ~S_DCC;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_DCC;
|
||||
}
|
||||
Serial.println(ShowData & S_DCC ? "DCC ON" : "DCC OFF");
|
||||
break;
|
||||
case 'i':
|
||||
if (ShowData & S_IDLE) {
|
||||
ShowData &= ~S_IDLE;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_IDLE;
|
||||
}
|
||||
Serial.println(ShowData & S_IDLE ? "Idle ON" : "Idle OFF");
|
||||
break;
|
||||
case 'r':
|
||||
if (ShowData & S_RESET) {
|
||||
ShowData &= ~S_RESET;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_RESET;
|
||||
}
|
||||
Serial.println(ShowData & S_RESET ? "Reset ON" : "Reset OFF");
|
||||
break;
|
||||
case 'c':
|
||||
if (ShowData & S_ACK) {
|
||||
ShowData &= ~S_ACK;
|
||||
}
|
||||
else {
|
||||
ShowData |= S_ACK;
|
||||
}
|
||||
Serial.println(ShowData & S_ACK ? "Ack OFF" : "Ack ON");
|
||||
break;
|
||||
case '\n':
|
||||
case '\r':
|
||||
break;
|
||||
default:
|
||||
if (ShowData != 0x00) {
|
||||
EndTime = millis() + DELAY_TIME;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((EndTime != 0) && (millis() > EndTime)) {
|
||||
Serial.printf(F("Clearing ShowData 0x%02x\n"), ShowData);
|
||||
ShowData = 0x00;
|
||||
EndTime = 0;
|
||||
}
|
||||
|
||||
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
|
||||
{
|
||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
||||
Serial.printf(F("CV %4u reset to factory default %3u 0x%02X.\n"),
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].CV,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV,
|
||||
FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
87
examples/SMA/AccDec_10Servos_7LED_6Ftn/AccDec_10Servos_7LED_6Ftn.ino
Executable file → Normal file
87
examples/SMA/AccDec_10Servos_7LED_6Ftn/AccDec_10Servos_7LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,10 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_10Servos_7LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -16,10 +21,10 @@
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,6 +54,7 @@ int t; // temp
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
@@ -61,7 +67,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -70,15 +76,25 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position F0=0
|
||||
{33, 140}, //F0 End Position F0=1
|
||||
{34, 28}, //F0 Current Position
|
||||
@@ -112,21 +128,21 @@ CVPair FactoryDefaultCVs [] =
|
||||
{62, 28}, // Start Position Fx=0
|
||||
{63, 140}, // End Position Fx=1
|
||||
{64, 28}, // Current Position
|
||||
{65, 2}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{65, 1}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{67, 28}, // Start Position Fx=0
|
||||
{68,140}, // End Position Fx=1
|
||||
{69, 28}, // Current Position
|
||||
{70, 2}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{67, 1}, // Start Position Fx=0
|
||||
{68,35}, // End Position Fx=1
|
||||
{69, 1}, // Current Position
|
||||
{70, 1}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{72, 28}, // Start Position Fx=0
|
||||
{73, 140}, // End Position Fx=1
|
||||
{74, 28}, // Current Position
|
||||
{75, 2}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{72, 1}, // Start Position Fx=0
|
||||
{73, 100}, // End Position Fx=1
|
||||
{74, 1}, // Current Position
|
||||
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{77, 28}, // Start Position Fx=0
|
||||
{78, 140}, // End Position Fx=1
|
||||
{79, 28}, // Current Position
|
||||
{77, 1}, // Start Position Fx=0
|
||||
{78, 10}, // End Position Fx=1
|
||||
{79, 1}, // Current Position
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{82, 1}, // Start Position Fx=0
|
||||
@@ -135,22 +151,22 @@ CVPair FactoryDefaultCVs [] =
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 20}, // End Position Fx=1
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 35}, // End Position Fx=1
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -203,7 +219,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -299,7 +315,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -370,22 +386,17 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
void exec_function (int function, int FuncState) {
|
||||
|
71
examples/SMA/AccDec_13Servos_4LED_6Ftn/AccDec_13Servos_4LED_6Ftn.ino
Executable file → Normal file
71
examples/SMA/AccDec_13Servos_4LED_6Ftn/AccDec_13Servos_4LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,11 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_13Servos_4LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +18,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,6 +54,7 @@ int t; // temp
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
@@ -61,7 +67,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -70,13 +76,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position F0=0
|
||||
@@ -142,22 +159,22 @@ CVPair FactoryDefaultCVs [] =
|
||||
{92, 28}, // Start Position Fx=0
|
||||
{93, 140}, // End Position Fx=1
|
||||
{94, 28}, // Current Position
|
||||
{95, 1}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 20}, // End Position Fx=1
|
||||
{99, 1}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 20}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
{113, 4}, // End Position Fx=1
|
||||
@@ -203,7 +220,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -299,7 +316,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -370,24 +387,20 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
|
||||
void exec_function (int function, int FuncState) {
|
||||
byte pin;
|
||||
int servo_temp;
|
||||
|
72
examples/SMA/AccDec_15Servos_2LED_6Ftn/AccDec_15Servos_2LED_6Ftn.ino
Executable file → Normal file
72
examples/SMA/AccDec_15Servos_2LED_6Ftn/AccDec_15Servos_2LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,10 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_15Servos_2LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +17,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,6 +53,7 @@ int t; // temp
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
@@ -61,7 +66,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -70,13 +75,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position F0=0
|
||||
@@ -203,7 +219,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -277,7 +293,13 @@ void setup() //******************************************************
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
|
||||
}
|
||||
break;
|
||||
case 6: // NEXT FEATURE to pin
|
||||
break;
|
||||
@@ -293,7 +315,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -353,13 +375,7 @@ void loop() //****************************************************************
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
|
||||
}
|
||||
|
||||
break;
|
||||
case 6: // NEXT FEATURE to pin
|
||||
break;
|
||||
@@ -370,24 +386,20 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
|
||||
void exec_function (int function, int FuncState) {
|
||||
byte pin;
|
||||
int servo_temp;
|
||||
|
47
examples/SMA/AccDec_17LED_1Ftn/AccDec_17LED_1Ftn.ino
Executable file → Normal file
47
examples/SMA/AccDec_17LED_1Ftn/AccDec_17LED_1Ftn.ino
Executable file → Normal file
@@ -1,5 +1,9 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_17LED_1Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
|
||||
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
|
||||
@@ -9,7 +13,7 @@
|
||||
|
||||
int tim_delay = 500;
|
||||
#define numleds 17
|
||||
byte ledpins [] = {0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
|
||||
const int FunctionPin0 = 3;
|
||||
const int FunctionPin1 = 4;
|
||||
@@ -31,9 +35,14 @@ const int FunctionPin16 = 19; //A5
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
|
||||
#define This_Decoder_Address 40 //ACCESSORY DECODER ADDRESS
|
||||
//Start of SWITCHES RANGE
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
@@ -41,11 +50,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
@@ -86,16 +108,15 @@ void setup()
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 0);
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
}
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint8_t Bit_State = OutputAddr & 0x01;
|
||||
if ( Addr >= This_Decoder_Address && Addr < This_Decoder_Address+17) //Controls This_Decoder_Address+16
|
||||
digitalWrite( ledpins[Addr-This_Decoder_Address], Bit_State );
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
if ( Addr >= Accessory_Address && Addr < Accessory_Address+17) //Controls This_Decoder_Address+16
|
||||
digitalWrite( ledpins[Addr-Accessory_Address], Direction );
|
||||
}
|
||||
|
||||
|
81
examples/SMA/AccDec_17LED_6Ftn/AccDec_17LED_6Ftn.ino
Executable file → Normal file
81
examples/SMA/AccDec_17LED_6Ftn/AccDec_17LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,10 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_17LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +17,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,6 +53,7 @@ int t; // temp
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
@@ -61,7 +66,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -70,13 +75,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position F0=0
|
||||
@@ -127,36 +143,36 @@ CVPair FactoryDefaultCVs [] =
|
||||
{77, 1}, // Start Position Fx=0
|
||||
{78, 10}, // End Position Fx=1
|
||||
{79, 1}, // Current Position
|
||||
{80, 5}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{82, 1}, // Start Position Fx=0
|
||||
{83, 5}, // End Position Fx=1
|
||||
{84, 1}, // Current Position
|
||||
{85, 4}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 20}, // End Position Fx=1
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 35}, // End Position Fx=1
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 20}, // Current Position
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
@@ -177,6 +193,9 @@ void notifyCVResetFactoryDefault()
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
||||
// OUTPUT PINS FOR FUNCTIONS
|
||||
|
||||
void setup() //******************************************************
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -203,7 +222,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -299,7 +318,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -370,24 +389,20 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
|
||||
void exec_function (int function, int FuncState) {
|
||||
byte pin;
|
||||
int servo_temp;
|
||||
|
60
examples/SMA/AccDec_7ServoBackandForth6Ftn/AccDec_7ServoBackandForth6Ftn.ino
Executable file → Normal file
60
examples/SMA/AccDec_7ServoBackandForth6Ftn/AccDec_7ServoBackandForth6Ftn.ino
Executable file → Normal file
@@ -1,13 +1,19 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_7ServoBackandForth6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
|
||||
// This Decoder Version has been modified so that each Switch Closure Transition from Thrown to Closed
|
||||
// Swings the Servo Quickly from Start to Stop and Back to Start
|
||||
// This is ONLY done in the transition from Thrown to Closed Servo Speed can be slowed by changing the
|
||||
// RATE CV towards 1
|
||||
//
|
||||
|
||||
// ******** 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
|
||||
@@ -19,10 +25,10 @@
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -64,7 +70,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -73,13 +79,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position
|
||||
@@ -180,6 +197,9 @@ void notifyCVResetFactoryDefault()
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
||||
// OUTPUT PINS FOR FUNCTIONS
|
||||
|
||||
void setup() //******************************************************
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -206,7 +226,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -302,7 +322,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -352,24 +372,20 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
|
||||
void exec_function (int function, int FuncState) {
|
||||
byte pin;
|
||||
int servo_temp;
|
||||
|
100
examples/SMA/AccDec_7Servos_10LED_6Ftn/AccDec_7Servos_10LED_6Ftn.ino
Executable file → Normal file
100
examples/SMA/AccDec_7Servos_10LED_6Ftn/AccDec_7Servos_10LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,10 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Switch Acessory DCC Decoder AccDec_7Servos_10LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses for CV Control Default 24 (LSB CV 121 ; MSB CV 122)
|
||||
// ACCESSORY DECODER DEFAULT ADDRESS IS 40 (MAX 40-56 SWITCHES)
|
||||
// ACCESSRY DECODER ADDRESS CAN NOW BE SET ABOVE 255
|
||||
// BE CAREFUL! DIFFERENT DCC BASE STATIONS ALLOW DIFFERING MAX ADDRESSES
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +17,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,6 +53,7 @@ int t; // temp
|
||||
#define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
|
||||
#define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
|
||||
// WHICH WILL EXTEND FOR 16 MORE SWITCH ADDRESSES
|
||||
// THIS CAN START ABOVE ADDRESS 256
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120; // THIS IS THE CV ADDRESS OF THE FULL RESET
|
||||
#define CV_To_Store_SET_CV_Address 121
|
||||
#define CV_Accessory_Address CV_ACCESSORY_DECODER_ADDRESS_LSB
|
||||
@@ -61,7 +66,7 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -70,13 +75,24 @@ struct CVPair
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
// These two CVs define the Long Accessory Address
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address&0xFF},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, (Accessory_Address>>8)&0x07},
|
||||
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// Speed Steps don't matter for this decoder
|
||||
// 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_29_CONFIG,CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_F0_LOCATION}, // Accesory Decoder Short Address
|
||||
// {CV_29_CONFIG, CV29_ACCESSORY_DECODER|CV29_OUTPUT_ADDRESS_MODE|CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Accesory Decoder Long Address
|
||||
|
||||
{CV_DECODER_MASTER_RESET, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address},
|
||||
{CV_To_Store_SET_CV_Address+1, 0},
|
||||
{CV_To_Store_SET_CV_Address, SET_CV_Address&0xFF }, // LSB Set CV Address
|
||||
{CV_To_Store_SET_CV_Address+1,(SET_CV_Address>>8)&0x3F }, //MSB Set CV Address
|
||||
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 28}, //F0 Start Position F0=0
|
||||
@@ -129,41 +145,41 @@ CVPair FactoryDefaultCVs [] =
|
||||
{79, 28}, // Current Position
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{82, 28}, // Start Position Fx=0
|
||||
{83, 140}, // End Position Fx=1
|
||||
{84, 28}, // Current Position
|
||||
{85, 0}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{82, 1}, // Start Position Fx=0
|
||||
{83, 5}, // End Position Fx=1
|
||||
{84, 1}, // Current Position
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 28}, // Start Position Fx=0
|
||||
{88, 140}, // End Position Fx=1
|
||||
{89, 28}, // Current Position
|
||||
{90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 28}, // Start Position Fx=0
|
||||
{93, 140}, // End Position Fx=1
|
||||
{94, 28}, // Current Position
|
||||
{95, 1}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 20}, // End Position Fx=1
|
||||
{99, 1}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 20}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
{113, 4}, // End Position Fx=1
|
||||
{114, 1}, // Current Position
|
||||
//FUTURE USE
|
||||
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=PWM
|
||||
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{117, 28}, // Start Position Fx=0
|
||||
{118, 50}, // End Position Fx=1
|
||||
@@ -177,6 +193,9 @@ void notifyCVResetFactoryDefault()
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
||||
// OUTPUT PINS FOR FUNCTIONS
|
||||
|
||||
void setup() //******************************************************
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -203,7 +222,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -299,7 +318,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -370,24 +389,21 @@ void loop() //****************************************************************
|
||||
}
|
||||
}
|
||||
|
||||
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) {
|
||||
uint16_t Current_Decoder_Addr;
|
||||
uint8_t Bit_State;
|
||||
Current_Decoder_Addr = Dcc.getAddr();
|
||||
Bit_State = OutputAddr & 0x01;
|
||||
// This function is called whenever a normal DCC Turnout Packet is received and we're in Output Addressing Mode
|
||||
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
|
||||
uint16_t Current_Decoder_Addr = Dcc.getAddr();
|
||||
|
||||
if ( Addr >= Current_Decoder_Addr && Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
|
||||
#ifdef DEBUG
|
||||
Serial.print("Addr = ");
|
||||
Serial.println(Addr);
|
||||
Serial.print("BoardAddr = ");
|
||||
Serial.println(BoardAddr);
|
||||
Serial.print("Bit_State = ");
|
||||
Serial.println(Bit_State);
|
||||
Serial.print("Direction = ");
|
||||
Serial.println(Direction);
|
||||
#endif
|
||||
exec_function(Addr-Current_Decoder_Addr, Bit_State );
|
||||
exec_function(Addr-Current_Decoder_Addr, Direction );
|
||||
}
|
||||
}
|
||||
|
||||
void exec_function (int function, int FuncState) {
|
||||
byte pin;
|
||||
int servo_temp;
|
||||
|
55
examples/SMA/Dec_10Serv_7LED_6Ftn/Dec_10Serv_7LED_6Ftn.ino
Executable file → Normal file
55
examples/SMA/Dec_10Serv_7LED_6Ftn/Dec_10Serv_7LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,6 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -16,10 +17,10 @@
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,7 +50,6 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -58,19 +58,29 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -130,22 +140,22 @@ CVPair FactoryDefaultCVs [] =
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 20}, // End Position Fx=1
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 35}, // End Position Fx=1
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -173,6 +183,8 @@ void notifyCVResetFactoryDefault()
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
||||
// OUTPUT PINS FOR FUNCTIONS
|
||||
void setup() //******************************************************
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -199,7 +211,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -295,7 +307,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -367,6 +379,17 @@ void loop() //****************************************************************
|
||||
}
|
||||
|
||||
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
|
||||
#ifdef DEBUG
|
||||
Serial.print(" addr: ");
|
||||
Serial.print(Addr, DEC) ;
|
||||
Serial.print(" at: ");
|
||||
Serial.print(AddrType, DEC) ;
|
||||
Serial.print(" fg : ");
|
||||
Serial.print(FuncGrp, DEC) ;
|
||||
Serial.print(" fs: ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
|
||||
switch(FuncGrp)
|
||||
{
|
||||
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
|
||||
@@ -480,4 +503,4 @@ void exec_function (int function, int pin, int FuncState) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
examples/SMA/Dec_13Serv_4LED_6Ftn/Dec_13Serv_4LED_6Ftn.ino
Executable file → Normal file
42
examples/SMA/Dec_13Serv_4LED_6Ftn/Dec_13Serv_4LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_13Serv_4LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +12,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,7 +48,6 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -65,12 +63,22 @@ struct CVPair
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -137,21 +145,21 @@ CVPair FactoryDefaultCVs [] =
|
||||
{92, 28}, // Start Position Fx=0
|
||||
{93, 140}, // End Position Fx=1
|
||||
{94, 28}, // Current Position
|
||||
{95, 1}, //F13 CConfig 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 20}, // End Position Fx=1
|
||||
{99, 1}, // Current Position
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 20}, // Current Position
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
@@ -199,7 +207,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -295,7 +303,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
|
38
examples/SMA/Dec_15Serv_2LED_6Ftn/Dec_15Serv_2LED_6Ftn.ino
Executable file → Normal file
38
examples/SMA/Dec_15Serv_2LED_6Ftn/Dec_15Serv_2LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_15Serv_2LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -12,14 +12,13 @@
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,7 +48,6 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -65,12 +63,22 @@ struct CVPair
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -147,15 +155,15 @@ CVPair FactoryDefaultCVs [] =
|
||||
{102, 28}, // Start Position Fx=0
|
||||
{103, 140}, // End Position Fx=1
|
||||
{104, 28}, // Current Position
|
||||
{105, 1}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 10}, // End Position Fx=1
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
{113, 10}, // End Position Fx=1
|
||||
{113, 4}, // End Position Fx=1
|
||||
{114, 1}, // Current Position
|
||||
//FUTURE USE
|
||||
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
@@ -199,7 +207,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -295,7 +303,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
|
34
examples/SMA/Dec_17LED_1Ftn/Dec_17LED_1Ftn.ino
Executable file → Normal file
34
examples/SMA/Dec_17LED_1Ftn/Dec_17LED_1Ftn.ino
Executable file → Normal file
@@ -1,5 +1,6 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_17LED_1Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
|
||||
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
|
||||
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
|
||||
@@ -9,7 +10,7 @@
|
||||
|
||||
int tim_delay = 500;
|
||||
#define numleds 17
|
||||
byte ledpins [] = {0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
|
||||
const int FunctionPin0 = 3;
|
||||
const int FunctionPin1 = 4;
|
||||
@@ -26,15 +27,13 @@ const int FunctionPin9 = 12;
|
||||
const int FunctionPin10 = 13;
|
||||
const int FunctionPin11 = 14; //A0
|
||||
const int FunctionPin12 = 15; //A1
|
||||
|
||||
const int FunctionPin13 = 16; //A2
|
||||
const int FunctionPin14 = 17; //A3
|
||||
const int FunctionPin15 = 18; //A4
|
||||
const int FunctionPin16 = 19; //A5
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
|
||||
struct CVPair
|
||||
{
|
||||
@@ -42,14 +41,25 @@ struct CVPair
|
||||
uint8_t Value;
|
||||
};
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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},
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 4;
|
||||
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
void notifyCVResetFactoryDefault()
|
||||
{
|
||||
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
||||
@@ -77,7 +87,7 @@ void setup()
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 0);
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
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 )
|
||||
|
89
examples/SMA/Dec_17LED_6Ftn/Dec_17LED_6Ftn.ino
Executable file → Normal file
89
examples/SMA/Dec_17LED_6Ftn/Dec_17LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,6 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_17LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -10,15 +11,14 @@
|
||||
|
||||
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
#define DEBUG
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -48,7 +48,7 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -64,18 +64,27 @@ struct CVPair
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
|
||||
// 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, 5}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 0}, //F0 Start Position F0=0
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 0}, //F0 Start Position F0=0
|
||||
{33, 8}, //F0 End Position F0=1
|
||||
{34, 1}, //F0 Current Position
|
||||
{34, 1}, //F0 Current Position
|
||||
{35, 5}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{37, 0}, // Start Position Fx=0
|
||||
@@ -121,40 +130,40 @@ CVPair FactoryDefaultCVs [] =
|
||||
{77, 28}, // Start Position Fx=0
|
||||
{78, 140}, // End Position Fx=1
|
||||
{79, 28}, // Current Position
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{82, 1}, // Start Position Fx=0
|
||||
{83, 5}, // End Position Fx=1
|
||||
{84, 1}, // Current Position
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 10}, // End Position Fx=1
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 6}, // End Position Fx=1
|
||||
{99, 1}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 6}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 10}, // End Position Fx=1
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
{113, 10}, // End Position Fx=1
|
||||
{113, 4}, // End Position Fx=1
|
||||
{114, 1}, // Current Position
|
||||
//FUTURE USE
|
||||
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
@@ -164,7 +173,7 @@ CVPair FactoryDefaultCVs [] =
|
||||
{119, 28}, // Current Position
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 95;
|
||||
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
void notifyCVResetFactoryDefault()
|
||||
{
|
||||
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
||||
@@ -172,14 +181,17 @@ void notifyCVResetFactoryDefault()
|
||||
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
|
||||
int i;
|
||||
uint8_t cv_value;
|
||||
Serial.begin(115200);
|
||||
// initialize the digital pins as outputs
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
pinMode(fpins[i], OUTPUT);
|
||||
@@ -199,12 +211,12 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
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
|
||||
#endif
|
||||
|
||||
{
|
||||
for (int j=0; j < FactoryDefaultCVIndex; j++ )
|
||||
@@ -213,8 +225,9 @@ void setup() //******************************************************
|
||||
delay (1000);
|
||||
digitalWrite(fpins[14], 0);
|
||||
}
|
||||
|
||||
for ( i=0; i < numfpins; i++) {
|
||||
cv_value = Dcc.getCV( 30+(i*5)) ;
|
||||
cv_value = Dcc.getCV( 30+(i*5)) ;
|
||||
#ifdef DEBUG
|
||||
Serial.print(" cv_value: ");
|
||||
Serial.println(cv_value, DEC) ;
|
||||
@@ -295,7 +308,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -367,6 +380,12 @@ void loop() //****************************************************************
|
||||
}
|
||||
|
||||
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
|
||||
@@ -403,7 +422,7 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
|
||||
}
|
||||
}
|
||||
void exec_function (int function, int pin, int FuncState) {
|
||||
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
case 0: // On - Off LED
|
||||
digitalWrite (pin, FuncState);
|
||||
ftn_queue[function].inuse = 0;
|
||||
@@ -480,4 +499,4 @@ void exec_function (int function, int pin, int FuncState) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,23 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 2 Motor 13 Function DCC Decoder Dec_2MotDrive_12LED_1Srv_6Ftn.ino
|
||||
// Version 6.01a Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// Better motor control added
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
|
||||
/*
|
||||
* Motor selection is via motor select Function 13 (Motor1) and Function 14 (Motor2)
|
||||
* Motor speed for each can only be changed if the corresponding Function is on
|
||||
* (F13 and/or F14). Motor speed is maintained if the corresponding Motor select function
|
||||
* is off. Thus, each motor can be controlled independently and run at different speeds.
|
||||
* F0-F12 control LEDs on Pro Mini Digital Pins 5,6,7,8,11,12,13,14,15,16,17,18,19
|
||||
* Simple speed control is made via throttle speed setting for two motors. Motor selection
|
||||
* is via motor select Function 13 (Motor1) and Function 14 (Motor2). Motor speed for each
|
||||
* can only be changed if the corresponding Function is on (F13 and/or F14). Motor speed is
|
||||
* maintained if the corresponding motor select function is off. Thus, each motor can be
|
||||
* controlled independently and run at different speeds. The other functions are configurable
|
||||
* but are preset for LED on/off control.
|
||||
*/
|
||||
// ******** 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
|
||||
@@ -15,18 +29,16 @@
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[12];
|
||||
SoftwareServo servo[13];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
uint8_t Motor1Speed = 0;
|
||||
int Motor1Speed = 0;
|
||||
uint8_t Motor1ForwardDir = 1;
|
||||
uint8_t Motor1MaxSpeed = 127;
|
||||
uint8_t Motor2Speed = 0;
|
||||
int Motor2Speed = 0;
|
||||
uint8_t Motor2ForwardDir = 1;
|
||||
uint8_t Motor2MaxSpeed = 127;
|
||||
int kickstarton = 1400; //kick start cycle on time
|
||||
int kickstarttime = 5; //kick start duration on time
|
||||
int fwdon = 0;
|
||||
@@ -35,6 +47,7 @@ int bwdon = 0;
|
||||
int bwdtime = 1;
|
||||
int bwdshift = 0;
|
||||
int cyclewidth = 2047;
|
||||
int loopdelay =14;
|
||||
int m2h = 3; //R H Bridge //Motor1
|
||||
int m2l = 4; //B H Bridge //Motor1
|
||||
int m0h = 9; //R H Bridge //Motor2
|
||||
@@ -42,7 +55,7 @@ int m0l = 10; //B H Bridge //Motor2
|
||||
|
||||
int speedup = 112; //Right track time differntial
|
||||
int deltime = 1500;
|
||||
int tim_delay = 100;
|
||||
int tim_delay = 30;
|
||||
int numfpins = 17;
|
||||
int num_active_fpins = 13;
|
||||
byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
@@ -69,7 +82,6 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -78,20 +90,29 @@ struct QUEUE
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
QUEUE *ftn_queue = new QUEUE[17];
|
||||
|
||||
extern uint8_t Decoder_Address = This_Decoder_Address;
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -186,7 +207,7 @@ CVPair FactoryDefaultCVs [] =
|
||||
{119, 28}, // Current Position
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 95;
|
||||
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
void notifyCVResetFactoryDefault()
|
||||
{
|
||||
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
||||
@@ -194,6 +215,9 @@ void notifyCVResetFactoryDefault()
|
||||
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
};
|
||||
|
||||
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
|
||||
// OUTPUT PINS FOR FUNCTIONS
|
||||
|
||||
void setup() //******************************************************
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -206,23 +230,21 @@ void setup() //******************************************************
|
||||
pinMode(fpins[i], OUTPUT);
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
for (int i=8; i < numfpins; i++) {
|
||||
digitalWrite(fpins[i], 1);
|
||||
delay (tim_delay/10);
|
||||
delay (tim_delay);
|
||||
}
|
||||
delay( tim_delay);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
for (int i=8; i < numfpins; i++) {
|
||||
digitalWrite(fpins[i], 0);
|
||||
delay (tim_delay/10);
|
||||
delay (tim_delay);
|
||||
}
|
||||
delay( tim_delay);
|
||||
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
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
|
||||
@@ -309,7 +331,6 @@ void setup() //******************************************************
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() //**********************************************************************
|
||||
{
|
||||
//MUST call the NmraDcc.process() method frequently
|
||||
@@ -317,14 +338,28 @@ void loop() //****************************************************************
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(2);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Motor1Speed= ");
|
||||
Serial.println(Motor1Speed, DEC) ;
|
||||
Serial.print("Motor2Speed= ");
|
||||
Serial.println(Motor2Speed, DEC) ;
|
||||
#endif
|
||||
if (Motor1Speed != 0) {
|
||||
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, int((Motor1Speed&0x7f)*21));
|
||||
else gobwd1 (bwdtime, int((Motor1Speed&0x7f)*21));
|
||||
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, Motor1Speed<<4);
|
||||
else gobwd1 (bwdtime, Motor1Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m2h, LOW); //Motor1 OFF
|
||||
digitalWrite(m2l, LOW); //Motor1 OFF
|
||||
}
|
||||
if (Motor2Speed != 0) {
|
||||
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, int((Motor2Speed&0x7f)*21));
|
||||
else gobwd2 (bwdtime, int((Motor2Speed&0x7f)*21));
|
||||
}
|
||||
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, Motor2Speed<<4);
|
||||
else gobwd2 (bwdtime, Motor2Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m0h, LOW); //Motor1 OFF
|
||||
digitalWrite(m0l, LOW); //Motor1 OFF
|
||||
}
|
||||
//
|
||||
for (int i=0; i < num_active_fpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
@@ -397,65 +432,76 @@ void loop() //****************************************************************
|
||||
}
|
||||
void gofwd1(int fcnt,int fcycle) {
|
||||
int icnt;
|
||||
int totcycle;
|
||||
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(fcycle);
|
||||
delayMicroseconds(delta_tp);
|
||||
digitalWrite(m2h, LOW); //Motor1
|
||||
delayMicroseconds(cyclewidth - fcycle);
|
||||
delayMicroseconds(delta_tm);
|
||||
icnt++;
|
||||
}
|
||||
}
|
||||
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(bcycle);
|
||||
delayMicroseconds(delta_tp);
|
||||
digitalWrite(m2l, LOW); //Motor1
|
||||
delayMicroseconds(cyclewidth - bcycle);
|
||||
delayMicroseconds(delta_tm);
|
||||
icnt++;
|
||||
}
|
||||
}
|
||||
void gofwd2(int fcnt,int fcycle) {
|
||||
int icnt;
|
||||
int totcycle;
|
||||
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(fcycle);
|
||||
delayMicroseconds(delta_tp);
|
||||
digitalWrite(m0h, LOW); //Motor2
|
||||
delayMicroseconds(cyclewidth - fcycle);
|
||||
delayMicroseconds(delta_tm);
|
||||
icnt++;
|
||||
}
|
||||
}
|
||||
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(bcycle);
|
||||
delayMicroseconds(delta_tp);
|
||||
digitalWrite(m0l, LOW); //Motor2
|
||||
delayMicroseconds(cyclewidth - bcycle);
|
||||
delayMicroseconds(delta_tm);
|
||||
icnt++;
|
||||
}
|
||||
}
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
|
||||
if (Function13_value==1) {
|
||||
Motor1Speed = Speed;
|
||||
Motor1Speed = (Speed & 0x7f );
|
||||
if (Motor1Speed == 1) Motor1Speed=0;
|
||||
Motor1ForwardDir = ForwardDir;
|
||||
}
|
||||
if (Function14_value==1) {
|
||||
Motor2Speed = Speed;
|
||||
Motor2Speed = (Speed & 0x7f );
|
||||
if (Motor2Speed == 1) Motor2Speed=0;
|
||||
Motor2ForwardDir = ForwardDir;
|
||||
}
|
||||
}
|
||||
|
||||
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
|
||||
switch(FuncGrp)
|
||||
{
|
||||
@@ -570,4 +616,4 @@ void exec_function (int function, int pin, int FuncState) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
726
examples/SMA/Dec_2Mot_3LED_TrigAud/Dec_2Mot_3LED_TrigAud.ino
Normal file
726
examples/SMA/Dec_2Mot_3LED_TrigAud/Dec_2Mot_3LED_TrigAud.ino
Normal file
@@ -0,0 +1,726 @@
|
||||
// Production 2 Motor w/Triggered Audio Multi Function DCC Decoder Dec_2Mot_3LED_TrigAudio.ino
|
||||
// Version 6.01a Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// Improved motor control added
|
||||
// This decoder will control 2 motors and play audio clips by function:
|
||||
// F0=LED on pin 8, F1-F4 Controls playing specific audio tracks in the 3rd CV (start) at the volume in the 2nd CV (rate)
|
||||
// F5 Controls playing audio track in CV57 at the volume in CV56 ONLY when F5 is ON and Pin17/A3 is held low,
|
||||
// and plays continuously until F5 turns off or Pin17 trigger goes HIGH or open
|
||||
// F6 plays one track selected randomly off the memory card
|
||||
// F13 and F14 select each separate motor which will respond to speed and direction controls
|
||||
// F7-F8 control LEDs by default PINS 18 and 19
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
|
||||
// * MAX 9 Configurations per pin function:
|
||||
// * 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
/*
|
||||
* Motor selection is via motor select Function 13 (Motor1) and Function 14 (Motor2)
|
||||
* Motor speed for each can only be changed if the corresponding Function is on
|
||||
* (F13 and/or F14). Motor speed is maintained if the corresponding Motor select function
|
||||
* is off. Thus, each motor can be controlled independently and run at different speeds.
|
||||
* F0 LED Pin 13
|
||||
* F1-F6 6 Functions Configures As Audio Play
|
||||
* F7-F8 2 Functions Configures As LEDs by default PINS 18 and 19
|
||||
* F13 Motor1 Control Enable
|
||||
* F14 Motor2 Control Enable
|
||||
* Pro Mini Transmit-7 (TX) connected to DFPlayer Receive (RX)Pin 2 via 470 Ohm Resistor
|
||||
* Pro Mini Receive (RX) connected to DFPlayer Transmit (TX) Pin 3
|
||||
* Remember to connect +5V and GND to the DFPlayer too: DFPLAYER PINS 1 & 7,10 respectively
|
||||
* This is a “mobile/function” decoder that adds 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. F0 is configured
|
||||
* as an on/off LED function, F1-F5 play audio tracks 1-5 respectively.
|
||||
* F6 plays a random selection in random order from tracks 1-6.
|
||||
* F7-F9 control LEDs on Pro Mini Digital Pins 11-13.
|
||||
* Simple speed control is made via throttle speed setting for two motors. Motor selection
|
||||
* is via motor select Function 13 (Motor1) and Function 14 (Motor2). Motor speed for each
|
||||
* can only be changed if the corresponding Function is on (F13 and/or F14). Motor speed is
|
||||
* maintained if the corresponding motor select function is off. Thus, each motor can be
|
||||
* controlled independently and run at different speeds. The other functions are configurable
|
||||
* but are preset for LED on/off control.
|
||||
*/
|
||||
// ******** 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 <SoftwareServo.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#include <DFPlayer_Mini_Mp3.h>
|
||||
SoftwareSerial mySerial(6,7); // PRO MINI RX, PRO MINI TX serial to DFPlayer
|
||||
|
||||
int busy_pin = 5; // DFPlayer Busy status pin
|
||||
#define num_clips 6 //number of sound tracks/clips on the Micro SD Memory Card
|
||||
int del_tim = 4000;
|
||||
int tctr, tctr2, i;
|
||||
byte audio_on = 0; // Audio ON sets this to 1; otherwise 0
|
||||
|
||||
SoftwareServo servo[10];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 4 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int Motor1Speed = 0;
|
||||
uint8_t Motor1ForwardDir = 1;
|
||||
int Motor2Speed = 0;
|
||||
uint8_t Motor2ForwardDir = 1;
|
||||
int kickstarton = 1400; //kick start cycle on time
|
||||
int kickstarttime = 5; //kick start duration on time
|
||||
int fwdon = 0;
|
||||
int fwdtime = 1;
|
||||
int bwdon = 0;
|
||||
int bwdtime = 1;
|
||||
int bwdshift = 0;
|
||||
int cyclewidth = 2047;
|
||||
int loopdelay =14;
|
||||
int m2h = 3; //R H Bridge //Motor1
|
||||
int m2l = 4; //B H Bridge //Motor1
|
||||
int m0h = 9; //R H Bridge //Motor2
|
||||
int m0l = 10; //B H Bridge //Motor2
|
||||
|
||||
int speedup = 112; //Right track time differntial
|
||||
int deltime = 1500;
|
||||
int tim_delay = 30;
|
||||
int numfpins = 13;
|
||||
int num_active_fpins = 9;
|
||||
byte fpins [] = {3,4,8,9,10,11,12,13,14,15,16,18};
|
||||
const int FunctionPin0 = 13;
|
||||
const int FunctionPin1 = 20; // Place holders ONLY
|
||||
const int FunctionPin2 = 20; // Place holders ONLY
|
||||
const int FunctionPin3 = 20; // Place holders ONLY
|
||||
const int FunctionPin4 = 20; //A0 Place holders ONLY
|
||||
|
||||
const int FunctionPin5 = 20; //A1 Place holders ONLY
|
||||
const int FunctionPin6 = 20; //A2 Place holders ONLY
|
||||
const int FunctionPin7 = 18; //A5 Place holders ONLY
|
||||
const int FunctionPin8 = 19; //A4 Place holders ONLY
|
||||
|
||||
const int AudioTriggerPin = 17; //A3 NOW USED AS Audio Trigger Pin INPUT_PULLUP
|
||||
|
||||
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 Function13_value = 0;
|
||||
int Function14_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[17];
|
||||
|
||||
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=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{32, 0}, //F0 Start Position F0=0,Audio=Audio Track/Clip#
|
||||
{33, 8}, //F0 End Position F0=1
|
||||
{34, 1}, //F0 Current Position
|
||||
{35, 6}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{36, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{37, 1}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{38, 8}, // End Position Fx=1
|
||||
{39, 1}, // Current Position
|
||||
{40, 6}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{41, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{42, 2}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{43, 140}, // End Position Fx=1
|
||||
{44, 0}, // Current Position
|
||||
{45, 6}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{46, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{47, 3}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{48, 140}, // End Position Fx=1
|
||||
{49, 0}, // Current Position
|
||||
{50, 6}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{51, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{52, 4}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{53, 140}, // End Position Fx=1
|
||||
{54, 0}, // Current Position
|
||||
{55, 8}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{56, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{57, 6}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{58, 140}, // End Position Fx=1
|
||||
{59, 0}, // Current Position
|
||||
{60, 7}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{61, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{62, 6}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{63, 140}, // End Position Fx=1
|
||||
{64, 28}, // Current Position
|
||||
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{67, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{68,140}, // End Position Fx=1
|
||||
{69, 28}, // Current Position
|
||||
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{72, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{73, 140}, // End Position Fx=1
|
||||
{74, 28}, // Current Position
|
||||
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio,7=Random Audio,8=Triggered Audio
|
||||
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{77, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{78, 140}, // End Position Fx=1
|
||||
{79, 28}, // Current Position
|
||||
};
|
||||
|
||||
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 (busy_pin, INPUT); // MUST NOT Pull Up == 3.3V device output pin
|
||||
pinMode (AudioTriggerPin, INPUT_PULLUP);
|
||||
|
||||
mySerial.begin (9600);
|
||||
mp3_set_serial (mySerial); //set softwareSerial for DFPlayer-mini mp3 module
|
||||
mp3_reset ();
|
||||
delay(100);
|
||||
mp3_set_volume (18);
|
||||
delay(50);
|
||||
audio_on = 0;
|
||||
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);
|
||||
}
|
||||
// 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[14], 1);
|
||||
delay (1000);
|
||||
digitalWrite(fpins[14], 0);
|
||||
}
|
||||
for ( i=0; i < num_active_fpins; i++) {
|
||||
cv_value = Dcc.getCV( 30+(i*5)) ;
|
||||
#ifdef DEBUG
|
||||
Serial.print(" cv_value: ");
|
||||
Serial.println(cv_value, DEC) ;
|
||||
#endif
|
||||
switch ( cv_value ) {
|
||||
case 0: // LED on/off
|
||||
ftn_queue[i].inuse = 0;
|
||||
break;
|
||||
case 1: // LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
|
||||
}
|
||||
break;
|
||||
case 2: //servo
|
||||
{
|
||||
ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5)));
|
||||
ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5)));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
|
||||
// attaches servo on pin to the servo object
|
||||
servo[i].attach(fpins[i]);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("InitServo ID= ");
|
||||
Serial.println(i, DEC) ;
|
||||
#endif
|
||||
servo[i].write(ftn_queue[i].start_value);
|
||||
for (t=0; t<servo_start_delay; t++)
|
||||
{SoftwareServo::refresh();delay(servo_init_delay);}
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
break;
|
||||
case 3: // DOUBLE ALTERNATING LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
|
||||
digitalWrite(fpins[i], 0);
|
||||
digitalWrite(fpins[i+1], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
|
||||
}
|
||||
break;
|
||||
case 6: // Audio Track Play
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
break;
|
||||
case 7: // Audio Random Track Play
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
break;
|
||||
case 8: // Triggered Audio Track Play
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
break;
|
||||
case 9: // NEXT FEATURE to pin
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() //**********************************************************************
|
||||
{
|
||||
//MUST call the NmraDcc.process() method frequently
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(2);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Motor1Speed= ");
|
||||
Serial.println(Motor1Speed, DEC) ;
|
||||
Serial.print("Motor2Speed= ");
|
||||
Serial.println(Motor2Speed, DEC) ;
|
||||
#endif
|
||||
if (Motor1Speed != 0) {
|
||||
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, Motor1Speed<<4);
|
||||
else gobwd1 (bwdtime, Motor1Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m2h, LOW); //Motor1 OFF
|
||||
digitalWrite(m2l, LOW); //Motor1 OFF
|
||||
}
|
||||
if (Motor2Speed != 0) {
|
||||
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, Motor2Speed<<4);
|
||||
else gobwd2 (bwdtime, Motor2Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m0h, LOW); //Motor1 OFF
|
||||
digitalWrite(m0l, LOW); //Motor1 OFF
|
||||
}
|
||||
//
|
||||
for (int i=0; i < num_active_fpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
switch (Dcc.getCV( 30+(i*5))) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
if (servo_slow_counter++ > servo_slowdown)
|
||||
{
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].increment > 0) {
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].current_position = ftn_queue[i].stop_value;
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
}
|
||||
if (ftn_queue[i].increment < 0) {
|
||||
if (ftn_queue[i].current_position < ftn_queue[i].start_value) {
|
||||
ftn_queue[i].current_position = ftn_queue[i].start_value;
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
}
|
||||
servo[i].write(ftn_queue[i].current_position);
|
||||
servo_slow_counter = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
|
||||
break;
|
||||
case 6: // Audio Track Play
|
||||
if (digitalRead(busy_pin)== HIGH) {
|
||||
ftn_queue[i].inuse = 0;
|
||||
}
|
||||
break;
|
||||
case 7: // Audio Random Track/Clip Play
|
||||
if (digitalRead(busy_pin)== HIGH) {
|
||||
ftn_queue[i].inuse = 0;
|
||||
/* Insert the following code if you want continuous random play as long as F6 is selected
|
||||
if (ftn_queue[i].inuse ==1) { // Audio Off continue playing clips
|
||||
mp3_play (random(1,num_clips)); // play random clip
|
||||
delay(5);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case 8: // Triggered Audio Track Play
|
||||
if (ftn_queue[i].inuse ==1) { // Function is set ON
|
||||
if ((digitalRead(AudioTriggerPin)== LOW)&&(digitalRead(busy_pin)== HIGH)) { // Trigger ON Audio Off
|
||||
mp3_set_volume (ftn_queue[i].increment);
|
||||
delay(8);
|
||||
mp3_play (ftn_queue[i].start_value); // play clip function
|
||||
delay(5);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 9: // NEXT FEATURE for the Future
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
|
||||
if (Function13_value==1) {
|
||||
Motor1Speed = (Speed & 0x7f );
|
||||
if (Motor1Speed == 1) Motor1Speed=0;
|
||||
Motor1ForwardDir = ForwardDir;
|
||||
}
|
||||
if (Function14_value==1) {
|
||||
Motor2Speed = (Speed & 0x7f );
|
||||
if (Motor2Speed == 1) Motor2Speed=0;
|
||||
Motor2ForwardDir = ForwardDir;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
Function13_value = (FuncState & FN_BIT_13);
|
||||
Function14_value = (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;
|
||||
}
|
||||
}
|
||||
void exec_function (int function, int pin, int FuncState) {
|
||||
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
case 0: // On - Off LED
|
||||
digitalWrite (pin, FuncState);
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 1: // Blinking LED
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(pin, 0);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(pin, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // Servo
|
||||
if (ftn_queue[function].inuse == 0) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
servo[function].attach(pin);
|
||||
}
|
||||
if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
|
||||
else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5)));
|
||||
if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
|
||||
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
|
||||
break;
|
||||
case 3: // Blinking LED PAIR
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 1);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if (FuncState==0) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // Pulse Output based on Rate*10 Milliseconds
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { //First Turn On Detected
|
||||
digitalWrite(fpins[function], 1);
|
||||
delay (10*ftn_queue[function].increment);
|
||||
digitalWrite(fpins[function], 0);
|
||||
ftn_queue[function].inuse = 1; //inuse set to 1 says we already pulsed
|
||||
} else
|
||||
if (FuncState==0) ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 5: // Fade On
|
||||
#define fadedelay 24
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
for (t=0; t<ftn_queue[function].stop_value; t+=ftn_queue[function].increment) {
|
||||
digitalWrite( fpins[function], 1);
|
||||
delay(fadedelay*(t/(1.*ftn_queue[function].stop_value)));
|
||||
digitalWrite( fpins[function], 0);
|
||||
delay(fadedelay-(fadedelay*(t/(1.*ftn_queue[function].stop_value))));
|
||||
}
|
||||
digitalWrite( fpins[function], 1 );
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // Audio Play
|
||||
#ifdef DEBUG
|
||||
Serial.print("function= ");
|
||||
Serial.println(function, DEC) ;
|
||||
Serial.print("FuncState= ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
if ((digitalRead(busy_pin)==HIGH)&&(FuncState!=0)) { // Audio Off = Not Playing
|
||||
ftn_queue[function].inuse = 1;
|
||||
mp3_set_volume (ftn_queue[function].increment);
|
||||
delay(8);
|
||||
mp3_play (ftn_queue[function].start_value); // play clip function
|
||||
delay(5);
|
||||
}
|
||||
if ((digitalRead(busy_pin)==LOW)&&(FuncState==0)) { // Audio On = Playing
|
||||
ftn_queue[function].inuse = 0; // Fuunction turned off so get ready to stop
|
||||
}
|
||||
break;
|
||||
case 7: // Random Audio Function
|
||||
#ifdef DEBUG
|
||||
Serial.print("function= ");
|
||||
Serial.println(function, DEC) ;
|
||||
Serial.print("FuncState= ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
if ((digitalRead(busy_pin)==HIGH)&&(FuncState!=0)) { // Audio Off = Not Playing
|
||||
ftn_queue[function].inuse = 1;
|
||||
mp3_set_volume (ftn_queue[function].increment);
|
||||
delay(8);
|
||||
mp3_play (random(1,num_clips+1)); // play random clip
|
||||
delay(5);
|
||||
}
|
||||
if ((digitalRead(busy_pin)==LOW)&&(FuncState==0)) { // Audio On = Playing
|
||||
ftn_queue[function].inuse = 0; // Fuunction turned off so get ready to stop
|
||||
}
|
||||
break;
|
||||
case 8: // Triggered Audio Function
|
||||
ftn_queue[function].inuse = FuncState;
|
||||
break;
|
||||
case 9: // NEXT FEATURE for the Future
|
||||
break;
|
||||
default:
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
mp3_play (); //start play
|
||||
mp3_play (5); //play "mp3/0005.mp3"
|
||||
mp3_next (); //play next
|
||||
mp3_prev (); //play previous
|
||||
mp3_set_volume (uint16_t volume); //0~30
|
||||
mp3_set_EQ (); //0~5
|
||||
mp3_pause ();
|
||||
mp3_stop ();
|
||||
void mp3_get_state (); //send get state command
|
||||
void mp3_get_volume ();
|
||||
void mp3_get_u_sum ();
|
||||
void mp3_get_tf_sum ();
|
||||
void mp3_get_flash_sum ();
|
||||
void mp3_get_tf_current ();
|
||||
void mp3_get_u_current ();
|
||||
void mp3_get_flash_current ();
|
||||
void mp3_single_loop (boolean state); //set single loop
|
||||
void mp3_DAC (boolean state);
|
||||
void mp3_random_play ();
|
||||
*/
|
705
examples/SMA/Dec_2Mot_4LED_Aud_8Ftn/Dec_2Mot_4LED_Aud_8Ftn.ino
Normal file
705
examples/SMA/Dec_2Mot_4LED_Aud_8Ftn/Dec_2Mot_4LED_Aud_8Ftn.ino
Normal file
@@ -0,0 +1,705 @@
|
||||
// Production 2 Motor w/Audio 13 Function DCC Decoder Dec_2Mot_10LED_Audio_8Ftn.ino
|
||||
// Version 6.01a Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// Improved motor control added
|
||||
// This decoder will control 2 motors and play audio clips by function:
|
||||
// F0=LED on pin 13, F1-F4 Controls playing specific audio tracks in the 3rd CV (start) at the volume in the 2nd CV (rate)
|
||||
// F5 Controls playing audio track in CV57 at the volume in CV56 ONLY when F5 is ON and Pin17/A3 is held low,
|
||||
// and plays continuously until F5 turns off or Pin17 trigger goes HIGH or open
|
||||
// F6 plays one track selected randomly off the memory card
|
||||
// F13 and F14 select each separate motor which will respond to speed and direction controls
|
||||
// F7-F8 control LEDs by default PINS 18 and 19
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
/*
|
||||
* Motor selection is via motor select Function 13 (Motor1) and Function 14 (Motor2)
|
||||
* Motor speed for each can only be changed if the corresponding Function is on
|
||||
* (F13 and/or F14). Motor speed is maintained if the corresponding Motor select function
|
||||
* is off. Thus, each motor can be controlled independently and run at different speeds.
|
||||
* F0 LED Pin 13
|
||||
* F1-F6 6 Functions Configures As Audio Play
|
||||
* F7-F9 3 Functions Configures As LEDs
|
||||
* F13 Motor1 Control Enable
|
||||
* F14 Motor2 Control Enable
|
||||
* Pro Mini Transmit-7 (TX) connected to DFPlayer Receive (RX)Pin 2 via 470 Ohm Resistor
|
||||
* Pro Mini Receive (RX) connected to DFPlayer Transmit (TX) Pin 3
|
||||
* Remember to connect +5V and GND to the DFPlayer too: DFPLAYER PINS 1 & 7,10 respectively
|
||||
* This is a “mobile/function” decoder that adds 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. F0 is configured
|
||||
* as an on/off LED function, F1-F5 play audio tracks 1-5 respectively.
|
||||
* F6 plays a random selection in random order from tracks 1-6.
|
||||
* F7-F9 control LEDs on Pro Mini Digital Pins 11-13.
|
||||
* Simple speed control is made via throttle speed setting for two motors. Motor selection
|
||||
* is via motor select Function 13 (Motor1) and Function 14 (Motor2). Motor speed for each
|
||||
* can only be changed if the corresponding Function is on (F13 and/or F14). Motor speed is
|
||||
* maintained if the corresponding motor select function is off. Thus, each motor can be
|
||||
* controlled independently and run at different speeds. The other functions are configurable
|
||||
* but are preset for LED on/off control.
|
||||
*/
|
||||
// ******** 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 <SoftwareServo.h>
|
||||
#include <SoftwareSerial.h>
|
||||
#include <DFPlayer_Mini_Mp3.h>
|
||||
SoftwareSerial mySerial(6,7); // PRO MINI RX, PRO MINI TX serial to DFPlayer
|
||||
|
||||
int busy_pin = 5; // DFPlayer Busy status pin
|
||||
#define num_clips 6 //number of sound tracks/clips on the Micro SD Memory Card
|
||||
int del_tim = 4000;
|
||||
int tctr, tctr2, i;
|
||||
byte audio_on = 0; // Audio ON sets this to 1; otherwise 0
|
||||
|
||||
SoftwareServo servo[10];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 4 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int Motor1Speed = 0;
|
||||
uint8_t Motor1ForwardDir = 1;
|
||||
int Motor2Speed = 0;
|
||||
uint8_t Motor2ForwardDir = 1;
|
||||
int kickstarton = 1400; //kick start cycle on time
|
||||
int kickstarttime = 5; //kick start duration on time
|
||||
int fwdon = 0;
|
||||
int fwdtime = 1;
|
||||
int bwdon = 0;
|
||||
int bwdtime = 1;
|
||||
int bwdshift = 0;
|
||||
int cyclewidth = 2047;
|
||||
int loopdelay =14;
|
||||
int m2h = 3; //R H Bridge //Motor1
|
||||
int m2l = 4; //B H Bridge //Motor1
|
||||
int m0h = 9; //R H Bridge //Motor2
|
||||
int m0l = 10; //B H Bridge //Motor2
|
||||
|
||||
int speedup = 112; //Right track time differntial
|
||||
int deltime = 1500;
|
||||
int tim_delay = 30;
|
||||
int numfpins = 14;
|
||||
int num_active_fpins = 10;
|
||||
byte fpins [] = {3,4,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
const int FunctionPin0 = 13;
|
||||
const int FunctionPin1 = 20; // Place holders ONLY
|
||||
const int FunctionPin2 = 20; // Place holders ONLY
|
||||
const int FunctionPin3 = 20; // Place holders ONLY
|
||||
const int FunctionPin4 = 20; //A0 Place holders ONLY
|
||||
|
||||
const int FunctionPin5 = 20; //A1 Place holders ONLY
|
||||
const int FunctionPin6 = 20; //A2 Place holders ONLY
|
||||
const int FunctionPin7 = 18; //A5 Place holders ONLY
|
||||
const int FunctionPin8 = 19; //A4 Place holders ONLY
|
||||
|
||||
const int AudioTriggerPin = 17; //A3 NOW USED AS Audio Trigger Pin INPUT_PULLUP
|
||||
|
||||
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 Function13_value = 0;
|
||||
int Function14_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[17];
|
||||
|
||||
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=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{32, 0}, //F0 Start Position F0=0,Audio=Audio Track/Clip#
|
||||
{33, 8}, //F0 End Position F0=1
|
||||
{34, 1}, //F0 Current Position
|
||||
{35, 6}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{36, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{37, 1}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{38, 8}, // End Position Fx=1
|
||||
{39, 1}, // Current Position
|
||||
{40, 6}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{41, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{42, 2}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{43, 140}, // End Position Fx=1
|
||||
{44, 0}, // Current Position
|
||||
{45, 6}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{46, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{47, 3}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{48, 140}, // End Position Fx=1
|
||||
{49, 0}, // Current Position
|
||||
{50, 6}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{51, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{52, 4}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{53, 140}, // End Position Fx=1
|
||||
{54, 0}, // Current Position
|
||||
{55, 6}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{56, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{57, 5}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{58, 140}, // End Position Fx=1
|
||||
{59, 28}, // Current Position
|
||||
{60, 7}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{61, 22}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{62, 6}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{63, 140}, // End Position Fx=1
|
||||
{64, 28}, // Current Position
|
||||
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{67, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{68,140}, // End Position Fx=1
|
||||
{69, 28}, // Current Position
|
||||
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{72, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{73, 140}, // End Position Fx=1
|
||||
{74, 28}, // Current Position
|
||||
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade,6=Audio
|
||||
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Audio=Volume(0-30)
|
||||
{77, 28}, // Start Position Fx=0,Audio=Audio Track/Clip#
|
||||
{78, 140}, // End Position Fx=1
|
||||
{79, 28}, // Current Position
|
||||
};
|
||||
|
||||
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 (busy_pin, INPUT);
|
||||
mySerial.begin (9600);
|
||||
mp3_set_serial (mySerial); //set softwareSerial for DFPlayer-mini mp3 module
|
||||
mp3_reset ();
|
||||
delay(100);
|
||||
mp3_set_volume (18);
|
||||
delay(50);
|
||||
audio_on = 0;
|
||||
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);
|
||||
}
|
||||
// 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[14], 1);
|
||||
delay (1000);
|
||||
digitalWrite(fpins[14], 0);
|
||||
}
|
||||
for ( i=0; i < num_active_fpins; i++) {
|
||||
cv_value = Dcc.getCV( 30+(i*5)) ;
|
||||
#ifdef DEBUG
|
||||
Serial.print(" cv_value: ");
|
||||
Serial.println(cv_value, DEC) ;
|
||||
#endif
|
||||
switch ( cv_value ) {
|
||||
case 0: // LED on/off
|
||||
ftn_queue[i].inuse = 0;
|
||||
break;
|
||||
case 1: // LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
|
||||
}
|
||||
break;
|
||||
case 2: //servo
|
||||
{
|
||||
ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5)));
|
||||
ftn_queue[i].stop_value = int (Dcc.getCV( 33+(i*5)));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
|
||||
// attaches servo on pin to the servo object
|
||||
servo[i].attach(fpins[i]);
|
||||
|
||||
#ifdef DEBUG
|
||||
Serial.print("InitServo ID= ");
|
||||
Serial.println(i, DEC) ;
|
||||
#endif
|
||||
servo[i].write(ftn_queue[i].start_value);
|
||||
for (t=0; t<servo_start_delay; t++)
|
||||
{SoftwareServo::refresh();delay(servo_init_delay);}
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
break;
|
||||
case 3: // DOUBLE ALTERNATING LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
|
||||
digitalWrite(fpins[i], 0);
|
||||
digitalWrite(fpins[i+1], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
|
||||
}
|
||||
break;
|
||||
case 6: // Audio Track Play
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
audio_on = 0;
|
||||
break;
|
||||
case 7: // Audio Random Track Play
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
|
||||
audio_on = 0;
|
||||
break;
|
||||
case 8: // NEXT FEATURE to pin
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loop() //**********************************************************************
|
||||
{
|
||||
//MUST call the NmraDcc.process() method frequently
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(2);
|
||||
#ifdef DEBUG
|
||||
Serial.print("Motor1Speed= ");
|
||||
Serial.println(Motor1Speed, DEC) ;
|
||||
Serial.print("Motor2Speed= ");
|
||||
Serial.println(Motor2Speed, DEC) ;
|
||||
#endif
|
||||
if (Motor1Speed != 0) {
|
||||
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, Motor1Speed<<4);
|
||||
else gobwd1 (bwdtime, Motor1Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m2h, LOW); //Motor1 OFF
|
||||
digitalWrite(m2l, LOW); //Motor1 OFF
|
||||
}
|
||||
if (Motor2Speed != 0) {
|
||||
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, Motor2Speed<<4);
|
||||
else gobwd2 (bwdtime, Motor2Speed<<4);
|
||||
}
|
||||
else {
|
||||
digitalWrite(m0h, LOW); //Motor1 OFF
|
||||
digitalWrite(m0l, LOW); //Motor1 OFF
|
||||
}
|
||||
//
|
||||
for (int i=0; i < num_active_fpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
switch (Dcc.getCV( 30+(i*5))) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
if (servo_slow_counter++ > servo_slowdown)
|
||||
{
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].increment > 0) {
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].current_position = ftn_queue[i].stop_value;
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
}
|
||||
if (ftn_queue[i].increment < 0) {
|
||||
if (ftn_queue[i].current_position < ftn_queue[i].start_value) {
|
||||
ftn_queue[i].current_position = ftn_queue[i].start_value;
|
||||
ftn_queue[i].inuse = 0;
|
||||
servo[i].detach();
|
||||
}
|
||||
}
|
||||
servo[i].write(ftn_queue[i].current_position);
|
||||
servo_slow_counter = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
|
||||
break;
|
||||
case 6: // Audio Track Play
|
||||
if (digitalRead(busy_pin)== HIGH) {
|
||||
ftn_queue[i].inuse = 0;
|
||||
}
|
||||
break;
|
||||
case 7: // Audio Random Track/Clip Play
|
||||
if (digitalRead(busy_pin)== HIGH) {
|
||||
ftn_queue[i].inuse = 0;
|
||||
/* Insert the following code if you want continuous random play as long as F6 is selected
|
||||
if (ftn_queue[i].inuse ==1) { // Audio Off continue playing clips
|
||||
mp3_play (random(1,num_clips)); // play random clip
|
||||
delay(5);
|
||||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case 8: // NEXT FEATURE to pin
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
}
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
|
||||
if (Function13_value==1) {
|
||||
Motor1Speed = (Speed & 0x7f );
|
||||
if (Motor1Speed == 1) Motor1Speed=0;
|
||||
Motor1ForwardDir = ForwardDir;
|
||||
}
|
||||
if (Function14_value==1) {
|
||||
Motor2Speed = (Speed & 0x7f );
|
||||
if (Motor2Speed == 1) Motor2Speed=0;
|
||||
Motor2ForwardDir = ForwardDir;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
Function13_value = (FuncState & FN_BIT_13);
|
||||
Function14_value = (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;
|
||||
}
|
||||
}
|
||||
void exec_function (int function, int pin, int FuncState) {
|
||||
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
case 0: // On - Off LED
|
||||
digitalWrite (pin, FuncState);
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 1: // Blinking LED
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(pin, 0);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(pin, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // Servo
|
||||
if (ftn_queue[function].inuse == 0) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
servo[function].attach(pin);
|
||||
}
|
||||
if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
|
||||
else ftn_queue[function].increment = - char(Dcc.getCV( 31+(function*5)));
|
||||
if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
|
||||
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
|
||||
break;
|
||||
case 3: // Blinking LED PAIR
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 1);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if (FuncState==0) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // Pulse Output based on Rate*10 Milliseconds
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { //First Turn On Detected
|
||||
digitalWrite(fpins[function], 1);
|
||||
delay (10*ftn_queue[function].increment);
|
||||
digitalWrite(fpins[function], 0);
|
||||
ftn_queue[function].inuse = 1; //inuse set to 1 says we already pulsed
|
||||
} else
|
||||
if (FuncState==0) ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 5: // Fade On
|
||||
#define fadedelay 24
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
for (t=0; t<ftn_queue[function].stop_value; t+=ftn_queue[function].increment) {
|
||||
digitalWrite( fpins[function], 1);
|
||||
delay(fadedelay*(t/(1.*ftn_queue[function].stop_value)));
|
||||
digitalWrite( fpins[function], 0);
|
||||
delay(fadedelay-(fadedelay*(t/(1.*ftn_queue[function].stop_value))));
|
||||
}
|
||||
digitalWrite( fpins[function], 1 );
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // Audio Play
|
||||
#ifdef DEBUG
|
||||
Serial.print("function= ");
|
||||
Serial.println(function, DEC) ;
|
||||
Serial.print("FuncState= ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
if ((digitalRead(busy_pin)==HIGH)&&(FuncState!=0)) { // Audio Off = Not Playing
|
||||
ftn_queue[function].inuse = 1;
|
||||
mp3_set_volume (ftn_queue[function].increment);
|
||||
delay(8);
|
||||
mp3_play (ftn_queue[function].start_value); // play clip function
|
||||
delay(5);
|
||||
}
|
||||
if ((digitalRead(busy_pin)==LOW)&&(FuncState==0)) { // Audio On = Playing
|
||||
ftn_queue[function].inuse = 0; // Fuunction turned off so get ready to stop
|
||||
}
|
||||
break;
|
||||
case 7: // Random Audio Function
|
||||
#ifdef DEBUG
|
||||
Serial.print("function= ");
|
||||
Serial.println(function, DEC) ;
|
||||
Serial.print("FuncState= ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
if ((digitalRead(busy_pin)==HIGH)&&(FuncState!=0)) { // Audio Off = Not Playing
|
||||
ftn_queue[function].inuse = 1;
|
||||
mp3_set_volume (ftn_queue[function].increment);
|
||||
delay(8);
|
||||
mp3_play (random(1,num_clips+1)); // play random clip
|
||||
delay(5);
|
||||
}
|
||||
if ((digitalRead(busy_pin)==LOW)&&(FuncState==0)) { // Audio On = Playing
|
||||
ftn_queue[function].inuse = 0; // Fuunction turned off so get ready to stop
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
mp3_play (); //start play
|
||||
mp3_play (5); //play "mp3/0005.mp3"
|
||||
mp3_next (); //play next
|
||||
mp3_prev (); //play previous
|
||||
mp3_set_volume (uint16_t volume); //0~30
|
||||
mp3_set_EQ (); //0~5
|
||||
mp3_pause ();
|
||||
mp3_stop ();
|
||||
void mp3_get_state (); //send get state command
|
||||
void mp3_get_volume ();
|
||||
void mp3_get_u_sum ();
|
||||
void mp3_get_tf_sum ();
|
||||
void mp3_get_flash_sum ();
|
||||
void mp3_get_tf_current ();
|
||||
void mp3_get_u_current ();
|
||||
void mp3_get_flash_current ();
|
||||
void mp3_single_loop (boolean state); //set single loop
|
||||
void mp3_DAC (boolean state);
|
||||
void mp3_random_play ();
|
||||
*/
|
46
examples/SMA/Dec_7Serv_10LED_6Ftn/Dec_7Serv_10LED_6Ftn.ino
Executable file → Normal file
46
examples/SMA/Dec_7Serv_10LED_6Ftn/Dec_7Serv_10LED_6Ftn.ino
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_7Serv_10LED_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -10,16 +10,15 @@
|
||||
|
||||
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
|
||||
// ******** INFO TO THE SERIAL MONITOR
|
||||
//#define DEBUG
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#include <NmraDcc.h>
|
||||
#include <SoftwareServo.h>
|
||||
|
||||
SoftwareServo servo[16];
|
||||
SoftwareServo servo[17];
|
||||
#define servo_start_delay 50
|
||||
#define servo_init_delay 7
|
||||
#define servo_slowdown 3 //servo loop counter limit
|
||||
#define servo_slowdown 12 //servo loop counter limit
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
|
||||
int tim_delay = 500;
|
||||
@@ -49,7 +48,6 @@ NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
int t; // temp
|
||||
#define This_Decoder_Address 24
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
@@ -65,12 +63,22 @@ struct CVPair
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
@@ -130,28 +138,28 @@ CVPair FactoryDefaultCVs [] =
|
||||
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{88, 50}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 20}, // End Position Fx=1
|
||||
{93, 100}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 35}, // End Position Fx=1
|
||||
{98, 200}, // End Position Fx=1
|
||||
{99, 2}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 4}, // End Position Fx=1
|
||||
{103, 200}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 60}, // End Position Fx=1
|
||||
{109, 20}, // Current Position
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
@@ -199,7 +207,7 @@ void setup() //******************************************************
|
||||
// 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, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
delay(800);
|
||||
|
||||
#if defined(DECODER_LOADED)
|
||||
@@ -295,7 +303,7 @@ void loop() //****************************************************************
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
SoftwareServo::refresh();
|
||||
delay(8);
|
||||
delay(3);
|
||||
for (int i=0; i < numfpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
|
||||
@@ -480,4 +488,4 @@ void exec_function (int function, int pin, int FuncState) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
examples/SMA/Dec_Dir_and_Fade/Dec_Dir_and_Fade.ino
Executable file → Normal file
36
examples/SMA/Dec_Dir_and_Fade/Dec_Dir_and_Fade.ino
Executable file → Normal file
@@ -1,6 +1,8 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// LED control is dependent on direction of travel
|
||||
// Production 17 Function DCC Decoder Dec_Dir_and_Fade.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
// LED control is dependent on direction of travel and Fade can be added
|
||||
|
||||
// ******** 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
|
||||
@@ -11,11 +13,12 @@ int tim_delay = 500;
|
||||
#define numleds 17
|
||||
byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19}; //Defines all possible LED pins
|
||||
|
||||
// IMPORTANT:
|
||||
// The following list defines how each of the 17 function pins operate:
|
||||
// a 0 allows for normal On/Off control with fade on and fade off
|
||||
// a 1 allows for normal control when the decoder sees a forward speed setting, reverse turns the LED off
|
||||
// a 2 allows for normal control when the decoder sees a reverse speed setting, forward turns the LED off
|
||||
byte led_direction [] = {0,1,2,0,1,1,1,1,2,2,2,2,0,0,0,0,0}; //0=On/Off, 1=On Forward, 2=On Reverse
|
||||
byte led_direction [] = {0,1,2,0,1,1,1,1,2,2,2,1,1,1,2,0,0}; //0=On/Off, 1=On Forward, 2=On Reverse
|
||||
|
||||
boolean led_last_state [] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; //last state of led
|
||||
boolean Last_Function_State[] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; //These hold the last Fx assignments
|
||||
@@ -44,19 +47,30 @@ const int FunctionPin15 = 18; //A4
|
||||
const int FunctionPin16 = 19; //A5
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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},
|
||||
};
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
void notifyCVResetFactoryDefault()
|
||||
@@ -96,7 +110,7 @@ void setup()
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 0);
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
@@ -199,4 +213,4 @@ void Switch_LED (int Function) {
|
||||
}
|
||||
led_last_state[Function] = end_state;
|
||||
}
|
||||
|
||||
|
||||
|
53
examples/SMA/Dec_SMA12_LED_Groups/Dec_SMA12_LED_Groups.ino
Executable file → Normal file
53
examples/SMA/Dec_SMA12_LED_Groups/Dec_SMA12_LED_Groups.ino
Executable file → Normal file
@@ -1,5 +1,7 @@
|
||||
// Production 17 Function DCC Decoder
|
||||
// Version 5.1 Geoff Bunza 2014,2015,2016
|
||||
// Production 17 Function DCC Decoder Dec_SMA12_LED_Groups.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
@@ -13,8 +15,8 @@
|
||||
//#define DEBUG
|
||||
|
||||
#include <NmraDcc.h>
|
||||
|
||||
int tim_delay = 500;
|
||||
|
||||
#define numleds 17
|
||||
byte ledpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
byte FPins_Assigned [12][5] = { // This array defines the pins controlled by each function
|
||||
@@ -52,37 +54,49 @@ const int FunctionPin1 = 4;
|
||||
const int FunctionPin2 = 5;
|
||||
const int FunctionPin3 = 6;
|
||||
const int FunctionPin4 = 7;
|
||||
|
||||
const int FunctionPin5 = 8;
|
||||
const int FunctionPin6 = 9;
|
||||
const int FunctionPin7 = 10;
|
||||
const int FunctionPin8 = 11;
|
||||
|
||||
const int FunctionPin9 = 12;
|
||||
const int FunctionPin10 = 13;
|
||||
const int FunctionPin11 = 14; //A0
|
||||
const int FunctionPin12 = 15; //A1
|
||||
|
||||
const int FunctionPin13 = 16; //A2
|
||||
const int FunctionPin14 = 17; //A3
|
||||
const int FunctionPin15 = 18; //A4
|
||||
const int FunctionPin16 = 19; //A5
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
#define This_Decoder_Address 24
|
||||
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
|
||||
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
|
||||
{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},
|
||||
};
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
|
||||
void notifyCVResetFactoryDefault()
|
||||
{
|
||||
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
|
||||
@@ -110,7 +124,11 @@ void setup()
|
||||
delay (tim_delay/10);
|
||||
}
|
||||
delay( tim_delay);
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
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
|
||||
@@ -121,18 +139,12 @@ void setup()
|
||||
delay (1000);
|
||||
digitalWrite(ledpins[14], 0);
|
||||
}
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
Dcc.pin(0, 2, 0);
|
||||
// Call the main DCC Init function to enable the DCC Receiver
|
||||
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 );
|
||||
delay(800);
|
||||
}
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
}
|
||||
|
||||
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
|
||||
int f_index;
|
||||
switch (FuncGrp) {
|
||||
@@ -143,20 +155,17 @@ switch (FuncGrp) {
|
||||
exec_function( 3, (FuncState & FN_BIT_03)>>2 );
|
||||
exec_function( 4, (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, (FuncState & FN_BIT_05));
|
||||
exec_function( 6, (FuncState & FN_BIT_06)>>1 );
|
||||
exec_function( 7, (FuncState & FN_BIT_07)>>2 );
|
||||
exec_function( 8, (FuncState & FN_BIT_08)>>3 );
|
||||
break;
|
||||
|
||||
break;
|
||||
case FN_9_12:
|
||||
exec_function( 9, (FuncState & FN_BIT_09));
|
||||
exec_function( 10,(FuncState & FN_BIT_10)>>1 );
|
||||
exec_function( 11,(FuncState & FN_BIT_11)>>2 );
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
void exec_function (int f_index, int FuncState) {
|
||||
|
508
examples/SMA/Dec_Stepper_6Ftn/Dec_Stepper_6Ftn.ino
Normal file
508
examples/SMA/Dec_Stepper_6Ftn/Dec_Stepper_6Ftn.ino
Normal file
@@ -0,0 +1,508 @@
|
||||
// Production Stepper Drive DCC Decoder Dec_Stepper_6Ftn.ino
|
||||
// Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
|
||||
// Now works with both short and long DCC Addesses
|
||||
|
||||
// NO LONGER REQUIRES modified software servo Lib
|
||||
// Software restructuring mods added from Alex Shepherd and Franz-Peter
|
||||
// With sincere thanks
|
||||
/*
|
||||
* Stepper Motor Drive (4 Pins Bi dirrectional) uses the 2 Motor controls MOT1 and MOT2
|
||||
* F0 LED Pin 5
|
||||
* This is a “mobile/function” decoder that controls a single four wire stepper motor
|
||||
* (5/12 Volt) via throttle speed setting and a multiplier which can be set in CV121.
|
||||
* Stepper speed is pre-set in the sketch but can be changed. The library also supports
|
||||
* setting acceleration/deceleration for the stepper. The other functions are configurable
|
||||
* but are preset for LED on/off control. No servo motor control is available.
|
||||
* Steppers whose coils need less than 500 ma can be accommodated. Each coil of the
|
||||
* stepper attaches to MOT1 and MOT2. You may have to reverse the connections of one
|
||||
* or the other until you get the connections right. The number of steps moved is set
|
||||
* by the speed setting multiplied by the contents of CV 121.
|
||||
* Every Off to On activation of F2 will move the stepper the specified number of steps,
|
||||
* in the direction set by the DCC speed direction.
|
||||
*/
|
||||
// ******** 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 <AccelStepper.h>
|
||||
AccelStepper stepper(AccelStepper::FULL4WIRE, 3, 4, 9, 10);
|
||||
|
||||
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
|
||||
long Motor1Speed = 0;
|
||||
uint8_t Motor1ForwardDir = 1;
|
||||
uint8_t Motor1MaxSpeed = 127;
|
||||
long Motor2Speed = 0;
|
||||
uint8_t Motor2ForwardDir = 1;
|
||||
uint8_t Motor2MaxSpeed = 127;
|
||||
int kickstarton = 1400; //kick start cycle on time
|
||||
int kickstarttime = 5; //kick start duration on time
|
||||
int fwdon = 0;
|
||||
int fwdtime = 1;
|
||||
int bwdon = 0;
|
||||
int bwdtime = 1;
|
||||
int bwdshift = 0;
|
||||
int cyclewidth = 2047;
|
||||
int m2h = 3; //R H Bridge //Motor1
|
||||
int m2l = 4; //B H Bridge //Motor1
|
||||
int m0h = 9; //R H Bridge //Motor2
|
||||
int m0l = 10; //B H Bridge //Motor2
|
||||
|
||||
int speedup = 112; //Right track time differntial
|
||||
int deltime = 1500;
|
||||
int tim_delay = 100;
|
||||
int numfpins = 17;
|
||||
int num_active_fpins = 13;
|
||||
byte fpins [] = {3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
|
||||
const int FunctionPin0 = 5;
|
||||
const int FunctionPin1 = 6;
|
||||
const int FunctionPin2 = 7;
|
||||
const int FunctionPin3 = 8;
|
||||
const int FunctionPin4 = 11;
|
||||
|
||||
const int FunctionPin5 = 12;
|
||||
const int FunctionPin6 = 13;
|
||||
const int FunctionPin7 = 14; //A0
|
||||
const int FunctionPin8 = 15; //A1
|
||||
|
||||
const int FunctionPin9 = 16; //A2
|
||||
const int FunctionPin10 = 17; //A3
|
||||
const int FunctionPin11 = 18; //A4
|
||||
const int FunctionPin12 = 19; //A5
|
||||
|
||||
byte Function2_value = 0;
|
||||
int Function13_value = 0;
|
||||
int Function14_value = 0;
|
||||
|
||||
NmraDcc Dcc ;
|
||||
DCC_MSG Packet ;
|
||||
uint8_t CV_DECODER_MASTER_RESET = 120;
|
||||
uint8_t Motor_Multiplier = 121;
|
||||
int t; // temp
|
||||
|
||||
struct QUEUE
|
||||
{
|
||||
int inuse;
|
||||
int current_position;
|
||||
int increment;
|
||||
int stop_value;
|
||||
int start_value;
|
||||
};
|
||||
QUEUE *ftn_queue = new QUEUE[16];
|
||||
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}, // CV 120
|
||||
{Motor_Multiplier, 10}, // CV 121
|
||||
{30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{32, 0}, //F0 Start Position F0=0
|
||||
{33, 8}, //F0 End Position F0=1
|
||||
{34, 1}, //F0 Current Position
|
||||
{35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{37, 0}, // Start Position Fx=0
|
||||
{38, 8}, // End Position Fx=1
|
||||
{39, 1}, // Current Position
|
||||
{40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{41, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{42, 28}, // Start Position Fx=0
|
||||
{43, 140}, // End Position Fx=1
|
||||
{44, 0}, // Current Position
|
||||
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{46, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{47, 28}, // Start Position Fx=0
|
||||
{48, 140}, // End Position Fx=1
|
||||
{49, 0}, // Current Position
|
||||
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{51, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{52, 28}, // Start Position Fx=0
|
||||
{53, 140}, // End Position Fx=1
|
||||
{54, 0}, // Current Position
|
||||
{55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{57, 28}, // Start Position Fx=0
|
||||
{58, 140}, // End Position Fx=1
|
||||
{59, 28}, // Current Position
|
||||
{60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{62, 1}, // Start Position Fx=0
|
||||
{63, 255}, // End Position Fx=1
|
||||
{64, 28}, // Current Position
|
||||
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{67, 28}, // Start Position Fx=0
|
||||
{68,140}, // End Position Fx=1
|
||||
{69, 28}, // Current Position
|
||||
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{72, 28}, // Start Position Fx=0
|
||||
{73, 140}, // End Position Fx=1
|
||||
{74, 28}, // Current Position
|
||||
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{77, 28}, // Start Position Fx=0
|
||||
{78, 140}, // End Position Fx=1
|
||||
{79, 28}, // Current Position
|
||||
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{82, 1}, // Start Position Fx=0
|
||||
{83, 5}, // End Position Fx=1
|
||||
{84, 1}, // Current Position
|
||||
{85, 0}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{87, 1}, // Start Position Fx=0
|
||||
{88, 5}, // End Position Fx=1
|
||||
{89, 1}, // Current Position
|
||||
{90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{92, 1}, // Start Position Fx=0
|
||||
{93, 10}, // End Position Fx=1
|
||||
{94, 1}, // Current Position
|
||||
{95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{97, 1}, // Start Position Fx=0
|
||||
{98, 6}, // End Position Fx=1
|
||||
{99, 1}, // Current Position
|
||||
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{102, 1}, // Start Position Fx=0
|
||||
{103, 6}, // End Position Fx=1
|
||||
{104, 1}, // Current Position
|
||||
{105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{107, 1}, // Start Position Fx=0
|
||||
{108, 10}, // End Position Fx=1
|
||||
{109, 1}, // Current Position
|
||||
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{112, 1}, // Start Position Fx=0
|
||||
{113, 10}, // End Position Fx=1
|
||||
{114, 1}, // Current Position
|
||||
//FUTURE USE
|
||||
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
{116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
|
||||
{117, 28}, // Start Position Fx=0
|
||||
{118, 50}, // End Position Fx=1
|
||||
{119, 28}, // Current Position
|
||||
};
|
||||
|
||||
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
|
||||
int i;
|
||||
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);
|
||||
}
|
||||
|
||||
// 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[14], 1);
|
||||
delay (1000);
|
||||
digitalWrite(fpins[14], 0);
|
||||
}
|
||||
for ( i=0; i < num_active_fpins; i++) {
|
||||
cv_value = Dcc.getCV( 30+(i*5)) ;
|
||||
#ifdef DEBUG
|
||||
Serial.print(" cv_value: ");
|
||||
Serial.println(cv_value, DEC) ;
|
||||
#endif
|
||||
stepper.setMaxSpeed(100.0);
|
||||
stepper.setAcceleration(50.0);
|
||||
stepper.moveTo(1);
|
||||
switch ( cv_value ) {
|
||||
case 0: // LED on/off
|
||||
ftn_queue[i].inuse = 0;
|
||||
break;
|
||||
case 1: // LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
|
||||
}
|
||||
break;
|
||||
case 2: //servo NOT AVAILABLE WITH THIS DECODER - STEPPER ONLY
|
||||
break;
|
||||
case 3: // DOUBLE ALTERNATING LED Blink
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
|
||||
digitalWrite(fpins[i], 0);
|
||||
digitalWrite(fpins[i+1], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].start_value = 0;
|
||||
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
|
||||
}
|
||||
break;
|
||||
case 6: // NEXT FEATURE to pin
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void loop() //**********************************************************************
|
||||
{
|
||||
//MUST call the NmraDcc.process() method frequently
|
||||
// from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
delay(2);
|
||||
stepper.run();
|
||||
//*************************Normal Function Processing follows
|
||||
for (int i=0; i < num_active_fpins; i++) {
|
||||
if (ftn_queue[i].inuse==1) {
|
||||
switch (Dcc.getCV( 30+(i*5))) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
|
||||
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
|
||||
ftn_queue[i].start_value = ~ftn_queue[i].start_value;
|
||||
digitalWrite(fpins[i], ftn_queue[i].start_value);
|
||||
digitalWrite(fpins[i]+1, ~ftn_queue[i].start_value);
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
|
||||
}
|
||||
i++;
|
||||
break;
|
||||
case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
|
||||
{
|
||||
ftn_queue[i].inuse = 0;
|
||||
ftn_queue[i].current_position = 0;
|
||||
ftn_queue[i].increment = 10 * int (char (Dcc.getCV( 31+(i*5))));
|
||||
digitalWrite(fpins[i], 0);
|
||||
}
|
||||
break;
|
||||
case 5: // Fade On
|
||||
|
||||
break;
|
||||
case 6: // NEXT FEATURE to pin
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
|
||||
//if (Function13_value==1) {
|
||||
Motor1Speed = Speed * Dcc.getCV( Motor_Multiplier);
|
||||
//Motor1ForwardDir = ForwardDir & 1;
|
||||
if (ForwardDir == DCC_DIR_REV) Motor1Speed = -Motor1Speed;;
|
||||
//}
|
||||
}
|
||||
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
|
||||
if (FuncGrp==FN_0_4 && ((FuncState & FN_BIT_02)>>1) == 1) {
|
||||
if (Function2_value == 0) {
|
||||
Function2_value=1;
|
||||
stepper.move(Motor1Speed);
|
||||
return;
|
||||
}
|
||||
} else if (FuncGrp==FN_0_4 && ((FuncState & FN_BIT_02)>>1) == 0) {
|
||||
Function2_value = 0;
|
||||
return;
|
||||
}
|
||||
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
|
||||
// Function13_value = (FuncState & FN_BIT_13);
|
||||
// Function14_value = (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;
|
||||
}
|
||||
}
|
||||
void exec_function (int function, int pin, int FuncState) {
|
||||
#ifdef DEBUG
|
||||
Serial.print(" function: ");
|
||||
Serial.println(function, DEC) ;
|
||||
Serial.print(" pin: ");
|
||||
Serial.println(pin, DEC) ;
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
Serial.print(" Dcc.getCV( 30+(function*5)): ");
|
||||
Serial.println(Dcc.getCV( 30+(function*5)), DEC) ;
|
||||
#endif
|
||||
if (function!=2)
|
||||
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
|
||||
case 0: // On - Off LED
|
||||
digitalWrite (pin, FuncState);
|
||||
#ifdef DEBUG
|
||||
Serial.print(" Dcc.getCV( 30+(function*5)): ");
|
||||
Serial.println(Dcc.getCV( 30+(function*5)), DEC) ;
|
||||
Serial.print(" pin: ");
|
||||
Serial.println(pin, DEC) ;
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.println(FuncState, DEC) ;
|
||||
#endif
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 1: // Blinking LED
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(pin, 0);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(pin, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: // Servo
|
||||
break;
|
||||
case 3: // Blinking LED PAIR
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
ftn_queue[function].start_value = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 1);
|
||||
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
|
||||
} else {
|
||||
if (FuncState==0) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
digitalWrite(fpins[function+1], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4: // Pulse Output based on Rate*10 Milliseconds
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { //First Turn On Detected
|
||||
digitalWrite(fpins[function], 1);
|
||||
delay (10*ftn_queue[function].increment);
|
||||
digitalWrite(fpins[function], 0);
|
||||
ftn_queue[function].inuse = 1; //inuse set to 1 says we already pulsed
|
||||
} else
|
||||
if (FuncState==0) ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
case 5: // Fade On
|
||||
#define fadedelay 24
|
||||
if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
|
||||
ftn_queue[function].inuse = 1;
|
||||
for (t=0; t<ftn_queue[function].stop_value; t+=ftn_queue[function].increment) {
|
||||
digitalWrite( fpins[function], 1);
|
||||
delay(fadedelay*(t/(1.*ftn_queue[function].stop_value)));
|
||||
digitalWrite( fpins[function], 0);
|
||||
delay(fadedelay-(fadedelay*(t/(1.*ftn_queue[function].stop_value))));
|
||||
}
|
||||
digitalWrite( fpins[function], 1 );
|
||||
} else {
|
||||
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
|
||||
ftn_queue[function].inuse = 0;
|
||||
digitalWrite(fpins[function], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: // Future Function
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
default:
|
||||
ftn_queue[function].inuse = 0;
|
||||
break;
|
||||
}
|
||||
}
|
@@ -1,12 +1,13 @@
|
||||
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}}
|
||||
{\*\generator Msftedit 5.41.15.1515;}\viewkind4\uc1\pard\sl276\slmult1\b\f0\fs24 Decoder Configuration Details\par
|
||||
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}}
|
||||
{\*\generator Riched20 10.0.10586}\viewkind4\uc1
|
||||
\pard\sl276\slmult1\b\f0\fs24 Decoder Configuration Details\par
|
||||
\par
|
||||
\b0 The multfunction decoder examples all for 4 functions to be assigned to any of the 17 available pins: on/off control, single line blinking with variable rate, servo control with start position/stop position/transit rate CV setting and end to end control via the function (on/off), and paired line blinking with variable rate.\par
|
||||
\b0 The multfunction decoder examples all for 6 functions to be assigned to any of the 17 available pins: on/off control, single line blinking with variable rate, servo control with start position/stop position/transit rate CV setting and end to end control via the function (on/off), and paired line blinking with variable rate.\par
|
||||
\par
|
||||
When first loaded the decoder is set to short DCC address 24 (or 17 in Decoder_17LED_1Function). The decoder can be reset to the original parameters by loading CV 120 with 120 (decimal). This will reset everything including the decoder address, when the pushbutton on the Pro Mini is pushed (reset) or by powering the decoder off then on. You will know when the default CV setting are being reset as the decoder will flash Digital Pin 14 (A0) for one second.\par
|
||||
The decoder address can be changed to another \ul\b short\ulnone\b0 DCC address by changing CV 1.\par
|
||||
\par
|
||||
\b The 7 Servo 10 LED decoder configuration\par
|
||||
\b Example Only: 7 Servo 10 LED decoder configuration\par
|
||||
\par
|
||||
\b0 Arduino Pro Mini Pins are set as follows: 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19\par
|
||||
\ul\b Pro Mini Pin\ulnone\b0\tab \ul\b Function\par
|
||||
@@ -151,7 +152,8 @@ For example \b F0\b0 is initially set for \b servo\b0 control:\par
|
||||
\par
|
||||
Before changing the CV settings take a look at the initial settings and make small changes first to observe the effects. This should give modelers a starting point, and a better understanding for customizing their decoders.\par
|
||||
\par
|
||||
Please also note there is a new 17 LED (On/Off) decoder configuration (Decoder_17LED_4Function), which while providing the 17 LED on/off control like the very first decoder (Decoder_17LED_1Function) introduced in this project, whichh ONLY has on/off control. However, this new version can be reconfigured via CV control to perform the other functions too.\par
|
||||
Please also note there is a new 17 LED (On/Off) decoder configuration (Dec_17LED_6Ftn), which while providing the 17 LED on/off control like the very first decoder (Dec_17LED_1Ftn) introduced in this project, which ONLY has on/off control. However, this new version can be reconfigured via CV control to perform the other functions too.\par
|
||||
|
||||
\pard\par
|
||||
}
|
||||
|