47 Commits
1.2.1 ... 2.0.0

Author SHA1 Message Date
Geoff Bunza
6dca23bc27 Gbsma601 (#20)
* Delete AccDec_7ServoBackandForth6Ftn.ino

* Delete AccDec_10Servos_7LED_6Ftn.ino

* Delete AccDec_13Servos_4LED_6Ftn.ino

* Delete AccDec_15Servos_2LED_6Ftn.ino

* Delete AccDec_17LED_1Ftn.ino

* Delete AccDec_17LED_6Ftn.ino

* Delete AccDec_7Servos_10LED_6Ftn.ino

* Delete Dec_10Serv_7LED_6Ftn.ino

* Delete Dec_13Serv_4LED_6Ftn.ino

* Delete Dec_15Serv_2LED_6Ftn.ino

* Delete Dec_17LED_1Ftn.ino

* Delete Dec_17LED_6Ftn.ino

* Delete Dec_2Mot_12LED_1Srv_6Ftn.ino

* Delete Dec_2Mot_3LED_TrigAud.ino

* Delete Dec_2Mot_4LED_Aud_8Ftn.ino

* Delete Dec_7Serv_10LED_6Ftn.ino

* Delete Dec_Dir_and_Fade.ino

* Delete Dec_SMA12_LED_Groups.ino

* Delete Dec_Stepper_6Ftn.ino

* Delete SMA 6.0 Release Notes.rtf

* Add files via upload

* Delete Dec_2Mot_12LED_1Srv_6Ftn.ino

* Delete Dec_2Mot_3LED_TrigAud.ino

* Delete Dec_2Mot_4LED_Aud_8Ftn.ino

* Add files via upload

* Delete SMA 6.01 Release Notes.rtf

* Add files via upload
2018-08-08 09:55:33 +12:00
per1234
15da83c411 Use a single tab field separator in keywords.txt (#19)
Each field of keywords.txt is separated by a single true tab. When you use multiple tabs it causes the field to be interpreted as empty. On Arduino IDE 1.6.5 and newer an empty KEYWORD_TOKENTYPE causes the default editor.function.style coloration to be used (as with KEYWORD2, KEYWORD3, LITERAL2). On Arduino IDE 1.6.4 and older it causes the keyword to not be recognized for any special coloration.

Reference:
https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5:-Library-specification#keywords
2018-07-15 23:21:17 +12:00
Alex Shepherd
7a3845cbdf Changed the architectures to now be * as we're no longer tied to AVR specific hardware, however I've listed the architectures its been tested on
Fixed a bug with CV bit-write
2018-07-08 00:54:21 +12:00
Alex Shepherd
1717a2efb0 Made some minor tweaks / tidy-ups after committing Franz-Peter's changes 2018-07-07 19:21:48 +12:00
Franz-Peter
32c5597870 Additional changes regarding output addressing and new callback notifyDccCVChanged() (#17)
* outputaddressing corrected

declared notifyDccAccState for backward compatibility

* version define in NmraDcc.h

* DB_PRINT introduced

Changed debug printing to a macro.
Added cv29 to CV-addresses that reset caching of myAddress

* Corrections regarding Outputaddressing

OutputAddress must be a signed variable

* Changes/additions regarding output addressing and CVChange callback
Change Flag FLAGS_OUTPUT_ADDRESS_MODE accordingly, when CV29 Bit 6 (output addressing) is changed.
New callback 'notifyDccCVChange' which is NOT called if the CV is changed by means of the setCV() method

* Shorten Debug Messages

Because of Buffer overrun in the serial output. This leads to blocking
Serial.write() calls

* notifyDccSigState restored

Restore the old callback notifyDccSigState for compatibiltity to version
1.4.2

* switch off debug printing
2018-07-07 13:26:51 +12:00
Geoff Bunza
2de91bd4fd Merge pull request #18 from mrrwa/GB_SMAV6.0_Update&Test
Gb smav6.0 update&test
2018-07-05 16:38:11 -07:00
Geoff Bunza
5a1e0b2997 Delete SMA 5.4 Release Notes.txt 2018-07-05 16:14:20 -07:00
Geoff Bunza
2b12179152 Delete Dec_2MotDrive_12LED_1Srv_6Ftn.ino 2018-07-05 16:13:14 -07:00
Geoff Bunza
c2de60b8cb Add files via upload 2018-07-05 15:18:48 -07:00
Alex Shepherd
f171dd3894 Added new FLAGS_AUTO_FACTORY_DEFAULT flag to enable checking CV 7 & 8 and if value of both is 255 then call notifyCVResetFactoryDefault() if defined 2018-04-18 23:53:01 +12:00
Franz-Peter
778de8ce74 Changes regarding output addressing (#16)
* outputaddressing corrected

declared notifyDccAccState for backward compatibility

* version define in NmraDcc.h

* DB_PRINT introduced

Changed debug printing to a macro.
Added cv29 to CV-addresses that reset caching of myAddress
2018-04-15 20:20:57 +12:00
M1118
ba3264bd87 Addition of notifyServceMode call to allow decoders to turn off high current outputs (#14)
* Add notification for entering and leaving service mode to allow the
decoder to swithc off high current outputs

* Add notification for entering and leaving service mode to allow the
decoder to swithc off high current outputs
2018-04-15 20:13:12 +12:00
Alex Shepherd
0fbe2a13d1 Changed version to 2.0.0
Added more detail to the README.md
NOT READY FOR PRODUCTION YET, needs more checking and change to provide some backwards compatibility for call-backs that had been removed
2018-03-06 18:48:43 +13:00
Alex Shepherd
369786325f updated the examples to reflect the removal of support for the two call-back functions: notifyDccAccState(), notifyDccSigState() 2018-03-01 00:00:15 +13:00
Alex Shepherd
ec801bf463 updated the examples to reflect the removal of support for the two call-back functions: notifyDccAccState(), notifyDccSigState() 2018-02-28 23:50:59 +13:00
Alex Shepherd
90470987a8 Merge branch 'AddOutputModeAddressing'
AddOutputModeAddressing:
  Fixed off-by-one (x4) error with DCC Accessory Output Mode Addressing. Made compatible with the DCC Spec for DCC Accessory Output Mode Addressing CV storage in CV 1 & 9. Its a bit wierd but...
  Added heaps of DEBUG PRINT to the Accessory Decoder section to follow/test the various test cases through the code and to figure out how to make this stuff work. Added more code to make the existing supported functions to be more selective about which packet bits patterns they take notice of as it was too broad previously Will remove some of the notifyCall-Back functions as some were not well conceived at the time and now need to go Testing is NOT complete as there were issues in JMRI that also need to be resolved in sync with this so we're not quite there yet..
  With eeprom_is_ready() for AVR-processors (#13)
  Fixed some bugs around DCC Accessory Output Mode Addressing and handling of edge cases Add function to set Accessory Decoder Address from next received Accessory Decoder command and new notify call-backs when a new address is set Added new notifyDccSigOutputState() with no OutputIndex parameter Bumped version but have NOT tagged the library as it needs more testing and checking for breakage
Added NmraDcc.h documentation changes and logic changes to correct a couple of issue that arose from Ken West performing a standard NMRA DCC Decoder Confirmance test. Added his test sketches and output reports
2017-12-24 16:53:22 +13:00
Alex Shepherd
9294aa29e5 Merge branch 'ESU_ECoS_CV_Programming'
* ESU_ECoS_CV_Programming:
  Added ESU ECoS CV Programming support
2017-12-24 15:25:17 +13:00
Alex Shepherd
844171f2ac Fixed off-by-one (x4) error with DCC Accessory Output Mode Addressing.
Made compatible with the DCC Spec for DCC Accessory Output Mode Addressing CV storage in CV 1 & 9. Its a bit wierd but...
2017-06-25 20:13:19 +12:00
Alex Shepherd
0656f58c5b Added heaps of DEBUG PRINT to the Accessory Decoder section to follow/test the various test cases through the code and to figure out how to make this stuff work.
Added more code to make the existing supported functions to be more selective about which packet bits patterns they take notice of as it was too broad previously
Will remove some of the notifyCall-Back functions as some were not well conceived at the time and now need to go
Testing is NOT complete as there were issues in JMRI that also need to be resolved in sync with this so we're not quite there yet..
2017-06-08 09:58:41 +12:00
Franz-Peter
0d2e8daeaf With eeprom_is_ready() for AVR-processors (#13)
* with eepromReady for AVR

* with eepromReady for AVR
2017-06-04 13:30:31 +12:00
Franz-Peter
92dd2e6ac5 With eeprom_is_ready() for AVR-processors (#13)
* with eepromReady for AVR

* with eepromReady for AVR
2017-05-25 15:19:17 +12:00
Alex Shepherd
07933e42a8 Fixed some bugs around DCC Accessory Output Mode Addressing and handling of edge cases
Add function to set Accessory Decoder Address from next received Accessory Decoder command and new notify call-backs when a new address is set
Added new notifyDccSigOutputState() with no OutputIndex parameter
Bumped version but have NOT tagged the library as it needs more testing and checking for breakage
2017-04-27 01:26:25 +12:00
Franz-Peter
f8f106962f Stm32 support (#12)
* 1st version for STM32

bit detection and EEPROM changed to support STM32

* added STM32F1 support

updated files: library.properties. NmraDcc.cpp, NmraDcc.h

* switch off debug output

* missing #endif added

Testports for esp8266 defined
2017-01-30 17:08:41 +13:00
Alex Shepherd
8c782d5f15 Added ESU ECoS CV Programming support 2016-11-27 22:25:12 +13:00
Alex Shepherd
dafa1c9964 Merged Geoff's Update-Examples-5.4 branch 2016-11-27 19:49:29 +13:00
Alex Shepherd
dcbd20ef7e Merge pull request #11 from mrrwa/Update-Examples-5.4
V5.4 Bug Fixes and Minor Chages
2016-11-27 19:42:57 +13:00
Geoff Bunza
e622a596d7 V5.4 Bug Fixes and Minor Chages
Bug Fix to allow maximum of 17 servos
Bug Fix to correct 2 reload #define definitions
Change to major Loop Delay cut in half to allow for fewer misses of DCC
packet detection
2016-11-26 12:42:30 -08:00
Alex Shepherd
4c1d5fd6e4 changed version to 1.4.1 as a bug fix as something changed in the ESP8266 Core 2016-11-16 10:03:36 +13:00
Alex Shepherd
3a5986d10d added esp8266 to supported architectures
added addition #include file for esp8266 to resolve missing SPI_FLASH_SEC_SIZE symbol
2016-11-16 10:01:36 +13:00
Alex Shepherd
9035e55930 Added Sven to contributors and incremented the version 2016-08-20 17:46:29 +12:00
Alex Shepherd
3eee73f6cd replaced '4096' with definition SPI_FLASH_SEC_SIZE from header file 2016-08-20 17:36:47 +12:00
Sven Bursch-Osewold
d3059d2f4e ESP8266 Support 2016-08-18 19:57:47 +02:00
Alex Shepherd
0c3385b27d Merge pull request #4 from MicroBahner/master
Update DCC bit decoding
2016-07-23 19:48:42 +12:00
MicroBahner
e0d46ff9b9 DCC_DEBUG: new function getNestedIrqCount()
getNestedIrqCount() returns how often the DCC-Irq interrupted itself.
This is a hint that the DCC Signal is not clean and there are glitches.
2016-07-18 16:21:20 +02:00
MicroBahner
0bab98c838 Consider glitches on DCC line
Glitches on the DCC line could make the decoding Irq hang in an dead
lock state. ( if it interrupts itself - this is now recognized )
2016-07-18 10:57:54 +02:00
Alex Shepherd
47d052a939 Added Franz-Peter Müller to the authors list 2016-06-11 16:21:48 +12:00
Alex Shepherd
275dc8ea94 Updated description paragraph to mention that we no longer use the Timer0 Compare MatchB interrupt 2016-06-11 15:58:53 +12:00
Alex Shepherd
dc45375a5a Changed version to 1.3.0 2016-06-11 15:47:03 +12:00
Alex Shepherd
9e656f49c6 Commented out #define NMRA_DCC_ENABLE_14_SPEED_STEP_MODE 2016-06-11 15:46:05 +12:00
Alex Shepherd
2c55e735b7 Added Geoff's 5.1 changes 2016-06-11 15:31:34 +12:00
Alex Shepherd
515e56d918 Merge branch 'master' into MicroBahner-Without-use-of-HW-timers
* master:
  Fixed issue reported by lucari Despite the values set for F0-4, a packet with all fields set to zero is received. The problem seems to be related to NrmaDcc.cpp and a hidden 'break' statement at line 484. This should be swapped with the #endif on the next line. The result is that when a Speed packet is processed, it drops through to the next case statement and sends an empty DCCFunc command.
  Added Iowa Scaled Engineering ARD-DCCSHIELD example
  fixed call-back function void notifyDccFunc and changed version to 1.2.1
2016-05-17 12:09:50 +12:00
Alex Shepherd
ebfb58c1fb Fixed issue reported by lucari
Despite the values set for F0-4, a packet with all fields set to zero is received. The problem seems to be related to NrmaDcc.cpp and a hidden 'break' statement at line 484. This should be swapped with the #endif on the next line. The result is that when a Speed packet is processed, it drops through to the next case statement and sends an empty DCCFunc command.
2016-05-11 20:53:06 +12:00
Alex Shepherd
f50fea1a85 Added Iowa Scaled Engineering ARD-DCCSHIELD example 2016-04-09 13:06:05 +12:00
Alex Shepherd
b8dac78697 merged in master and added initAccessoryDecoder method 2016-03-25 17:46:22 +13:00
Alex Shepherd
e087dc9052 Merge branch 'master' into MicroBahner-Without-use-of-HW-timers 2016-03-24 18:51:12 +13:00
MicroBahner
3cff15994c Switchoff DBGVAR
No Debug-Output
2016-01-03 14:23:45 +01:00
MicroBahner
d47795e54a No HW dependencies
Compiles for AVR and Teensy (Arm) without modifications
2016-01-03 14:17:02 +01:00
58 changed files with 26100 additions and 8147 deletions

View File

@@ -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)

File diff suppressed because it is too large Load Diff

526
NmraDcc.h
View File

@@ -2,7 +2,7 @@
// //
// Model Railroading with Arduino - NmraDcc.h // 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, // This source file is subject of the GNU general public license 2,
// that is available at the world-wide-web at // that is available at the world-wide-web at
@@ -19,6 +19,8 @@
// 2015-11-06 Martin Pischky (martin@pischky.de): // 2015-11-06 Martin Pischky (martin@pischky.de):
// Experimental Version to support 14 speed steps // Experimental Version to support 14 speed steps
// and new signature of notifyDccSpeed and notifyDccFunc // and new signature of notifyDccSpeed and notifyDccFunc
// 2017-11-29 Ken West (kgw4449@gmail.com):
// Added method and callback headers.
// //
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// //
@@ -42,9 +44,13 @@
#include "WProgram.h" #include "WProgram.h"
#endif #endif
#include "EEPROM.h"
#ifndef NMRADCC_IS_IN #ifndef NMRADCC_IS_IN
#define NMRADCC_IS_IN #define NMRADCC_IS_IN
#define NMRADCC_VERSION 200 // Version 2.0.0
#define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte #define MAX_DCC_MESSAGE_LEN 6 // including XOR-Byte
typedef struct typedef struct
@@ -89,12 +95,21 @@ typedef struct
#define CV_VERSION_ID 7 #define CV_VERSION_ID 7
#define CV_MANUFACTURER_ID 8 #define CV_MANUFACTURER_ID 8
#define CV_29_CONFIG 29 #define CV_29_CONFIG 29
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
#if defined(ESP8266)
#include <spi_flash.h>
#define MAXCV SPI_FLASH_SEC_SIZE
#elif defined( __STM32F1__)
#define MAXCV (EEPROM_PAGE_SIZE/4 - 1) // number of storage places (CV address could be larger
// because STM32 uses virtual adresses)
#else
#define MAXCV E2END // the upper limit of the CV value currently defined to max memory.
#endif
typedef enum { typedef enum {
CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */ CV29_LOCO_DIR = 0b00000001, /** bit 0: Locomotive Direction: "0" = normal, "1" = reversed */
CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */ CV29_F0_LOCATION = 0b00000010, /** bit 1: F0 location: "0" = bit 4 in Speed and Direction instructions, "1" = bit 4 in function group one instruction */
CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */ CV29_APS = 0b00000100, /** bit 2: Alternate Power Source (APS) "0" = NMRA Digital only, "1" = Alternate power source set by CV12 */
CV29_ADV_ACK = 0b00001000, /** bit 3: ACK, Advanced Acknowledge mode enabled if 1, disabled if 0 */ 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_SPEED_TABLE_ENABLE = 0b00010000, /** bit 4: STE, Speed Table Enable, "0" = values in CVs 2, 4 and 6, "1" = Custom table selected by CV 25 */
CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */ CV29_EXT_ADDRESSING = 0b00100000, /** bit 5: "0" = one byte addressing, "1" = two byte addressing */
@@ -166,6 +181,16 @@ typedef enum
#define FN_BIT_27 0x40 #define FN_BIT_27 0x40
#define FN_BIT_28 0x80 #define FN_BIT_28 0x80
//#define DCC_DBGVAR
#ifdef DCC_DBGVAR
typedef struct countOf_t {
unsigned long Tel;
unsigned long Err;
}countOf_t ;
extern struct countOf_t countOf;
#endif
class NmraDcc class NmraDcc
{ {
private: private:
@@ -175,23 +200,189 @@ class NmraDcc
NmraDcc(); NmraDcc();
// Flag values to be logically ORed together and passed into the init() method // 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_MY_ADDRESS_ONLY 0x01 // Only process DCC Packets with My Address
#define FLAGS_OUTPUT_ADDRESS_MODE 0x40 // CV 29/541 bit 6 #define FLAGS_AUTO_FACTORY_DEFAULT 0x02 // Call notifyCVResetFactoryDefault() if CV 7 & 8 == 255
#define FLAGS_DCC_ACCESSORY_DECODER 0x80 // CV 29/541 bit 7 #define FLAGS_SETCV_CALLED 0x10 // only used internally !!
void pin( uint8_t ExtIntNum, uint8_t ExtIntPinNum, uint8_t EnablePullup); #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 ); 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(); 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 ); 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 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 // #define DCC_DEBUG
#ifdef DCC_DEBUG #ifdef DCC_DEBUG
uint8_t getIntCount(void); uint8_t getIntCount(void);
uint8_t getTickCount(void); uint8_t getTickCount(void);
uint8_t getBitCount(void); uint8_t getBitCount(void);
uint8_t getState(void); uint8_t getState(void);
uint8_t getNestedIrqCount(void);
#endif #endif
}; };
@@ -204,30 +395,321 @@ class NmraDcc
extern "C" { extern "C" {
#endif #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)); * notifyDccSpeed() Callback for a multifunction decoder speed command.
extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) __attribute__ ((weak)); * 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)); 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)); 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)); 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)); 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)); 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 chaged by means of the setCV() method.
* Note: It is not called if notifyCVWrite() is defined
* or if the value in the EEPROM is the same as the value
* in the write command.
*
* Inputs:
* CV - CV number.
* Value - Value of the CV.
*
* Returns:
* None
*/
extern void notifyCVChange( uint16_t CV, uint8_t Value) __attribute__ ((weak)); 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)); 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)); 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) #if defined (__cplusplus)
} }

View File

@@ -1,2 +1,12 @@
# NmraDcc # NmraDcc
NMRA Digital Command Control (DCC) Library 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)

View File

@@ -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
}

View File

@@ -56,20 +56,7 @@ void notifyDccMsg( DCC_MSG * Msg)
} }
#endif #endif
// 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 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
void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower ) void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t Direction, uint8_t OutputPower )
{ {
Serial.print("notifyDccAccTurnoutBoard: ") ; Serial.print("notifyDccAccTurnoutBoard: ") ;
@@ -82,7 +69,7 @@ void notifyDccAccTurnoutBoard( uint16_t BoardAddr, uint8_t OutputPair, uint8_t D
Serial.println(OutputPower, HEX) ; 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 ) void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower )
{ {
Serial.print("notifyDccAccTurnoutOutput: ") ; 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 // 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(Addr,DEC) ;
Serial.print(','); Serial.print(',');
Serial.print(OutputIndex,DEC) ;
Serial.print(',');
Serial.println(State, HEX) ; Serial.println(State, HEX) ;
} }

View File

@@ -0,0 +1,123 @@
#include <NmraDcc.h>
// This Example shows how to use the library with the Iowa Scaled Engineering ARD-DCCSHIELD
// You can find out more about this DCC Interface here: http://www.iascaled.com/store/ARD-DCCSHIELD
//
// 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
//
// It is a very basic DCC Accessory Decoder that does nothing except allow CV Read/Write and
// you can also print every DCC packet by uncommenting the "#define NOTIFY_DCC_MSG" line below
#define NOTIFY_DCC_MSG
// You can also print other Debug Messages uncommenting the line below
#define DEBUG_MSG
// Un-Comment the line below to Enable DCC ACK for Service Mode Programming Read CV Capablilty
#define ENABLE_DCC_ACK 15 // This is A1 on the Iowa Scaled Engineering ARD-DCCSHIELD DCC Shield
NmraDcc Dcc ;
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, 1},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
};
uint8_t FactoryDefaultCVIndex = 0;
void notifyCVResetFactoryDefault()
{
#ifdef DEBUG_MSG
Serial.println("notifyCVResetFactoryDefault: Settings CVs to Factory Defaults") ;
#endif // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
// to flag to the loop() function that a reset to Factory Defaults needs to be done
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
};
// This function is called by the NmraDcc library when a DCC ACK needs to be sent
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
#ifdef ENABLE_DCC_ACK
void notifyCVAck(void)
{
#ifdef DEBUG_MSG
Serial.println("notifyCVAck") ;
#endif
// Configure the DCC CV Programing ACK pin for an output
pinMode( ENABLE_DCC_ACK, OUTPUT );
// Generate the DCC ACK 60mA pulse
digitalWrite( ENABLE_DCC_ACK, HIGH );
delay( 10 ); // The DCC Spec says 6ms but 10 makes sure... ;)
digitalWrite( ENABLE_DCC_ACK, LOW );
}
#endif
#ifdef NOTIFY_DCC_MSG
void notifyDccMsg( DCC_MSG * Msg)
{
Serial.print("notifyDccMsg: ") ;
for(uint8_t i = 0; i < Msg->Size; i++)
{
Serial.print(Msg->Data[i], HEX);
Serial.write(' ');
}
Serial.println();
}
#endif
void notifyCVChange(uint16_t CV, uint8_t Value)
{
#ifdef DEBUG_MSG
Serial.print("notifyCVChange: CV: ") ;
Serial.print(CV,DEC) ;
Serial.print(" Value: ") ;
Serial.println(Value, DEC) ;
#else
Value = Value; // Silence Compiler Warnings...
CV = CV;
#endif
}
void setup()
{
Serial.begin(115200);
Serial.println("NMRA DCC Iowa Scaled Engineering ARD-DCCSHIELD Example");
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 1);
// Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 10, CV29_ACCESSORY_DECODER, 0 );
Serial.println("Init Done");
}
void loop()
{
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process();
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
{
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
}
}

View 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);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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);
}
}

View File

Before

Width:  |  Height:  |  Size: 780 KiB

After

Width:  |  Height:  |  Size: 780 KiB

View File

@@ -0,0 +1,483 @@
// 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1
{34, 28}, //F0 Current Position
{35, 2}, //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, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //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, 2}, //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, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 28}, // Current Position
{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, 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, 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, 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
{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, 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, 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, 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, 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, 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=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);
};
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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -0,0 +1,485 @@
// Production 17 Function DCC Decoder
// 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{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
{35, 2}, //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, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //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, 2}, //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, 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
{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
{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
{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, 2}, //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, 2}, //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, 2}, //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, 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, 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, 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, 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
{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);
};
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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -0,0 +1,484 @@
// 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{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
{35, 2}, //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, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //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, 2}, //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, 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
{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
{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
{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, 2}, //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, 2}, //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, 2}, //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, 2}, //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, 28}, // Start Position Fx=0
{98, 140}, // End Position Fx=1
{99, 28}, // Current Position
{100, 2}, //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, 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
{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);
};
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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -1,7 +1,10 @@
// Working 17 Function ACESSORY DCC Decoder No CV Programming DccAckPin not needed // Production 17 Switch Acessory DCC Decoder AccDec_17LED_1Ftn.ino
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
// This uses Accessory addresses defined from This_Decoder_Address + 16 // 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 // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
@@ -11,6 +14,7 @@
int tim_delay = 500; int tim_delay = 500;
#define numleds 17 #define numleds 17
byte ledpins [] = {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 FunctionPin0 = 3;
const int FunctionPin1 = 4; const int FunctionPin1 = 4;
const int FunctionPin2 = 5; const int FunctionPin2 = 5;
@@ -31,9 +35,14 @@ const int FunctionPin16 = 19; //A5
NmraDcc Dcc ; NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
#define This_Decoder_Address 40 //ACCESSORY DECODER ADDRESS #define SET_CV_Address 24 // THIS ADDRESS IS FOR SETTING CV'S Like a Loco
//Start of SWITCHES RANGE #define Accessory_Address 40 // THIS ADDRESS IS THE START OF THE SWITCHES RANGE
uint8_t CV_DECODER_MASTER_RESET = 120; // 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 struct CVPair
{ {
uint16_t CV; uint16_t CV;
@@ -41,11 +50,24 @@ struct CVPair
}; };
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_ACCESSORY_DECODER_ADDRESS_LSB, This_Decoder_Address}, // These two CVs define the Long Accessory Address
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0}, {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_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 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_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; uint8_t FactoryDefaultCVIndex = 0;
@@ -55,10 +77,8 @@ void notifyCVResetFactoryDefault()
// to flag to the loop() function that a reset to Factory Defaults needs to be done // to flag to the loop() function that a reset to Factory Defaults needs to be done
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
}; };
void setup() void setup()
{ {
//Serial.begin(115200);
// initialize the digital pins as an outputs // initialize the digital pins as an outputs
for (int i=0; i< numleds; i++) { for (int i=0; i< numleds; i++) {
pinMode(ledpins[i], OUTPUT); pinMode(ledpins[i], OUTPUT);
@@ -88,16 +108,15 @@ void setup()
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 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() void loop()
{ {
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
} }
extern void notifyDccAccState( uint16_t Addr, uint16_t BoardAddr, uint8_t OutputAddr, uint8_t State) { extern void notifyDccAccTurnoutOutput( uint16_t Addr, uint8_t Direction, uint8_t OutputPower ) {
uint8_t Bit_State = OutputAddr & 0x01; if ( Addr >= Accessory_Address && Addr < Accessory_Address+17) //Controls This_Decoder_Address+16
if ( Addr >= This_Decoder_Address || Addr < This_Decoder_Address+17) //Controls This_Decoder_Address+16 digitalWrite( ledpins[Addr-Accessory_Address], Direction );
digitalWrite( ledpins[Addr-This_Decoder_Address], Bit_State );
} }

View File

@@ -0,0 +1,487 @@
// 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{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
{33, 140}, //F0 End Position F0=1
{34, 28}, //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, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // 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, 28}, // Start Position Fx=0
{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
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 1}, // Start Position Fx=0
{68,35}, // End Position Fx=1
{69, 1}, // 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, 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, 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
{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, 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, 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, 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, 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, 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=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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -0,0 +1,484 @@
// 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
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{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
{33, 140}, //F0 End Position
{34, 28}, //F0 Current Position
{35, 2}, //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, 28}, // Start Position
{38, 140}, // End Position
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position
{43, 140}, // End Position
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 2}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position
{48, 140}, // End Position
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 2}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position
{53, 140}, // End Position
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{56, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position
{58, 140}, // End Position
{59, 28}, // Current Position
{60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{61, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position
{63, 140}, // End Position
{64, 28}, // Current Position
{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
{68, 140}, // End Position
{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, 1}, // Start Position
{73, 100}, // End Position
{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, 1}, // Start Position
{78, 10}, // End Position
{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
{83, 5}, // End Position
{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, 1}, // Start Position
{88, 5}, // End Position
{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
{93, 20}, // End Position
{94, 1}, // Current Position
{95, 1}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position
{98, 20}, // End Position
{99, 1}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position
{103, 4}, // End Position
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position
{108, 60}, // End Position
{109, 20}, // Current Position
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position
{113, 4}, // End Position
{114, 1}, // Current Position
//FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position
{118, 50}, // End Position
{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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // All Servo service timing is now local to the Turn on transition
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;
}
}
}
}
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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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) && (FuncState==1)) { // We have an OFF->ON transition
servo[function].attach(pin);
ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
ftn_queue[function].start_value = Dcc.getCV( 32+(function*5));
ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
for (servo_temp=ftn_queue[function].start_value; servo_temp<ftn_queue[function].stop_value; servo_temp=servo_temp+ftn_queue[function].increment) {
servo[function].write(servo_temp);
SoftwareServo::refresh();
delay(4);
}
for (servo_temp=ftn_queue[function].stop_value; servo_temp>ftn_queue[function].start_value; servo_temp=servo_temp-ftn_queue[function].increment) {
servo[function].write(servo_temp);
SoftwareServo::refresh();
delay(4);
}
ftn_queue[function].inuse = 1;
}
if (FuncState==0) {
ftn_queue[function].inuse = 0;
servo[function].detach();
}
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;
}
}

View File

@@ -0,0 +1,488 @@
// 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED
// ******** REMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
struct QUEUE
{
int inuse;
int current_position;
int increment;
int stop_value;
int start_value;
};
QUEUE *ftn_queue = new QUEUE[17];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
CVPair FactoryDefaultCVs [] =
{
// 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
{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
{35, 2}, //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, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //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, 2}, //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, 28}, // Start Position Fx=0
{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
{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, 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, 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, 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, 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, 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, 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=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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 601, FLAGS_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
// 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("Direction = ");
Serial.println(Direction);
#endif
exec_function(Addr-Current_Decoder_Addr, Direction );
}
}
void exec_function (int function, int FuncState) {
byte pin;
int servo_temp;
pin = fpins[function];
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -1,541 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 1}, // Current Position
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1
{99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1
{109, 1}, // Current Position
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,541 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{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
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{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
{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
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,641 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 28}, // Start Position Fx=0
{98, 140}, // End Position Fx=1
{99, 28}, // Current Position
{100, 2}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
void loop() //**********************************************************************
{
boolean servo_on = true;
//MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation
Dcc.process();
SoftwareServo::refresh();
delay(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
servo_on = true;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
servo_on = false;
detach_servo (i);
}
}
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;
servo_on = false;
detach_servo (i);
}
}
if (servo_on) {
set_servo(i, ftn_queue[i].current_position);
}
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0:
if (servo0.attached()==0) servo0.attach(FunctionPin0);
servo0.write(servo_pos);
break;
case 1:
if (servo1.attached()==0) servo1.attach(FunctionPin1);
servo1.write(servo_pos);
break;
case 2:
if (servo2.attached()==0) servo2.attach(FunctionPin2);
servo2.write(servo_pos);
break;
case 3:
if (servo3.attached()==0) servo3.attach(FunctionPin3);
servo3.write(servo_pos);
break;
case 4:
if (servo4.attached()==0) servo4.attach(FunctionPin4);
servo4.write(servo_pos);
break;
case 5:
if (servo5.attached()==0) servo5.attach(FunctionPin5);
servo5.write(servo_pos);
break;
case 6:
if (servo6.attached()==0) servo6.attach(FunctionPin6);
servo6.write(servo_pos);
break;
case 7:
if (servo7.attached()==0) servo7.attach(FunctionPin7);
servo7.write(servo_pos);
break;
case 8:
if (servo8.attached()==0) servo8.attach(FunctionPin8);
servo8.write(servo_pos);
break;
case 9:
if (servo9.attached()==0) servo9.attach(FunctionPin9);
servo9.write(servo_pos);
break;
case 10:
if (servo10.attached()==0) servo10.attach(FunctionPin10);
servo10.write(servo_pos);
break;
case 11:
if (servo11.attached()==0) servo11.attach(FunctionPin11);
servo11.write(servo_pos);
break;
case 12:
if (servo12.attached()==0) servo12.attach(FunctionPin12);
servo12.write(servo_pos);
case 13:
if (servo13.attached()==0) servo13.attach(FunctionPin13);
servo13.write(servo_pos);
break;
case 14:
if (servo14.attached()==0) servo12.attach(FunctionPin14);
servo14.write(servo_pos);
break;
case 15:
if (servo15.attached()==0) servo15.attach(FunctionPin15);
servo15.write(servo_pos);
break;
case 16:
if (servo16.attached()==0) servo16.attach(FunctionPin16);
servo16.write(servo_pos);
break;
default:
break;
}
}
void detach_servo (int servo_num) {
switch (servo_num) {
case 0:
if (servo0.attached()!=0) servo0.detach();
break;
case 1:
if (servo1.attached()!=0) servo1.detach();
break;
case 2:
if (servo2.attached()!=0) servo2.detach();
break;
case 3:
if (servo3.attached()!=0) servo3.detach();
break;
case 4:
if (servo4.attached()!=0) servo4.detach();
break;
case 5:
if (servo5.attached()!=0) servo5.detach();
break;
case 6:
if (servo6.attached()!=0) servo6.detach();
break;
case 7:
if (servo7.attached()!=0) servo7.detach();
break;
case 8:
if (servo8.attached()!=0) servo8.detach();
break;
case 9:
if (servo9.attached()!=0) servo9.detach();
break;
case 10:
if (servo10.attached()!=0) servo10.detach();
break;
case 11:
if (servo11.attached()!=0) servo11.detach();
break;
case 12:
if (servo12.attached()!=0) servo12.detach();
break;
case 13:
if (servo13.attached()!=0) servo13.detach();
break;
case 14:
if (servo14.attached()!=0) servo12.detach();
break;
case 15:
if (servo15.attached()!=0) servo15.detach();
break;
case 16:
if (servo16.attached()!=0) servo16.detach();
break;
default:
break;
}
}

View File

@@ -1,541 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 28}, // Start Position Fx=0
{98, 140}, // End Position Fx=1
{99, 28}, // Current Position
{100, 2}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,541 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 28}, // Current Position
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 1}, // Start Position Fx=0
{68,35}, // End Position Fx=1
{69, 1}, // Current Position
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 1}, // Current Position
{95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1
{99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,564 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// This configuration supports 5 Modes per pin:
// 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
// It is recommended that you NOT MIX pulsed and servo control
// simultaneously as the servo timing will be off
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 4}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1
{34, 0}, //F0 Current Position
{35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{36, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 0}, // Current Position
{40, 4}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{41, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 0}, // Current Position
{45, 4}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{46, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 0}, // Current Position
{50, 4}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{51, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 0}, // Current Position
{55, 4}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{56, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1
{59, 0}, // Current Position
{60, 4}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{61, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 0}, // Current Position
{65, 4}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{66, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{67, 1}, // Start Position Fx=0
{68,35}, // End Position Fx=1
{69, 0}, // Current Position
{70, 4}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{71, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{72, 1}, // Start Position Fx=0
{73, 100}, // End Position Fx=1
{74, 0}, // Current Position
{75, 4}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{76, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{77, 1}, // Start Position Fx=0
{78, 10}, // End Position Fx=1
{79, 0}, // Current Position
{80, 4}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{81, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{82, 1}, // Start Position Fx=0
{83, 5}, // End Position Fx=1
{84, 0}, // Current Position
{85, 4}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{86, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{87, 1}, // Start Position Fx=0
{88, 5}, // End Position Fx=1
{89, 0}, // Current Position
{90, 4}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{91, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 0}, // Current Position
{95, 4}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{96, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1
{99, 0}, // Current Position
{100, 4}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{101, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 0}, // Current Position
{105, 4}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{106, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1
{109, 0}, // Current Position
{110, 4}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{111, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{112, 1}, // Start Position Fx=0
{113, 4}, // End Position Fx=1
{114, 0}, // Current Position
//FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{116, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{117, 28}, // Start Position Fx=0
{118, 50}, // End Position Fx=1
{119, 28}, // Current Position
};
uint8_t FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
void setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: //FUTURE FUNCTION
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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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
break;
case 5: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,548 +0,0 @@
// Production 7 Servo Back and Forth DCC Acessory Decoder Dual Address w/CV Access
// Version 1.2 Geoff Bunza 2014
// Uses modified software servo Lib
// 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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
int servo_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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{31, 3}, //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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{56, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1
{59, 28}, // Current Position
{60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 3}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 28}, // Current Position
{65, 1}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 1}, // Current Position
{95, 1}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{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
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{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
{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
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 0;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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: // All Servo service timing is now local to the Turn on transition
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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) && (FuncState==1)) { // We have an OFF->ON transition
ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
ftn_queue[function].start_value = Dcc.getCV( 32+(function*5));
ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
for (servo_temp=ftn_queue[function].start_value; servo_temp<ftn_queue[function].stop_value; servo_temp=servo_temp+ftn_queue[function].increment) {
set_servo(function,servo_temp);
SoftwareServo::refresh();
delay(4);
}
for (servo_temp=ftn_queue[function].stop_value; servo_temp>ftn_queue[function].start_value; servo_temp=servo_temp-ftn_queue[function].increment) {
set_servo(function,servo_temp);
SoftwareServo::refresh();
delay(4);
}
ftn_queue[function].inuse = 1;
}
if (FuncState==0) ftn_queue[function].inuse = 0;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,541 +0,0 @@
// Production 17 Function DCC Acessory Decoder Dual Address w/CV Access
// Version 4.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 ;
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
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 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;
};
CVPair FactoryDefaultCVs [] =
{
{CV_ACCESSORY_DECODER_ADDRESS_LSB, Accessory_Address},
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0},
{CV_DECODER_MASTER_RESET, 0},
{CV_To_Store_SET_CV_Address, SET_CV_Address},
{CV_To_Store_SET_CV_Address+1, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{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
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=PWM
{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
{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
{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 setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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_OUTPUT_ADDRESS_MODE | FLAGS_DCC_ACCESSORY_DECODER, CV_To_Store_SET_CV_Address);
delay(800);
#if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif
{
for (int j=0; j < sizeof(FactoryDefaultCVs)/sizeof(CVPair); j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(fpins[14], 1);
delay (1000);
digitalWrite(fpins[14], 0);
}
for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
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;
if ( Addr >= Current_Decoder_Addr || Addr < Current_Decoder_Addr+17) { //Controls Accessory_Address+16
switch (Addr-Current_Decoder_Addr) {
case 0: exec_function( 0, FunctionPin0, Bit_State );
break;
case 1: exec_function( 1, FunctionPin1, Bit_State );
break;
case 2: exec_function( 2, FunctionPin2, Bit_State );
break;
case 3: exec_function( 3, FunctionPin3, Bit_State );
break;
case 4: exec_function( 4, FunctionPin4, Bit_State );
break;
case 5: exec_function( 5, FunctionPin5, Bit_State );
break;
case 6: exec_function( 6, FunctionPin6, Bit_State );
break;
case 7: exec_function( 7, FunctionPin7, Bit_State );
break;
case 8: exec_function( 8, FunctionPin8, Bit_State );
break;
case 9: exec_function( 9, FunctionPin9, Bit_State );
break;
case 10: exec_function( 10, FunctionPin10, Bit_State );
break;
case 11: exec_function( 11, FunctionPin11, Bit_State );
break;
case 12: exec_function( 12, FunctionPin12, Bit_State );
break;
case 13: exec_function( 13, FunctionPin13, Bit_State );
break;
case 14: exec_function( 14, FunctionPin14, Bit_State );
break;
case 15: exec_function( 15, FunctionPin15, Bit_State );
break;
case 16: exec_function( 16, FunctionPin16, Bit_State );
break;
default:
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,34 +1,27 @@
// Production 17 Function DCC Decoder // Production 17 Function DCC Decoder
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
// Uses modified software servo Lib // 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
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h> #include <NmraDcc.h>
#include <SoftwareServo.h> #include <SoftwareServo.h>
SoftwareServo servo0; SoftwareServo servo[17];
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50 #define servo_start_delay 50
#define servo_init_delay 7 #define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500; int tim_delay = 500;
int numfpins = 17; int numfpins = 17;
@@ -57,7 +50,6 @@ NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120; uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp int t; // temp
#define This_Decoder_Address 24
struct QUEUE struct QUEUE
{ {
int inuse; int inuse;
@@ -66,107 +58,117 @@ struct QUEUE
int stop_value; int stop_value;
int start_value; int start_value;
}; };
QUEUE *ftn_queue = new QUEUE[16]; QUEUE *ftn_queue = new QUEUE[17];
struct CVPair struct CVPair
{ {
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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_DECODER_MASTER_RESET, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
{32, 28}, //F0 Start Position F0=0 {32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1 {33, 140}, //F0 End Position F0=1
{34, 28}, //F0 Current Position {34, 28}, //F0 Current Position
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {35, 2}, //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 {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0 {37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1 {38, 140}, // End Position Fx=1
{39, 28}, // Current Position {39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0 {42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1 {43, 140}, // End Position Fx=1
{44, 28}, // Current Position {44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0 {47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1 {48, 140}, // End Position Fx=1
{49, 28}, // Current Position {49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0 {52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1 {53, 140}, // End Position Fx=1
{54, 28}, // Current Position {54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {55, 2}, //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 {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position Fx=0 {57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1 {58, 140}, // End Position Fx=1
{59, 28}, // Current Position {59, 28}, // Current Position
{60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {60, 2}, //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 {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0 {62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1 {63, 140}, // End Position Fx=1
{64, 28}, // Current Position {64, 28}, // Current Position
{65, 2}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {65, 2}, //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 {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 28}, // Start Position Fx=0 {67, 28}, // Start Position Fx=0
{68,140}, // End Position Fx=1 {68,140}, // End Position Fx=1
{69, 28}, // Current Position {69, 28}, // Current Position
{70, 2}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {70, 2}, //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 {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{72, 28}, // Start Position Fx=0 {72, 28}, // Start Position Fx=0
{73, 140}, // End Position Fx=1 {73, 140}, // End Position Fx=1
{74, 28}, // Current Position {74, 28}, // Current Position
{75, 2}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {75, 2}, //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 {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{77, 28}, // Start Position Fx=0 {77, 28}, // Start Position Fx=0
{78, 140}, // End Position Fx=1 {78, 140}, // End Position Fx=1
{79, 28}, // Current Position {79, 28}, // Current Position
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{82, 1}, // Start Position Fx=0 {82, 1}, // Start Position Fx=0
{83, 5}, // End Position Fx=1 {83, 5}, // End Position Fx=1
{84, 1}, // Current Position {84, 1}, // Current Position
{85, 1}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{87, 1}, // Start Position Fx=0 {87, 1}, // Start Position Fx=0
{88, 5}, // End Position Fx=1 {88, 50}, // End Position Fx=1
{89, 1}, // Current Position {89, 1}, // Current Position
{90, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0 {92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1 {93, 100}, // End Position Fx=1
{94, 1}, // Current Position {94, 1}, // Current Position
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0 {97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1 {98, 200}, // End Position Fx=1
{99, 2}, // Current Position {99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0 {102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1 {103, 200}, // End Position Fx=1
{104, 1}, // Current Position {104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0 {107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1 {108, 60}, // End Position Fx=1
{109, 1}, // Current Position {109, 1}, // Current Position
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position Fx=0 {112, 1}, // Start Position Fx=0
{113, 4}, // End Position Fx=1 {113, 4}, // End Position Fx=1
{114, 1}, // Current Position {114, 1}, // Current Position
//FUTURE USE //FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position Fx=0 {117, 28}, // Start Position Fx=0
{118, 50}, // End Position Fx=1 {118, 50}, // End Position Fx=1
@@ -181,11 +183,15 @@ void notifyCVResetFactoryDefault()
FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair); FactoryDefaultCVIndex = sizeof(FactoryDefaultCVs)/sizeof(CVPair);
}; };
// NOTE: NO PROGRAMMING ACK IS SET UP TO MAXIMAIZE
// OUTPUT PINS FOR FUNCTIONS
void setup() //****************************************************** void setup() //******************************************************
{ {
#ifdef DEBUG
Serial.begin(115200);
#endif
int i; int i;
uint8_t cv_value; uint8_t cv_value;
Serial.begin(115200);
// initialize the digital pins as outputs // initialize the digital pins as outputs
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
pinMode(fpins[i], OUTPUT); pinMode(fpins[i], OUTPUT);
@@ -205,12 +211,12 @@ void setup() //******************************************************
// Setup which External Interrupt, the Pin it's associated with that we're using // Setup which External Interrupt, the Pin it's associated with that we're using
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
delay(800); delay(800);
#if defined(DECODER_LOADED) #if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif #endif
{ {
for (int j=0; j < FactoryDefaultCVIndex; j++ ) for (int j=0; j < FactoryDefaultCVIndex; j++ )
@@ -218,11 +224,13 @@ void setup() //******************************************************
digitalWrite(fpins[14], 1); digitalWrite(fpins[14], 1);
delay (1000); delay (1000);
digitalWrite(fpins[14], 0); digitalWrite(fpins[14], 0);
} }
for ( i=0; i < numfpins; i++) { for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ; cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: "); #ifdef DEBUG
//Serial.println(cv_value, DEC) ; Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) { switch ( cv_value ) {
case 0: // LED on/off case 0: // LED on/off
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
@@ -230,143 +238,84 @@ void setup() //******************************************************
case 1: // LED Blink case 1: // LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
} }
break; break;
case 2: //servo case 2: //servo
{ ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); {
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].stop_value = int (Dcc.getCV( 33+(i*5)));
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
switch ( i ) { // attaches servo on pin to the servo object
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object servo[i].attach(fpins[i]);
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value); #ifdef DEBUG
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} Serial.print("InitServo ID= ");
break; Serial.println(i, DEC) ;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object #endif
ftn_queue[i].inuse = 1; servo[i].write(ftn_queue[i].start_value);
servo1.write(ftn_queue[i].start_value); for (t=0; t<servo_start_delay; t++)
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} {SoftwareServo::refresh();delay(servo_init_delay);}
break; ftn_queue[i].inuse = 0;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object servo[i].detach();
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
} }
break; break;
case 3: // DOUBLE ALTERNATING LED Blink case 3: // DOUBLE ALTERNATING LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
digitalWrite(fpins[i+1], 0); digitalWrite(fpins[i+1], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
} }
break; break;
case 4: // NEXT FEATURE to pin 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; break;
default: default:
break; break;
} }
} }
}
}
void loop() //********************************************************************** void loop() //**********************************************************************
{ {
//MUST call the NmraDcc.process() method frequently //MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation // from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
SoftwareServo::refresh(); SoftwareServo::refresh();
delay(8); delay(3);
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) { if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) { switch (Dcc.getCV( 30+(i*5))) {
case 0: case 0:
break; break;
case 1: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -376,18 +325,30 @@ void loop() //****************************************************************
break; break;
case 2: case 2:
{ {
if (ftn_queue[i].increment > 0) { if (servo_slow_counter++ > servo_slowdown)
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].current_position = ftn_queue[i].stop_value; ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
} if (ftn_queue[i].increment > 0) {
if (ftn_queue[i].increment < 0) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
if (ftn_queue[i].current_position < ftn_queue[i].start_value) ftn_queue[i].current_position = ftn_queue[i].stop_value;
ftn_queue[i].current_position = ftn_queue[i].start_value; ftn_queue[i].inuse = 0;
} servo[i].detach();
set_servo(i, ftn_queue[i].current_position); }
} }
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; break;
case 3: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -397,16 +358,38 @@ void loop() //****************************************************************
} }
i++; i++;
break; break;
case 4: //FUTURE FUNCTION case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
break; {
default: ftn_queue[i].inuse = 0;
break; 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 notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) { 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) switch(FuncGrp)
{ {
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1 case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
@@ -443,7 +426,7 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
} }
} }
void exec_function (int function, int pin, int FuncState) { void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink 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 case 0: // On - Off LED
digitalWrite (pin, FuncState); digitalWrite (pin, FuncState);
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
@@ -452,31 +435,24 @@ void exec_function (int function, int pin, int FuncState) {
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
ftn_queue[function].inuse = 1; ftn_queue[function].inuse = 1;
ftn_queue[function].start_value = 0; ftn_queue[function].start_value = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
} else { } else {
if ((ftn_queue[function].inuse==1) && (FuncState==0)) { if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
} }
} }
break; break;
case 2: // Servo case 2: // Servo
ftn_queue[function].inuse = 1; 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))); if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
else 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)); if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
break; break;
case 3: // Blinking LED PAIR case 3: // Blinking LED PAIR
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
@@ -493,51 +469,38 @@ void exec_function (int function, int pin, int FuncState) {
} }
} }
break; break;
case 4: // Future Function 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; ftn_queue[function].inuse = 0;
break; break;
default: default:
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
break; break;
} }
} }
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,34 +1,25 @@
// Production 17 Function DCC Decoder // Production 17 Function DCC Decoder Dec_13Serv_4LED_6Ftn.ino
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016
// Uses modified software servo Lib // NO LONGER REQUIRES modified software servo Lib
// // Software restructuring mods added from Alex Shepherd and Franz-Peter
// With sincere thanks
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h> #include <NmraDcc.h>
#include <SoftwareServo.h> #include <SoftwareServo.h>
SoftwareServo servo0; SoftwareServo servo[17];
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50 #define servo_start_delay 50
#define servo_init_delay 7 #define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500; int tim_delay = 500;
int numfpins = 17; int numfpins = 17;
@@ -57,7 +48,6 @@ NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120; uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp int t; // temp
#define This_Decoder_Address 24
struct QUEUE struct QUEUE
{ {
int inuse; int inuse;
@@ -73,100 +63,110 @@ struct CVPair
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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_DECODER_MASTER_RESET, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
{32, 28}, //F0 Start Position F0=0 {32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1 {33, 140}, //F0 End Position F0=1
{34, 28}, //F0 Current Position {34, 28}, //F0 Current Position
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {35, 2}, //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 {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0 {37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1 {38, 140}, // End Position Fx=1
{39, 28}, // Current Position {39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0 {42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1 {43, 140}, // End Position Fx=1
{44, 28}, // Current Position {44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0 {47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1 {48, 140}, // End Position Fx=1
{49, 28}, // Current Position {49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0 {52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1 {53, 140}, // End Position Fx=1
{54, 28}, // Current Position {54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {55, 2}, //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 {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position Fx=0 {57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1 {58, 140}, // End Position Fx=1
{59, 28}, // Current Position {59, 28}, // Current Position
{60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {60, 2}, //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 {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0 {62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1 {63, 140}, // End Position Fx=1
{64, 28}, // Current Position {64, 28}, // Current Position
{65, 2}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {65, 2}, //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 {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 28}, // Start Position Fx=0 {67, 28}, // Start Position Fx=0
{68, 140}, // End Position Fx=1 {68, 140}, // End Position Fx=1
{69, 28}, // Current Position {69, 28}, // Current Position
{70, 2}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {70, 2}, //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 {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{72, 28}, // Start Position Fx=0 {72, 28}, // Start Position Fx=0
{73, 140}, // End Position Fx=1 {73, 140}, // End Position Fx=1
{74, 28}, // Current Position {74, 28}, // Current Position
{75, 2}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {75, 2}, //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 {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{77, 28}, // Start Position Fx=0 {77, 28}, // Start Position Fx=0
{78, 140}, // End Position Fx=1 {78, 140}, // End Position Fx=1
{79, 28}, // Current Position {79, 28}, // Current Position
{80, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {80, 2}, //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 {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{82, 28}, // Start Position Fx=0 {82, 28}, // Start Position Fx=0
{83, 140}, // End Position Fx=1 {83, 140}, // End Position Fx=1
{84, 28}, // Current Position {84, 28}, // Current Position
{85, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {85, 2}, //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 {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{87, 28}, // Start Position Fx=0 {87, 28}, // Start Position Fx=0
{88, 140}, // End Position Fx=1 {88, 140}, // End Position Fx=1
{89, 28}, // Current Position {89, 28}, // Current Position
{90, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {90, 2}, //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 {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 28}, // Start Position Fx=0 {92, 28}, // Start Position Fx=0
{93, 140}, // End Position Fx=1 {93, 140}, // End Position Fx=1
{94, 28}, // Current Position {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 {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0 {97, 1}, // Start Position Fx=0
{98, 20}, // End Position Fx=1 {98, 200}, // End Position Fx=1
{99, 1}, // Current Position {99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=PWM {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 {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0 {102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1 {103, 200}, // End Position Fx=1
{104, 1}, // Current Position {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 {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0 {107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1 {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=PWM {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 {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position Fx=0 {112, 1}, // Start Position Fx=0
{113, 4}, // End Position Fx=1 {113, 4}, // End Position Fx=1
{114, 1}, // Current Position {114, 1}, // Current Position
//FUTURE USE //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 {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position Fx=0 {117, 28}, // Start Position Fx=0
{118, 50}, // End Position Fx=1 {118, 50}, // End Position Fx=1
@@ -183,9 +183,11 @@ void notifyCVResetFactoryDefault()
void setup() //****************************************************** void setup() //******************************************************
{ {
#ifdef DEBUG
Serial.begin(115200);
#endif
int i; int i;
uint8_t cv_value; uint8_t cv_value;
Serial.begin(115200);
// initialize the digital pins as outputs // initialize the digital pins as outputs
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
pinMode(fpins[i], OUTPUT); pinMode(fpins[i], OUTPUT);
@@ -205,12 +207,12 @@ void setup() //******************************************************
// Setup which External Interrupt, the Pin it's associated with that we're using // Setup which External Interrupt, the Pin it's associated with that we're using
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
delay(800); delay(800);
#if defined(DECODER_LOADED) #if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif #endif
{ {
for (int j=0; j < FactoryDefaultCVIndex; j++ ) for (int j=0; j < FactoryDefaultCVIndex; j++ )
@@ -218,11 +220,13 @@ void setup() //******************************************************
digitalWrite(fpins[14], 1); digitalWrite(fpins[14], 1);
delay (1000); delay (1000);
digitalWrite(fpins[14], 0); digitalWrite(fpins[14], 0);
} }
for ( i=0; i < numfpins; i++) { for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ; cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: "); #ifdef DEBUG
//Serial.println(cv_value, DEC) ; Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) { switch ( cv_value ) {
case 0: // LED on/off case 0: // LED on/off
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
@@ -230,143 +234,84 @@ void setup() //******************************************************
case 1: // LED Blink case 1: // LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
} }
break; break;
case 2: //servo case 2: //servo
{ ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); {
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].stop_value = int (Dcc.getCV( 33+(i*5)));
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
switch ( i ) { // attaches servo on pin to the servo object
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object servo[i].attach(fpins[i]);
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value); #ifdef DEBUG
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} Serial.print("InitServo ID= ");
break; Serial.println(i, DEC) ;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object #endif
ftn_queue[i].inuse = 1; servo[i].write(ftn_queue[i].start_value);
servo1.write(ftn_queue[i].start_value); for (t=0; t<servo_start_delay; t++)
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} {SoftwareServo::refresh();delay(servo_init_delay);}
break; ftn_queue[i].inuse = 0;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object servo[i].detach();
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
} }
break; break;
case 3: // DOUBLE ALTERNATING LED Blink case 3: // DOUBLE ALTERNATING LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
digitalWrite(fpins[i+1], 0); digitalWrite(fpins[i+1], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
} }
break; break;
case 4: // NEXT FEATURE to pin 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; break;
default: default:
break; break;
} }
} }
}
}
void loop() //********************************************************************** void loop() //**********************************************************************
{ {
//MUST call the NmraDcc.process() method frequently //MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation // from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
SoftwareServo::refresh(); SoftwareServo::refresh();
delay(8); delay(3);
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) { if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) { switch (Dcc.getCV( 30+(i*5))) {
case 0: case 0:
break; break;
case 1: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -376,18 +321,30 @@ void loop() //****************************************************************
break; break;
case 2: case 2:
{ {
if (ftn_queue[i].increment > 0) { if (servo_slow_counter++ > servo_slowdown)
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].current_position = ftn_queue[i].stop_value; ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
} if (ftn_queue[i].increment > 0) {
if (ftn_queue[i].increment < 0) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
if (ftn_queue[i].current_position < ftn_queue[i].start_value) ftn_queue[i].current_position = ftn_queue[i].stop_value;
ftn_queue[i].current_position = ftn_queue[i].start_value; ftn_queue[i].inuse = 0;
} servo[i].detach();
set_servo(i, ftn_queue[i].current_position); }
} }
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; break;
case 3: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -397,10 +354,21 @@ void loop() //****************************************************************
} }
i++; i++;
break; break;
case 4: //FUTURE FUNCTION case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
break; {
default: ftn_queue[i].inuse = 0;
break; 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;
} }
} }
} }
@@ -443,9 +411,8 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
} }
} }
void exec_function (int function, int pin, int FuncState) { void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink 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 case 0: // On - Off LED
//Serial.println("****************cv:0 ") ;
digitalWrite (pin, FuncState); digitalWrite (pin, FuncState);
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
break; break;
@@ -453,31 +420,24 @@ void exec_function (int function, int pin, int FuncState) {
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
ftn_queue[function].inuse = 1; ftn_queue[function].inuse = 1;
ftn_queue[function].start_value = 0; ftn_queue[function].start_value = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
} else { } else {
if ((ftn_queue[function].inuse==1) && (FuncState==0)) { if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
} }
} }
break; break;
case 2: // Servo case 2: // Servo
ftn_queue[function].inuse = 1; 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))); if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
else 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)); if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
break; break;
case 3: // Blinking LED PAIR case 3: // Blinking LED PAIR
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
@@ -494,7 +454,34 @@ void exec_function (int function, int pin, int FuncState) {
} }
} }
break; break;
case 4: // Future Function 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; ftn_queue[function].inuse = 0;
break; break;
default: default:
@@ -502,43 +489,3 @@ void exec_function (int function, int pin, int FuncState) {
break; break;
} }
} }
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,34 +1,25 @@
// Production 17 Function DCC Decoder // Production 17 Function DCC Decoder Dec_15Serv_2LED_6Ftn.ino
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016
// Uses modified software servo Lib // NO LONGER REQUIRES modified software servo Lib
// // Software restructuring mods added from Alex Shepherd and Franz-Peter
// With sincere thanks
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h> #include <NmraDcc.h>
#include <SoftwareServo.h> #include <SoftwareServo.h>
SoftwareServo servo0; SoftwareServo servo[17];
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50 #define servo_start_delay 50
#define servo_init_delay 7 #define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500; int tim_delay = 500;
int numfpins = 17; int numfpins = 17;
@@ -57,7 +48,6 @@ NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120; uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp int t; // temp
#define This_Decoder_Address 24
struct QUEUE struct QUEUE
{ {
int inuse; int inuse;
@@ -73,100 +63,110 @@ struct CVPair
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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_DECODER_MASTER_RESET, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
{32, 28}, //F0 Start Position F0=0 {32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1 {33, 140}, //F0 End Position F0=1
{34, 28}, //F0 Current Position {34, 28}, //F0 Current Position
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {35, 2}, //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 {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0 {37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1 {38, 140}, // End Position Fx=1
{39, 28}, // Current Position {39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0 {42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1 {43, 140}, // End Position Fx=1
{44, 28}, // Current Position {44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0 {47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1 {48, 140}, // End Position Fx=1
{49, 28}, // Current Position {49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0 {52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1 {53, 140}, // End Position Fx=1
{54, 28}, // Current Position {54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {55, 2}, //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 {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position Fx=0 {57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1 {58, 140}, // End Position Fx=1
{59, 28}, // Current Position {59, 28}, // Current Position
{60, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {60, 2}, //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 {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0 {62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1 {63, 140}, // End Position Fx=1
{64, 28}, // Current Position {64, 28}, // Current Position
{65, 2}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {65, 2}, //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 {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 28}, // Start Position Fx=0 {67, 28}, // Start Position Fx=0
{68, 140}, // End Position Fx=1 {68, 140}, // End Position Fx=1
{69, 28}, // Current Position {69, 28}, // Current Position
{70, 2}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {70, 2}, //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 {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{72, 28}, // Start Position Fx=0 {72, 28}, // Start Position Fx=0
{73, 140}, // End Position Fx=1 {73, 140}, // End Position Fx=1
{74, 28}, // Current Position {74, 28}, // Current Position
{75, 2}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {75, 2}, //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 {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{77, 28}, // Start Position Fx=0 {77, 28}, // Start Position Fx=0
{78, 140}, // End Position Fx=1 {78, 140}, // End Position Fx=1
{79, 28}, // Current Position {79, 28}, // Current Position
{80, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {80, 2}, //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 {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{82, 28}, // Start Position Fx=0 {82, 28}, // Start Position Fx=0
{83, 140}, // End Position Fx=1 {83, 140}, // End Position Fx=1
{84, 28}, // Current Position {84, 28}, // Current Position
{85, 2}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {85, 2}, //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 {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{87, 28}, // Start Position Fx=0 {87, 28}, // Start Position Fx=0
{88, 140}, // End Position Fx=1 {88, 140}, // End Position Fx=1
{89, 28}, // Current Position {89, 28}, // Current Position
{90, 2}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {90, 2}, //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 {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 28}, // Start Position Fx=0 {92, 28}, // Start Position Fx=0
{93, 140}, // End Position Fx=1 {93, 140}, // End Position Fx=1
{94, 28}, // Current Position {94, 28}, // Current Position
{95, 2}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {95, 2}, //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 {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 28}, // Start Position Fx=0 {97, 28}, // Start Position Fx=0
{98, 140}, // End Position Fx=1 {98, 140}, // End Position Fx=1
{99, 28}, // Current Position {99, 28}, // Current Position
{100, 2}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {100, 2}, //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 {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 28}, // Start Position Fx=0 {102, 28}, // Start Position Fx=0
{103, 140}, // End Position Fx=1 {103, 140}, // End Position Fx=1
{104, 28}, // Current Position {104, 28}, // Current Position
{105, 1}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0 {107, 1}, // Start Position Fx=0
{108, 10}, // End Position Fx=1 {108, 60}, // End Position Fx=1
{109, 1}, // Current Position {109, 1}, // Current Position
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position Fx=0 {112, 1}, // Start Position Fx=0
{113, 10}, // End Position Fx=1 {113, 4}, // End Position Fx=1
{114, 1}, // Current Position {114, 1}, // Current Position
//FUTURE USE //FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position Fx=0 {117, 28}, // Start Position Fx=0
{118, 50}, // End Position Fx=1 {118, 50}, // End Position Fx=1
@@ -183,9 +183,11 @@ void notifyCVResetFactoryDefault()
void setup() //****************************************************** void setup() //******************************************************
{ {
#ifdef DEBUG
Serial.begin(115200);
#endif
int i; int i;
uint8_t cv_value; uint8_t cv_value;
Serial.begin(115200);
// initialize the digital pins as outputs // initialize the digital pins as outputs
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
pinMode(fpins[i], OUTPUT); pinMode(fpins[i], OUTPUT);
@@ -205,12 +207,12 @@ void setup() //******************************************************
// Setup which External Interrupt, the Pin it's associated with that we're using // Setup which External Interrupt, the Pin it's associated with that we're using
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
delay(800); delay(800);
#if defined(DECODER_LOADED) #if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif #endif
{ {
for (int j=0; j < FactoryDefaultCVIndex; j++ ) for (int j=0; j < FactoryDefaultCVIndex; j++ )
@@ -218,11 +220,13 @@ void setup() //******************************************************
digitalWrite(fpins[14], 1); digitalWrite(fpins[14], 1);
delay (1000); delay (1000);
digitalWrite(fpins[14], 0); digitalWrite(fpins[14], 0);
} }
for ( i=0; i < numfpins; i++) { for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ; cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: "); #ifdef DEBUG
//Serial.println(cv_value, DEC) ; Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) { switch ( cv_value ) {
case 0: // LED on/off case 0: // LED on/off
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
@@ -230,113 +234,37 @@ void setup() //******************************************************
case 1: // LED Blink case 1: // LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) ;
} }
break; break;
case 2: //servo case 2: //servo
{ ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); {
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].stop_value = int (Dcc.getCV( 33+(i*5)));
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
switch ( i ) { // attaches servo on pin to the servo object
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object servo[i].attach(fpins[i]);
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value); #ifdef DEBUG
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);} Serial.print("InitServo ID= ");
break; Serial.println(i, DEC) ;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object #endif
ftn_queue[i].inuse = 1; servo[i].write(ftn_queue[i].start_value);
servo1.write(ftn_queue[i].start_value); for (t=0; t<servo_start_delay; t++)
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);} {SoftwareServo::refresh();delay(servo_init_delay);}
break; ftn_queue[i].inuse = 0;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object servo[i].detach();
ftn_queue[i].inuse = 1; }
servo2.write(ftn_queue[i].start_value); break;
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(10);}
break;
default:
break;
}
}
break;
case 3: // DOUBLE ALTERNATING LED Blink case 3: // DOUBLE ALTERNATING LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = Dcc.getCV( 31+(i*5)); ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
@@ -344,29 +272,46 @@ void setup() //******************************************************
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
} }
break; break;
case 4: // NEXT FEATURE to pin case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
break; {
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: default:
break; break;
} }
} }
}
}
void loop() //********************************************************************** void loop() //**********************************************************************
{ {
//MUST call the NmraDcc.process() method frequently //MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation // from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
SoftwareServo::refresh(); SoftwareServo::refresh();
delay(8); delay(3);
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) { if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) { switch (Dcc.getCV( 30+(i*5))) {
case 0: case 0:
break; break;
case 1: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -376,18 +321,30 @@ void loop() //****************************************************************
break; break;
case 2: case 2:
{ {
if (ftn_queue[i].increment > 0) { if (servo_slow_counter++ > servo_slowdown)
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].current_position = ftn_queue[i].stop_value; ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
} if (ftn_queue[i].increment > 0) {
if (ftn_queue[i].increment < 0) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
if (ftn_queue[i].current_position < ftn_queue[i].start_value) ftn_queue[i].current_position = ftn_queue[i].stop_value;
ftn_queue[i].current_position = ftn_queue[i].start_value; ftn_queue[i].inuse = 0;
} servo[i].detach();
set_servo(i, ftn_queue[i].current_position); }
} }
break; if (ftn_queue[i].increment < 0) {
case 3: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -396,11 +353,22 @@ void loop() //****************************************************************
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
} }
i++; i++;
break; break;
case 4: //FUTURE FUNCTION case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
break; {
default: ftn_queue[i].inuse = 0;
break; 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;
} }
} }
} }
@@ -443,7 +411,7 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
} }
} }
void exec_function (int function, int pin, int FuncState) { void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink 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 case 0: // On - Off LED
digitalWrite (pin, FuncState); digitalWrite (pin, FuncState);
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
@@ -452,31 +420,24 @@ void exec_function (int function, int pin, int FuncState) {
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
ftn_queue[function].inuse = 1; ftn_queue[function].inuse = 1;
ftn_queue[function].start_value = 0; ftn_queue[function].start_value = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))); ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5)));
} else { } else {
if ((ftn_queue[function].inuse==1) && (FuncState==0)) { if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
digitalWrite(fpins[function], 0); digitalWrite(pin, 0);
} }
} }
break; break;
case 2: // Servo case 2: // Servo
ftn_queue[function].inuse = 1; 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))); if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
else 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)); if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
break; break;
case 3: // Blinking LED PAIR case 3: // Blinking LED PAIR
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
@@ -493,7 +454,34 @@ void exec_function (int function, int pin, int FuncState) {
} }
} }
break; break;
case 4: // Future Function 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; ftn_queue[function].inuse = 0;
break; break;
default: default:
@@ -501,43 +489,3 @@ void exec_function (int function, int pin, int FuncState) {
break; break;
} }
} }
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,12 +1,16 @@
// Working 14 Function DCC Decoder DccAckPin not needed // Production 17 Function DCC Decoder Dec_17LED_1Ftn.ino
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
// Uses modified software servo Lib // 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!!
//#define DECODER_LOADED
#include <NmraDcc.h> #include <NmraDcc.h>
int tim_delay = 500; int tim_delay = 500;
#define numleds 17 #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 FunctionPin0 = 3;
const int FunctionPin1 = 4; const int FunctionPin1 = 4;
@@ -23,15 +27,13 @@ const int FunctionPin9 = 12;
const int FunctionPin10 = 13; const int FunctionPin10 = 13;
const int FunctionPin11 = 14; //A0 const int FunctionPin11 = 14; //A0
const int FunctionPin12 = 15; //A1 const int FunctionPin12 = 15; //A1
const int FunctionPin13 = 16; //A2 const int FunctionPin13 = 16; //A2
const int FunctionPin14 = 17; //A3 const int FunctionPin14 = 17; //A3
const int FunctionPin15 = 18; //A4 const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5 const int FunctionPin16 = 19; //A5
NmraDcc Dcc ; NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
#define This_Decoder_Address 17
struct CVPair struct CVPair
{ {
@@ -39,14 +41,25 @@ struct CVPair
uint8_t Value; uint8_t Value;
}; };
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
#define This_Decoder_Address 24
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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() void notifyCVResetFactoryDefault()
{ {
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
@@ -74,9 +87,19 @@ void setup()
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 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
{
for (int j=0; j < FactoryDefaultCVIndex; j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
digitalWrite(13, 1); //Blink the on board LED
delay (1000);
digitalWrite(13, 0);
}
} }
void loop() void loop()
{ {
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
@@ -93,32 +116,32 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
switch(FuncGrp) switch(FuncGrp)
{ {
case FN_0_4: case FN_0_4:
digitalWrite( FunctionPin0, (FuncState & FN_BIT_00) ); digitalWrite( FunctionPin0, (FuncState & FN_BIT_00)>>4 );
digitalWrite( FunctionPin1, (FuncState & FN_BIT_01) ); digitalWrite( FunctionPin1, (FuncState & FN_BIT_01) );
digitalWrite( FunctionPin2, (FuncState & FN_BIT_02) ); digitalWrite( FunctionPin2, (FuncState & FN_BIT_02)>>1 );
digitalWrite( FunctionPin3, (FuncState & FN_BIT_03) ); digitalWrite( FunctionPin3, (FuncState & FN_BIT_03)>>2 );
digitalWrite( FunctionPin4, (FuncState & FN_BIT_04) ); digitalWrite( FunctionPin4, (FuncState & FN_BIT_03)>>3 );
break; break;
case FN_5_8: case FN_5_8:
digitalWrite( FunctionPin5, (FuncState & FN_BIT_05) ); digitalWrite( FunctionPin5, (FuncState & FN_BIT_05) );
digitalWrite( FunctionPin6, (FuncState & FN_BIT_06) ); digitalWrite( FunctionPin6, (FuncState & FN_BIT_06)>>1 );
digitalWrite( FunctionPin7, (FuncState & FN_BIT_07) ); digitalWrite( FunctionPin7, (FuncState & FN_BIT_07)>>2 );
digitalWrite( FunctionPin8, (FuncState & FN_BIT_08) ); digitalWrite( FunctionPin8, (FuncState & FN_BIT_08)>>3 );
break; break;
case FN_9_12: case FN_9_12:
digitalWrite( FunctionPin9, (FuncState & FN_BIT_09) ); digitalWrite( FunctionPin9, (FuncState & FN_BIT_09) );
digitalWrite( FunctionPin10, (FuncState & FN_BIT_10) ); digitalWrite( FunctionPin10, (FuncState & FN_BIT_10)>>1 );
digitalWrite( FunctionPin11, (FuncState & FN_BIT_11) ); digitalWrite( FunctionPin11, (FuncState & FN_BIT_11)>>2 );
digitalWrite( FunctionPin12, (FuncState & FN_BIT_12) ); digitalWrite( FunctionPin12, (FuncState & FN_BIT_12)>>3 );
break; break;
case FN_13_20: case FN_13_20:
digitalWrite( FunctionPin13, (FuncState & FN_BIT_13) ); digitalWrite( FunctionPin13, (FuncState & FN_BIT_13) );
digitalWrite( FunctionPin14, (FuncState & FN_BIT_14) ); digitalWrite( FunctionPin14, (FuncState & FN_BIT_14)>>1 );
digitalWrite( FunctionPin15, (FuncState & FN_BIT_15) ); digitalWrite( FunctionPin15, (FuncState & FN_BIT_15)>>2 );
digitalWrite( FunctionPin16, (FuncState & FN_BIT_16) ); digitalWrite( FunctionPin16, (FuncState & FN_BIT_16)>>3 );
break; break;
case FN_21_28: case FN_21_28:

View File

@@ -0,0 +1,502 @@
// 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
// ******** 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>
SoftwareServo servo[17];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 & LOAD ACK
const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5
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[16];
struct CVPair
{
uint16_t CV;
uint8_t Value;
};
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] =
{
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address},
// 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
{33, 8}, //F0 End Position F0=1
{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
{38, 8}, // End Position Fx=1
{39, 1}, // Current Position
{40, 4}, //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, 4}, //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, 4}, //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, 28}, // Start Position Fx=0
{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
{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, 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, 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, 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, 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, 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, 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=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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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, 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 < numfpins; 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: // 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(3);
for (int i=0; i < numfpins; 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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
}
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
#ifdef DEBUG
Serial.print("Addr= ");
Serial.println(Addr, DEC) ;
Serial.print("FuncState= ");
Serial.println(FuncState, DEC) ;
#endif
switch(FuncGrp)
{
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 );
exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01));
exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1);
exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 );
exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 );
break;
case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05));
exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 );
exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 );
exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 );
break;
case FN_9_12:
exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09));
exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 );
exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 );
exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 );
break;
case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control
exec_function( 13, FunctionPin13, (FuncState & FN_BIT_13));
exec_function( 14, FunctionPin14, (FuncState & FN_BIT_14)>>1 );
exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 );
exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 );
break;
case FN_21_28:
break;
}
}
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View File

@@ -0,0 +1,619 @@
// 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
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo[13];
#define servo_start_delay 50
#define servo_init_delay 7
#define servo_slowdown 12 //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 = 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
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
{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, 28}, // Start Position Fx=0
{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
{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, 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
{89, 1}, // Current Position
{90, 2}, //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, 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
{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);
}
for (int i=8; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay);
}
delay( tim_delay);
for (int i=8; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
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, 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: // 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: // 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) {
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}

View 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 ();
*/

View 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 ();
*/

View File

@@ -1,34 +1,25 @@
// Production 17 Function DCC Decoder // Production 17 Function DCC Decoder Dec_7Serv_10LED_6Ftn.ino
// Version 3.0 Geoff Bunza 2014 // Version 6.01 Geoff Bunza 2014,2015,2016
// Uses modified software servo Lib // NO LONGER REQUIRES modified software servo Lib
// // Software restructuring mods added from Alex Shepherd and Franz-Peter
// With sincere thanks
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
#define DEBUG
#include <NmraDcc.h> #include <NmraDcc.h>
#include <SoftwareServo.h> #include <SoftwareServo.h>
SoftwareServo servo0; SoftwareServo servo[17];
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50 #define servo_start_delay 50
#define servo_init_delay 7 #define servo_init_delay 7
#define servo_slowdown 12 //servo loop counter limit
int servo_slow_counter = 0; //servo loop counter to slowdown servo transit
int tim_delay = 500; int tim_delay = 500;
int numfpins = 17; int numfpins = 17;
@@ -57,7 +48,6 @@ NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120; uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp int t; // temp
#define This_Decoder_Address 24
struct QUEUE struct QUEUE
{ {
int inuse; int inuse;
@@ -73,100 +63,110 @@ struct CVPair
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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_DECODER_MASTER_RESET, 0},
{30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
{32, 28}, //F0 Start Position F0=0 {32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1 {33, 140}, //F0 End Position F0=1
{34, 28}, //F0 Current Position {34, 28}, //F0 Current Position
{35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {35, 2}, //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 {36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0 {37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1 {38, 140}, // End Position Fx=1
{39, 28}, // Current Position {39, 28}, // Current Position
{40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0 {42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1 {43, 140}, // End Position Fx=1
{44, 28}, // Current Position {44, 28}, // Current Position
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0 {47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1 {48, 140}, // End Position Fx=1
{49, 28}, // Current Position {49, 28}, // Current Position
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate {51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0 {52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1 {53, 140}, // End Position Fx=1
{54, 28}, // Current Position {54, 28}, // Current Position
{55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {55, 2}, //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 {56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 28}, // Start Position Fx=0 {57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1 {58, 140}, // End Position Fx=1
{59, 28}, // Current Position {59, 28}, // Current Position
{60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {60, 2}, //F6 Config 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 {61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0 {62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1 {63, 140}, // End Position Fx=1
{64, 28}, // Current Position {64, 28}, // Current Position
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 1}, // Start Position Fx=0 {67, 1}, // Start Position Fx=0
{68,35}, // End Position Fx=1 {68,35}, // End Position Fx=1
{69, 1}, // Current Position {69, 1}, // Current Position
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{72, 1}, // Start Position Fx=0 {72, 1}, // Start Position Fx=0
{73, 100}, // End Position Fx=1 {73, 100}, // End Position Fx=1
{74, 1}, // Current Position {74, 1}, // Current Position
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{77, 1}, // Start Position Fx=0 {77, 1}, // Start Position Fx=0
{78, 10}, // End Position Fx=1 {78, 10}, // End Position Fx=1
{79, 1}, // Current Position {79, 1}, // Current Position
{80, 0}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {81, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{82, 1}, // Start Position Fx=0 {82, 1}, // Start Position Fx=0
{83, 5}, // End Position Fx=1 {83, 5}, // End Position Fx=1
{84, 1}, // Current Position {84, 1}, // Current Position
{85, 0}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {86, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{87, 1}, // Start Position Fx=0 {87, 1}, // Start Position Fx=0
{88, 5}, // End Position Fx=1 {88, 50}, // End Position Fx=1
{89, 1}, // Current Position {89, 1}, // Current Position
{90, 0}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0 {92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1 {93, 100}, // End Position Fx=1
{94, 1}, // Current Position {94, 1}, // Current Position
{95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0 {97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1 {98, 200}, // End Position Fx=1
{99, 2}, // Current Position {99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0 {102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1 {103, 200}, // End Position Fx=1
{104, 1}, // Current Position {104, 1}, // Current Position
{105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0 {107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1 {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=Double LED Blink {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 {111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position Fx=0 {112, 1}, // Start Position Fx=0
{113, 4}, // End Position Fx=1 {113, 4}, // End Position Fx=1
{114, 1}, // Current Position {114, 1}, // Current Position
//FUTURE USE //FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink {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 {116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position Fx=0 {117, 28}, // Start Position Fx=0
{118, 50}, // End Position Fx=1 {118, 50}, // End Position Fx=1
@@ -183,9 +183,11 @@ void notifyCVResetFactoryDefault()
void setup() //****************************************************** void setup() //******************************************************
{ {
#ifdef DEBUG
Serial.begin(115200);
#endif
int i; int i;
uint8_t cv_value; uint8_t cv_value;
//Serial.begin(115200);
// initialize the digital pins as outputs // initialize the digital pins as outputs
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
pinMode(fpins[i], OUTPUT); pinMode(fpins[i], OUTPUT);
@@ -205,12 +207,12 @@ void setup() //******************************************************
// Setup which External Interrupt, the Pin it's associated with that we're using // Setup which External Interrupt, the Pin it's associated with that we're using
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
delay(800); delay(800);
#if defined(DECODER_LOADED) #if defined(DECODER_LOADED)
if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET ) if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif #endif
{ {
for (int j=0; j < FactoryDefaultCVIndex; j++ ) for (int j=0; j < FactoryDefaultCVIndex; j++ )
@@ -218,11 +220,13 @@ void setup() //******************************************************
digitalWrite(fpins[14], 1); digitalWrite(fpins[14], 1);
delay (1000); delay (1000);
digitalWrite(fpins[14], 0); digitalWrite(fpins[14], 0);
} }
for ( i=0; i < numfpins; i++) { for ( i=0; i < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ; cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: "); #ifdef DEBUG
//Serial.println(cv_value, DEC) ; Serial.print(" cv_value: ");
Serial.println(cv_value, DEC) ;
#endif
switch ( cv_value ) { switch ( cv_value ) {
case 0: // LED on/off case 0: // LED on/off
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
@@ -230,7 +234,7 @@ void setup() //******************************************************
case 1: // LED Blink case 1: // LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = int (char (Dcc.getCV( 31+(i*5))));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
@@ -238,105 +242,29 @@ void setup() //******************************************************
} }
break; break;
case 2: //servo case 2: //servo
{ ftn_queue[i].current_position =int (Dcc.getCV( 34+(i*5))); {
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].stop_value = int (Dcc.getCV( 33+(i*5)));
ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5))); ftn_queue[i].start_value = int (Dcc.getCV( 32+(i*5)));
ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5)))); ftn_queue[i].increment = -int (char (Dcc.getCV( 31+(i*5))));
switch ( i ) { // attaches servo on pin to the servo object
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object servo[i].attach(fpins[i]);
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value); #ifdef DEBUG
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} Serial.print("InitServo ID= ");
break; Serial.println(i, DEC) ;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object #endif
ftn_queue[i].inuse = 1; servo[i].write(ftn_queue[i].start_value);
servo1.write(ftn_queue[i].start_value); for (t=0; t<servo_start_delay; t++)
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);} {SoftwareServo::refresh();delay(servo_init_delay);}
break; ftn_queue[i].inuse = 0;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object servo[i].detach();
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
} }
break; break;
case 3: // DOUBLE ALTERNATING LED Blink case 3: // DOUBLE ALTERNATING LED Blink
{ {
ftn_queue[i].inuse = 0; ftn_queue[i].inuse = 0;
ftn_queue[i].current_position = 0; ftn_queue[i].current_position = 0;
ftn_queue[i].start_value = 0; ftn_queue[i].start_value = 0;
ftn_queue[i].increment = Dcc.getCV( 31+(i*5)); ftn_queue[i].increment = Dcc.getCV( 31+(i*5));
digitalWrite(fpins[i], 0); digitalWrite(fpins[i], 0);
@@ -344,29 +272,46 @@ void setup() //******************************************************
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))); ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5)));
} }
break; break;
case 4: // NEXT FEATURE to pin 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; break;
default: default:
break; break;
} }
} }
}
}
void loop() //********************************************************************** void loop() //**********************************************************************
{ {
//MUST call the NmraDcc.process() method frequently //MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation // from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
SoftwareServo::refresh(); SoftwareServo::refresh();
delay(8); delay(3);
for (int i=0; i < numfpins; i++) { for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) { if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) { switch (Dcc.getCV( 30+(i*5))) {
case 0: case 0:
break; break;
case 1: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -376,18 +321,30 @@ void loop() //****************************************************************
break; break;
case 2: case 2:
{ {
if (ftn_queue[i].increment > 0) { if (servo_slow_counter++ > servo_slowdown)
if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].current_position = ftn_queue[i].stop_value; ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
} if (ftn_queue[i].increment > 0) {
if (ftn_queue[i].increment < 0) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
if (ftn_queue[i].current_position < ftn_queue[i].start_value) ftn_queue[i].current_position = ftn_queue[i].stop_value;
ftn_queue[i].current_position = ftn_queue[i].start_value; ftn_queue[i].inuse = 0;
} servo[i].detach();
set_servo(i, ftn_queue[i].current_position); }
} }
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; break;
case 3: 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) { if (ftn_queue[i].current_position > ftn_queue[i].stop_value) {
ftn_queue[i].start_value = ~ftn_queue[i].start_value; ftn_queue[i].start_value = ~ftn_queue[i].start_value;
digitalWrite(fpins[i], ftn_queue[i].start_value); digitalWrite(fpins[i], ftn_queue[i].start_value);
@@ -397,10 +354,21 @@ void loop() //****************************************************************
} }
i++; i++;
break; break;
case 4: //FUTURE FUNCTION case 4: // Simple Pulsed Output based on saved Rate =10*Rate in Milliseconds
break; {
default: ftn_queue[i].inuse = 0;
break; 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;
} }
} }
} }
@@ -443,9 +411,8 @@ void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uin
} }
} }
void exec_function (int function, int pin, int FuncState) { void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink 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 case 0: // On - Off LED
//Serial.println("****************cv:0 ") ;
digitalWrite (pin, FuncState); digitalWrite (pin, FuncState);
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
break; break;
@@ -463,21 +430,14 @@ void exec_function (int function, int pin, int FuncState) {
} }
break; break;
case 2: // Servo case 2: // Servo
ftn_queue[function].inuse = 1; 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))); if (FuncState==1) ftn_queue[function].increment = char ( Dcc.getCV( 31+(function*5)));
else 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)); if (FuncState==1) ftn_queue[function].stop_value = Dcc.getCV( 33+(function*5));
else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5)); else ftn_queue[function].stop_value = Dcc.getCV( 32+(function*5));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
break; break;
case 3: // Blinking LED PAIR case 3: // Blinking LED PAIR
if ((ftn_queue[function].inuse==0) && (FuncState==1)) { if ((ftn_queue[function].inuse==0) && (FuncState==1)) {
@@ -494,51 +454,38 @@ void exec_function (int function, int pin, int FuncState) {
} }
} }
break; break;
case 4: // Future Function 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; ftn_queue[function].inuse = 0;
break; break;
default: default:
ftn_queue[function].inuse = 0; ftn_queue[function].inuse = 0;
break; break;
} }
} }
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,23 +1,28 @@
#include <NmraDcc.h> // Production 17 Function DCC Decoder Dec_Dir_and_Fade.ino
// Working 17 Function DCC Decoder DccAckPin not needed // Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
// LED control is dependent on direction of travel // 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 // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
#include <NmraDcc.h>
int tim_delay = 500; int tim_delay = 500;
#define numleds 17 #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 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: // 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 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 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 // 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 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 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
uint8_t Decoder_direction = 0; uint8_t Decoder_direction = DCC_DIR_FWD;
uint8_t Last_Decoder_direction = 0; uint8_t Last_Decoder_direction = 0;
int fade_time = 170; int fade_time = 170;
const int FunctionPin0 = 3; const int FunctionPin0 = 3;
@@ -42,19 +47,30 @@ const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5 const int FunctionPin16 = 19; //A5
NmraDcc Dcc ; NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
#define This_Decoder_Address 24
struct CVPair struct CVPair
{ {
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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 = 0;
void notifyCVResetFactoryDefault() void notifyCVResetFactoryDefault()
@@ -94,14 +110,13 @@ void setup()
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up // Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
Dcc.pin(0, 2, 0); Dcc.pin(0, 2, 0);
// Call the main DCC Init function to enable the DCC Receiver // Call the main DCC Init function to enable the DCC Receiver
Dcc.init( MAN_ID_DIY, 100, FLAGS_MY_ADDRESS_ONLY, 0 ); Dcc.init( MAN_ID_DIY, 601, FLAGS_MY_ADDRESS_ONLY, 0 );
} }
void loop() void loop()
{ {
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
} }
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) { void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
int f_index; int f_index;
switch (FuncGrp) { switch (FuncGrp) {
@@ -146,8 +161,7 @@ void exec_function (int f_index, int FuncState) {
Set_LED (f_index,false); Set_LED (f_index,false);
} }
} }
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION ForwardDir, DCC_SPEED_STEPS SpeedSteps ) {
void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed ) {
Last_Decoder_direction = Decoder_direction; Last_Decoder_direction = Decoder_direction;
Decoder_direction = ForwardDir; Decoder_direction = ForwardDir;
if ( Decoder_direction==Last_Decoder_direction) return; if ( Decoder_direction==Last_Decoder_direction) return;
@@ -199,4 +213,4 @@ void Switch_LED (int Function) {
} }
led_last_state[Function] = end_state; led_last_state[Function] = end_state;
} }

View File

@@ -1,13 +1,22 @@
#include <NmraDcc.h> // Production 17 Function DCC Decoder Dec_SMA12_LED_Groups.ino
// Working 12 Function DCC Decoder DccAckPin not needed // Version 6.01 Geoff Bunza 2014,2015,2016,2017,2018
// 5 pin Arbitrary Group Lighting Functions Set in 4-Function Groups // Now works with both short and long DCC Addesses
// With Fade On and Fade Off
// Rev 4 Geoff Bunza September 2015 // NO LONGER REQUIRES modified software servo Lib
// Software restructuring mods added from Alex Shepherd and Franz-Peter
// With sincere thanks
// ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP // ******** UNLESS YOU WANT ALL CV'S RESET UPON EVERY POWER UP
// ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!! // ******** AFTER THE INITIAL DECODER LOAD REMOVE THE "//" IN THE FOOLOWING LINE!!
//#define DECODER_LOADED //#define DECODER_LOADED
// ******** EMOVE THE "//" IN THE FOOLOWING LINE TO SEND DEBUGGING
// ******** INFO TO THE SERIAL MONITOR
//#define DEBUG
#include <NmraDcc.h>
int tim_delay = 500; int tim_delay = 500;
#define numleds 17 #define numleds 17
byte ledpins [] = {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};
byte FPins_Assigned [12][5] = { // This array defines the pins controlled by each function byte FPins_Assigned [12][5] = { // This array defines the pins controlled by each function
@@ -45,37 +54,49 @@ const int FunctionPin1 = 4;
const int FunctionPin2 = 5; const int FunctionPin2 = 5;
const int FunctionPin3 = 6; const int FunctionPin3 = 6;
const int FunctionPin4 = 7; const int FunctionPin4 = 7;
const int FunctionPin5 = 8; const int FunctionPin5 = 8;
const int FunctionPin6 = 9; const int FunctionPin6 = 9;
const int FunctionPin7 = 10; const int FunctionPin7 = 10;
const int FunctionPin8 = 11; const int FunctionPin8 = 11;
const int FunctionPin9 = 12; const int FunctionPin9 = 12;
const int FunctionPin10 = 13; const int FunctionPin10 = 13;
const int FunctionPin11 = 14; //A0 const int FunctionPin11 = 14; //A0
const int FunctionPin12 = 15; //A1 const int FunctionPin12 = 15; //A1
const int FunctionPin13 = 16; //A2 const int FunctionPin13 = 16; //A2
const int FunctionPin14 = 17; //A3 const int FunctionPin14 = 17; //A3
const int FunctionPin15 = 18; //A4 const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5 const int FunctionPin16 = 19; //A5
NmraDcc Dcc ; NmraDcc Dcc ;
DCC_MSG Packet ; DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
#define This_Decoder_Address 24
struct CVPair struct CVPair
{ {
uint16_t CV; uint16_t CV;
uint8_t Value; uint8_t Value;
}; };
#define This_Decoder_Address 24
CVPair FactoryDefaultCVs [] = CVPair FactoryDefaultCVs [] =
{ {
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address}, {CV_MULTIFUNCTION_PRIMARY_ADDRESS, This_Decoder_Address&0x7F },
{CV_ACCESSORY_DECODER_ADDRESS_MSB, 0},
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, 0}, // These two CVs define the Long DCC Address
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, 0}, {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() void notifyCVResetFactoryDefault()
{ {
// Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset // Make FactoryDefaultCVIndex non-zero and equal to num CV's to be reset
@@ -85,7 +106,9 @@ void notifyCVResetFactoryDefault()
void setup() void setup()
{ {
//Serial.begin(115200); #ifdef DEBUG
Serial.begin(115200);
#endif
// initialize the digital pins as an outputs // initialize the digital pins as an outputs
for (int i=0; i< numleds; i++) { for (int i=0; i< numleds; i++) {
pinMode(ledpins[i], OUTPUT); pinMode(ledpins[i], OUTPUT);
@@ -101,10 +124,14 @@ void setup()
delay (tim_delay/10); delay (tim_delay/10);
} }
delay( tim_delay); delay( tim_delay);
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
#if defined(DECODER_LOADED) 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 ) if ( Dcc.getCV(CV_DECODER_MASTER_RESET)== CV_DECODER_MASTER_RESET )
#endif #endif
{ {
for (int j=0; j < FactoryDefaultCVIndex; j++ ) for (int j=0; j < FactoryDefaultCVIndex; j++ )
Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value); Dcc.setCV( FactoryDefaultCVs[j].CV, FactoryDefaultCVs[j].Value);
@@ -112,17 +139,12 @@ void setup()
delay (1000); delay (1000);
digitalWrite(ledpins[14], 0); 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 );
} }
void loop() void loop()
{ {
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation // You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
Dcc.process(); Dcc.process();
} }
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) { void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
int f_index; int f_index;
switch (FuncGrp) { switch (FuncGrp) {
@@ -133,20 +155,17 @@ switch (FuncGrp) {
exec_function( 3, (FuncState & FN_BIT_03)>>2 ); exec_function( 3, (FuncState & FN_BIT_03)>>2 );
exec_function( 4, (FuncState & FN_BIT_04)>>3 ); exec_function( 4, (FuncState & FN_BIT_04)>>3 );
break; break;
case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8 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( 5, (FuncState & FN_BIT_05));
exec_function( 6, (FuncState & FN_BIT_06)>>1 ); exec_function( 6, (FuncState & FN_BIT_06)>>1 );
exec_function( 7, (FuncState & FN_BIT_07)>>2 ); exec_function( 7, (FuncState & FN_BIT_07)>>2 );
exec_function( 8, (FuncState & FN_BIT_08)>>3 ); exec_function( 8, (FuncState & FN_BIT_08)>>3 );
break; break;
case FN_9_12: case FN_9_12:
exec_function( 9, (FuncState & FN_BIT_09)); exec_function( 9, (FuncState & FN_BIT_09));
exec_function( 10,(FuncState & FN_BIT_10)>>1 ); exec_function( 10,(FuncState & FN_BIT_10)>>1 );
exec_function( 11,(FuncState & FN_BIT_11)>>2 ); exec_function( 11,(FuncState & FN_BIT_11)>>2 );
break; break;
} }
} }
void exec_function (int f_index, int FuncState) { void exec_function (int f_index, int FuncState) {
@@ -172,5 +191,3 @@ void exec_function (int f_index, int FuncState) {
Last_Function_State[f_index] = false; Last_Function_State[f_index] = false;
} }
} }

View 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;
}
}

View File

@@ -1,565 +0,0 @@
// Production 17 Function DCC Decoder
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 & LOAD ACK
const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
#define This_Decoder_Address 24
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;
};
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_DECODER_MASTER_RESET, 0},
{30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 28}, // Current Position
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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 = 95;
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);
};
void setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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 );
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 < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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].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 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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
break;
case 3: // DOUBLE ALTERNATING LED Blink
{
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);
digitalWrite(fpins[i+1], 0);
ftn_queue[i].stop_value = int(Dcc.getCV( 33+(i*5))) *10.;
}
break;
case 4: // 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 5: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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))) *10.;
}
break;
case 2:
{
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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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))) *10.;
}
i++;
break;
case 4: // Fade On
break;
case 5: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
if (FuncNum==1) { //Function Group 1 F0 F4 F3 F2 F1
exec_function( 0, FunctionPin0, (FuncState&0x10)>>4 );
exec_function( 1, FunctionPin1, (FuncState&0x01 ));
exec_function( 2, FunctionPin2, (FuncState&0x02)>>1 );
exec_function( 3, FunctionPin3, (FuncState&0x04)>>2 );
exec_function( 4, FunctionPin4, (FuncState&0x08)>>3 );
}
else if (FuncNum==2) { //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
if ((FuncState & 0x10)==0x10) {
exec_function( 5, FunctionPin5, (FuncState&0x01 ));
exec_function( 6, FunctionPin6, (FuncState&0x02)>>1 );
exec_function( 7, FunctionPin7, (FuncState&0x04)>>2 );
exec_function( 8, FunctionPin8, (FuncState&0x08)>>3 );
}
else {
exec_function( 9, FunctionPin9, (FuncState&0x01 ));
exec_function( 10, FunctionPin10, (FuncState&0x02)>>1 );
exec_function( 11, FunctionPin11, (FuncState&0x04)>>2 );
exec_function( 12, FunctionPin12, (FuncState&0x08)>>3 );
}
}
else if (FuncNum==3) { //Function Group 2 FuncState == F20-F13 Function Control
exec_function( 13, FunctionPin13, (FuncState&0x01 ));
exec_function( 14, FunctionPin14, (FuncState&0x02)>>1 );
exec_function( 15, FunctionPin15, (FuncState&0x04)>>2 );
exec_function( 16, FunctionPin16, (FuncState&0x08)>>3 );
}
}
void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
case 0: // On - Off LED
//Serial.println("****************cv:0 ") ;
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(fpins[function], 0);
ftn_queue[function].stop_value = int(Dcc.getCV( 33+(function*5))) *10.;
} else {
if ((ftn_queue[function].inuse==1) && (FuncState==0)) {
ftn_queue[function].inuse = 0;
digitalWrite(fpins[function], 0);
}
}
break;
case 2: // Servo
ftn_queue[function].inuse = 1;
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));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
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))) *10.;
} else {
if (FuncState==0) {
ftn_queue[function].inuse = 0;
digitalWrite(fpins[function], 0);
digitalWrite(fpins[function+1], 0);
}
}
break;
case 4: // 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 5: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,566 +0,0 @@
// Production 17 Function DCC Decoder
// Version 3.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// This configuration supports 5 Modes per pin:
// 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
// It is recommended that you NOT MIX pulsed and servo control
// simultaneously as the servo timing will be off
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 & LOAD ACK
const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
#define This_Decoder_Address 24
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;
};
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_DECODER_MASTER_RESET, 0},
{30, 4}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{31, 10}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{32, 28}, //F0 Start Position F0=0
{33, 140}, //F0 End Position F0=1
{34, 0}, //F0 Current Position
{35, 4}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{36, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 0}, // Current Position
{40, 4}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{41, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 0}, // Current Position
{45, 4}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{46, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 0}, // Current Position
{50, 4}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{51, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 0}, // Current Position
{55, 4}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{56, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{57, 28}, // Start Position Fx=0
{58, 140}, // End Position Fx=1
{59, 0}, // Current Position
{60, 4}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{61, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 0}, // Current Position
{65, 4}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{66, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{67, 1}, // Start Position Fx=0
{68,35}, // End Position Fx=1
{69, 0}, // Current Position
{70, 4}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{71, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{72, 1}, // Start Position Fx=0
{73, 100}, // End Position Fx=1
{74, 0}, // Current Position
{75, 4}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{76, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{77, 1}, // Start Position Fx=0
{78, 10}, // End Position Fx=1
{79, 0}, // Current Position
{80, 4}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{81, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{82, 1}, // Start Position Fx=0
{83, 5}, // End Position Fx=1
{84, 0}, // Current Position
{85, 4}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{86, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{87, 1}, // Start Position Fx=0
{88, 5}, // End Position Fx=1
{89, 0}, // Current Position
{90, 4}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{91, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 0}, // Current Position
{95, 4}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{96, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1
{99, 0}, // Current Position
{100, 4}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{101, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 0}, // Current Position
{105, 4}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{106, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{107, 1}, // Start Position Fx=0
{108, 60}, // End Position Fx=1
{109, 0}, // Current Position
{110, 4}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{111, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{112, 1}, // Start Position Fx=0
{113, 4}, // End Position Fx=1
{114, 0}, // Current Position
//FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink,4=Pulsed
{116, 10}, // Rate Blink=Eate,PWM=Rate,Servo=Rate,Pulsed=Milliseconds/10
{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);
};
void setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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 );
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 < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: //FUTURE FUNCTION
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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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
break;
case 5: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
switch(FuncGrp)
{
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 );
exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01));
exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1);
exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 );
exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 );
break;
case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05));
exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 );
exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 );
exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 );
break;
case FN_9_12:
exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09));
exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 );
exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 );
exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 );
break;
case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control
exec_function( 13, FunctionPin13, (FuncState & FN_BIT_13));
exec_function( 14, FunctionPin14, (FuncState & FN_BIT_14)>>1 );
exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 );
exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 );
break;
case FN_21_28:
break;
}
}
void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
case 0: // On - Off LED
//Serial.println("****************cv:0 ") ;
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
ftn_queue[function].inuse = 1;
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));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,672 +0,0 @@
// Production Motor Drive 13 Pin Function DCC Decoder with Motor Drive
// F13 and F14 enable speed control of MOTOR1 and MOTOR2 respectively
// Version 5.0 Geoff Bunza 2015
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
#define servo_start_delay 50
#define servo_init_delay 7
uint8_t Motor1Speed = 0;
uint8_t Motor1ForwardDir = 1;
uint8_t Motor1MaxSpeed = 127;
uint8_t 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
int Function13_value = 0;
int Function14_value = 0;
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
#define This_Decoder_Address 24
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;
};
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_DECODER_MASTER_RESET, 0},
{30, 0}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{31, 1}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate
{32, 1}, //F0 Start Position F0=0
{33, 1}, //F0 End Position F0=1
{34, 10}, //F0 Current Position
{35, 0}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 1}, // Start Position Fx=0
{38, 1}, // End Position Fx=1
{39, 10}, // Current Position
{40, 0}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 1}, // Start Position Fx=0
{43, 10}, // End Position Fx=1
{44, 10}, // Current Position
{45, 0}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 1}, // Start Position Fx=0
{48, 1}, // End Position Fx=1
{49, 10}, // Current Position
{50, 0}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 1}, // Start Position Fx=0
{53, 1}, // End Position Fx=1
{54, 10}, // Current Position
{55, 0}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{56, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{57, 1}, // Start Position Fx=0
{58, 1}, // End Position Fx=1
{59, 10}, // Current Position
{60, 0}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 1}, // Start Position Fx=0
{63, 1}, // End Position Fx=1
{64, 10}, // Current Position
{65, 0}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{67, 1}, // Start Position Fx=0
{68, 1}, // End Position Fx=1
{69, 1}, // Current Position
{70, 0}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{72, 1}, // Start Position Fx=0
{73, 10}, // End Position Fx=1
{74, 1}, // Current Position
{75, 0}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{77, 1}, // Start Position Fx=0
{78, 10}, // End Position Fx=1
{79, 1}, // Current Position
{80, 2}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0
{93, 1}, // End Position Fx=1
{94, 28}, // Current Position
{95, 0}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0
{98, 28}, // End Position Fx=1
{99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 0}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{106, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{107, 1}, // Start Position Fx=0
{108, 1}, // End Position Fx=1
{109, 20}, // Current Position
{110, 0}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{111, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{112, 1}, // Start Position Fx=0
{113, 1}, // End Position Fx=1
{114, 1}, // Current Position
//FUTURE USE
{115, 0}, //F17 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{116, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{117, 28}, // Start Position Fx=0
{118, 140}, // 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);
};
void setup() //******************************************************
{
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);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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 );
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)) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // NEXT FEATURE to pin
break;
default:
break;
}
}
}
void loop() //**********************************************************************
{
boolean servo_on = true;
//MUST call the NmraDcc.process() method frequently
// from the Arduino loop() function for correct library operation
Dcc.process();
SoftwareServo::refresh();
delay(2);
if (Motor1Speed != 0) {
if (Motor1ForwardDir == 0) gofwd1 (fwdtime, int((Motor1Speed&0x7f)*21));
else gobwd1 (bwdtime, int((Motor1Speed&0x7f)*21));
}
if (Motor2Speed != 0) {
if (Motor2ForwardDir == 0) gofwd2 (fwdtime, int((Motor2Speed&0x7f)*21));
else gobwd2 (bwdtime, int((Motor2Speed&0x7f)*21));
}
//
for (int i=0; i < num_active_fpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
servo_on = true;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
servo_on = false;
detach_servo (i);
}
}
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;
servo_on = false;
detach_servo (i);
}
}
if (servo_on) {
set_servo(i, ftn_queue[i].current_position);
}
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
//
}
void gofwd1(int fcnt,int fcycle) {
int icnt;
int totcycle;
icnt = 0;
while (icnt < fcnt)
{
digitalWrite(m2h, HIGH); //Motor1
delayMicroseconds(fcycle);
digitalWrite(m2h, LOW); //Motor1
delayMicroseconds(cyclewidth - fcycle);
icnt++;
}
}
void gobwd1(int bcnt,int bcycle) {
int icnt;
icnt=0;
while (icnt < bcnt)
{
digitalWrite(m2l, HIGH); //Motor1
delayMicroseconds(bcycle);
digitalWrite(m2l, LOW); //Motor1
delayMicroseconds(cyclewidth - bcycle);
icnt++;
}
}
void gofwd2(int fcnt,int fcycle) {
int icnt;
int totcycle;
icnt = 0;
while (icnt < fcnt)
{
digitalWrite(m0h, HIGH); //Motor2
delayMicroseconds(fcycle);
digitalWrite(m0h, LOW); //Motor2
delayMicroseconds(cyclewidth - fcycle);
icnt++;
}
}
void gobwd2(int bcnt,int bcycle) {
int icnt;
icnt=0;
while (icnt < bcnt)
{
digitalWrite(m0l, HIGH); //Motor2
delayMicroseconds(bcycle);
digitalWrite(m0l, LOW); //Motor2
delayMicroseconds(cyclewidth - bcycle);
icnt++;
}
}
void notifyDccSpeed( uint16_t Addr, uint8_t Speed, uint8_t ForwardDir, uint8_t MaxSpeed ) {
if (Function13_value==1) {
Motor1Speed = Speed;
Motor1ForwardDir = ForwardDir;
Motor1MaxSpeed = MaxSpeed;
}
if (Function14_value==1) {
Motor2Speed = Speed;
Motor2ForwardDir = ForwardDir;
Motor2MaxSpeed = MaxSpeed;
}
}
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
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=Double LED Blink
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
ftn_queue[function].inuse = 1;
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0:
if (servo0.attached()==0) servo0.attach(FunctionPin0);
servo0.write(servo_pos);
break;
case 1:
if (servo1.attached()==0) servo1.attach(FunctionPin1);
servo1.write(servo_pos);
break;
case 2:
if (servo2.attached()==0) servo2.attach(FunctionPin2);
servo2.write(servo_pos);
break;
case 3:
if (servo3.attached()==0) servo3.attach(FunctionPin3);
servo3.write(servo_pos);
break;
case 4:
if (servo4.attached()==0) servo4.attach(FunctionPin4);
servo4.write(servo_pos);
break;
case 5:
if (servo5.attached()==0) servo5.attach(FunctionPin5);
servo5.write(servo_pos);
break;
case 6:
if (servo6.attached()==0) servo6.attach(FunctionPin6);
servo6.write(servo_pos);
break;
case 7:
if (servo7.attached()==0) servo7.attach(FunctionPin7);
servo7.write(servo_pos);
break;
case 8:
if (servo8.attached()==0) servo8.attach(FunctionPin8);
servo8.write(servo_pos);
break;
case 9:
if (servo9.attached()==0) servo9.attach(FunctionPin9);
servo9.write(servo_pos);
break;
case 10:
if (servo10.attached()==0) servo10.attach(FunctionPin10);
servo10.write(servo_pos);
break;
case 11:
if (servo11.attached()==0) servo11.attach(FunctionPin11);
servo11.write(servo_pos);
break;
case 12:
if (servo12.attached()==0) servo12.attach(FunctionPin12);
servo12.write(servo_pos);
break;
default:
break;
}
}
void detach_servo (int servo_num) {
switch (servo_num) {
case 0:
if (servo0.attached()!=0) servo0.detach();
break;
case 1:
if (servo1.attached()!=0) servo1.detach();
break;
case 2:
if (servo2.attached()!=0) servo2.detach();
break;
case 3:
if (servo3.attached()!=0) servo3.detach();
break;
case 4:
if (servo4.attached()!=0) servo4.detach();
break;
case 5:
if (servo5.attached()!=0) servo5.detach();
break;
case 6:
if (servo6.attached()!=0) servo6.detach();
break;
case 7:
if (servo7.attached()!=0) servo7.detach();
break;
case 8:
if (servo8.attached()!=0) servo8.detach();
break;
case 9:
if (servo9.attached()!=0) servo9.detach();
break;
case 10:
if (servo10.attached()!=0) servo10.detach();
break;
case 11:
if (servo11.attached()!=0) servo11.detach();
break;
case 12:
if (servo12.attached()!=0) servo12.detach();
default:
break;
}
}

View File

@@ -1,544 +0,0 @@
// Production 17 Function DCC Decoder
// Version 3.0 Geoff Bunza 2014
// Uses modified software servo Lib
//
// ******** 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
#include <NmraDcc.h>
#include <SoftwareServo.h>
SoftwareServo servo0;
SoftwareServo servo1;
SoftwareServo servo2;
SoftwareServo servo3;
SoftwareServo servo4;
SoftwareServo servo5;
SoftwareServo servo6;
SoftwareServo servo7;
SoftwareServo servo8;
SoftwareServo servo9;
SoftwareServo servo10;
SoftwareServo servo11;
SoftwareServo servo12;
SoftwareServo servo13;
SoftwareServo servo14;
SoftwareServo servo15;
SoftwareServo servo16;
#define servo_start_delay 50
#define servo_init_delay 7
int tim_delay = 500;
int numfpins = 17;
byte fpins [] = {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;
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 & LOAD ACK
const int FunctionPin15 = 18; //A4
const int FunctionPin16 = 19; //A5
NmraDcc Dcc ;
DCC_MSG Packet ;
uint8_t CV_DECODER_MASTER_RESET = 120;
int t; // temp
#define This_Decoder_Address 24
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;
};
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_DECODER_MASTER_RESET, 0},
{30, 2}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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
{35, 2}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{36, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{37, 28}, // Start Position Fx=0
{38, 140}, // End Position Fx=1
{39, 28}, // Current Position
{40, 2}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{41, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{42, 28}, // Start Position Fx=0
{43, 140}, // End Position Fx=1
{44, 28}, // Current Position
{45, 2}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{46, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{47, 28}, // Start Position Fx=0
{48, 140}, // End Position Fx=1
{49, 28}, // Current Position
{50, 2}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{51, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{52, 28}, // Start Position Fx=0
{53, 140}, // End Position Fx=1
{54, 28}, // Current Position
{55, 2}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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, 2}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{61, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{62, 28}, // Start Position Fx=0
{63, 140}, // End Position Fx=1
{64, 28}, // Current Position
{65, 1}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{66, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{71, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{76, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{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=Double LED Blink
{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=Double LED Blink
{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, 1}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{91, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{92, 1}, // Start Position Fx=0
{93, 20}, // End Position Fx=1
{94, 1}, // Current Position
{95, 3}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{96, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{97, 1}, // Start Position Fx=0
{98, 35}, // End Position Fx=1
{99, 2}, // Current Position
{100, 0}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{101, 1}, // Rate Blink=Eate,PWM=Rate,Servo=Rate
{102, 1}, // Start Position Fx=0
{103, 4}, // End Position Fx=1
{104, 1}, // Current Position
{105, 3}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
{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=Double LED Blink
{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=Double LED Blink
{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);
};
void setup() //******************************************************
{
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);
digitalWrite(fpins[i], 0);
}
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 1);
delay (tim_delay/10);
}
delay( tim_delay);
for (int i=0; i < numfpins; i++) {
digitalWrite(fpins[i], 0);
delay (tim_delay/10);
}
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 );
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 < numfpins; i++) {
cv_value = Dcc.getCV( 30+(i*5)) ;
//Serial.print(" cv_value: ");
//Serial.println(cv_value, DEC) ;
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))));
switch ( i ) {
case 0: servo0.attach(FunctionPin0); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo0.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 1: servo1.attach(FunctionPin1); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo1.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 2: servo2.attach(FunctionPin2); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo2.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 3: servo3.attach(FunctionPin3); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo3.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 4: servo4.attach(FunctionPin4); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo4.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 5: servo5.attach(FunctionPin5); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo5.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 6: servo6.attach(FunctionPin6); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo6.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 7: servo7.attach(FunctionPin7); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo7.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 8: servo8.attach(FunctionPin8); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo8.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 9: servo9.attach(FunctionPin9); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo9.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 10: servo10.attach(FunctionPin10); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo10.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 11: servo11.attach(FunctionPin11); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo11.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 12: servo12.attach(FunctionPin12); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo12.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 13: servo13.attach(FunctionPin13); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo13.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 14: servo14.attach(FunctionPin14); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo14.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 15: servo15.attach(FunctionPin15); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo15.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
case 16: servo16.attach(FunctionPin16); // attaches servo on pin to the servo object
ftn_queue[i].inuse = 1;
servo16.write(ftn_queue[i].start_value);
for (t=0; t<servo_start_delay; t++) {SoftwareServo::refresh();delay(servo_init_delay);}
break;
default:
break;
}
}
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: // 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(8);
for (int i=0; i < numfpins; i++) {
if (ftn_queue[i].inuse==1) {
ftn_queue[i].current_position = ftn_queue[i].current_position + ftn_queue[i].increment;
switch (Dcc.getCV( 30+(i*5))) {
case 0:
break;
case 1:
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 (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;
}
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;
}
set_servo(i, ftn_queue[i].current_position);
}
break;
case 3:
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: //FUTURE FUNCTION
break;
default:
break;
}
}
}
}
void notifyDccFunc( uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState) {
switch(FuncGrp)
{
case FN_0_4: //Function Group 1 F0 F4 F3 F2 F1
exec_function( 0, FunctionPin0, (FuncState & FN_BIT_00)>>4 );
exec_function( 1, FunctionPin1, (FuncState & FN_BIT_01));
exec_function( 2, FunctionPin2, (FuncState & FN_BIT_02)>>1);
exec_function( 3, FunctionPin3, (FuncState & FN_BIT_03)>>2 );
exec_function( 4, FunctionPin4, (FuncState & FN_BIT_04)>>3 );
break;
case FN_5_8: //Function Group 1 S FFFF == 1 F8 F7 F6 F5 & == 0 F12 F11 F10 F9 F8
exec_function( 5, FunctionPin5, (FuncState & FN_BIT_05));
exec_function( 6, FunctionPin6, (FuncState & FN_BIT_06)>>1 );
exec_function( 7, FunctionPin7, (FuncState & FN_BIT_07)>>2 );
exec_function( 8, FunctionPin8, (FuncState & FN_BIT_08)>>3 );
break;
case FN_9_12:
exec_function( 9, FunctionPin9, (FuncState & FN_BIT_09));
exec_function( 10, FunctionPin10, (FuncState & FN_BIT_10)>>1 );
exec_function( 11, FunctionPin11, (FuncState & FN_BIT_11)>>2 );
exec_function( 12, FunctionPin12, (FuncState & FN_BIT_12)>>3 );
break;
case FN_13_20: //Function Group 2 FuncState == F20-F13 Function Control
exec_function( 13, FunctionPin13, (FuncState & FN_BIT_13));
exec_function( 14, FunctionPin14, (FuncState & FN_BIT_14)>>1 );
exec_function( 15, FunctionPin15, (FuncState & FN_BIT_15)>>2 );
exec_function( 16, FunctionPin16, (FuncState & FN_BIT_16)>>3 );
break;
case FN_21_28:
break;
}
}
void exec_function (int function, int pin, int FuncState) {
switch ( Dcc.getCV( 30+(function*5)) ) { // Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink
case 0: // On - Off LED
//Serial.println("****************cv:0 ") ;
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
ftn_queue[function].inuse = 1;
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));
/*
Serial.print("servo inc: ") ;
Serial.print(ftn_queue[function].increment,DEC) ;
Serial.print("servo inuse: ") ;
Serial.print(ftn_queue[function].inuse,DEC) ;
Serial.print("servo num: ") ;
Serial.print(function,DEC) ;
Serial.print(" stop: ");
Serial.println(ftn_queue[function].stop_value,DEC) ;
*/
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: // Future Function
ftn_queue[function].inuse = 0;
break;
default:
ftn_queue[function].inuse = 0;
break;
}
}
void set_servo (int servo_num, int servo_pos) {
switch (servo_num) {
case 0: servo0.write(servo_pos);
break;
case 1: servo1.write(servo_pos);
break;
case 2: servo2.write(servo_pos);
break;
case 3: servo3.write(servo_pos);
break;
case 4: servo4.write(servo_pos);
break;
case 5: servo5.write(servo_pos);
break;
case 6: servo6.write(servo_pos);
break;
case 7: servo7.write(servo_pos);
break;
case 8: servo8.write(servo_pos);
break;
case 9: servo9.write(servo_pos);
break;
case 10: servo10.write(servo_pos);
break;
case 11: servo11.write(servo_pos);
break;
case 12: servo12.write(servo_pos);
break;
case 13: servo13.write(servo_pos);
break;
case 14: servo14.write(servo_pos);
break;
case 15: servo15.write(servo_pos);
break;
case 16: servo16.write(servo_pos);
break;
default:
break;
}
}

View File

@@ -1,12 +1,13 @@
{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fswiss\fprq2\fcharset0 Calibri;}} {\rtf1\ansi\ansicpg1252\deff0\nouicompat\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 {\*\generator Riched20 10.0.10586}\viewkind4\uc1
\pard\sl276\slmult1\b\f0\fs24 Decoder Configuration Details\par
\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 \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 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 The decoder address can be changed to another \ul\b short\ulnone\b0 DCC address by changing CV 1.\par
\par \par
\b The 7 Servo 10 LED decoder configuration\par \b Example Only: 7 Servo 10 LED decoder configuration\par
\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 \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 \ul\b Pro Mini Pin\ulnone\b0\tab \ul\b Function\par
@@ -33,87 +34,87 @@ Correspondingly by way of example, for the 7 Servo 10 LED decoder configuration,
\par \par
\ul\b\{CV number, Value\} Description\par \ul\b\{CV number, Value\} Description\par
\ulnone\b0 \{1, 24\} Decoder Initial Address\par \ulnone\b0 \{1, 24\} Decoder Initial Address\par
\{30, 2\}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{30, 2\}, //F0 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{31, 1\}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{31, 1\}, //F0 Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{32, 28\}, //F0 Start Position F0=0\par \{32, 28\}, //F0 Start Position F0=0\par
\{33, 140\}, //F0 End Position F0=1\par \{33, 140\}, //F0 End Position F0=1\par
\{34, 28\}, //F0 Current Position\par \{34, 28\}, //F0 Current Position\par
\{35, 2\}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{35, 2\}, //F1 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{36, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{36, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{37, 28\}, // Start Position Fx=0\par \{37, 28\}, // Start Position Fx=0\par
\{38, 140\}, // End Position Fx=1\par \{38, 140\}, // End Position Fx=1\par
\{39, 28\}, // Current Position\par \{39, 28\}, // Current Position\par
\{40, 2\}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{40, 2\}, //F2 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{41, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{41, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{42, 28\}, // Start Position Fx=0\par \{42, 28\}, // Start Position Fx=0\par
\{43, 140\}, // End Position Fx=1\par \{43, 140\}, // End Position Fx=1\par
\{44, 28\}, // Current Position\par \{44, 28\}, // Current Position\par
\{45, 2\}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{45, 2\}, //F3 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{46, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{46, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{47, 28\}, // Start Position Fx=0\par \{47, 28\}, // Start Position Fx=0\par
\{48, 140\}, // End Position Fx=1\par \{48, 140\}, // End Position Fx=1\par
\{49, 28\}, // Current Position\par \{49, 28\}, // Current Position\par
\{50, 2\}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{50, 2\}, //F4 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{51, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{51, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{52, 28\}, // Start Position Fx=0\par \{52, 28\}, // Start Position Fx=0\par
\{53, 140\}, // End Position Fx=1\par \{53, 140\}, // End Position Fx=1\par
\{54, 28\}, // Current Position\par \{54, 28\}, // Current Position\par
\{55, 2\}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{55, 2\}, //F5 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{56, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{56, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{57, 28\}, // Start Position Fx=0\par \{57, 28\}, // Start Position Fx=0\par
\{58, 140\}, // End Position Fx=1\par \{58, 140\}, // End Position Fx=1\par
\{59, 28\}, // Current Position\par \{59, 28\}, // Current Position\par
\{60, 2\}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{60, 2\}, //F6 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{61, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{61, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{62, 28\}, // Start Position Fx=0\par \{62, 28\}, // Start Position Fx=0\par
\{63, 140\}, // End Position Fx=1\par \{63, 140\}, // End Position Fx=1\par
\{64, 28\}, // Current Position\par \{64, 28\}, // Current Position\par
\{65, 1\}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{65, 1\}, //F7 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{66, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{66, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{67, 1\}, // Start Position Fx=0\par \{67, 1\}, // Start Position Fx=0\par
\{68,35\}, // End Position Fx=1\par \{68,35\}, // End Position Fx=1\par
\{69, 1\}, // Current Position\par \{69, 1\}, // Current Position\par
\{70, 1\}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{70, 1\}, //F8 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{71, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{71, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{72, 1\}, // Start Position Fx=0\par \{72, 1\}, // Start Position Fx=0\par
\{73, 100\}, // End Position Fx=1\par \{73, 100\}, // End Position Fx=1\par
\{74, 1\}, // Current Position\par \{74, 1\}, // Current Position\par
\{75, 0\}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{75, 0\}, //F9 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{76, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{76, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{77, 1\}, // Start Position Fx=0\par \{77, 1\}, // Start Position Fx=0\par
\{78, 10\}, // End Position Fx=1\par \{78, 10\}, // End Position Fx=1\par
\{79, 1\}, // Current Position\par \{79, 1\}, // Current Position\par
\{80, 0\}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{80, 0\}, //F10 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{81, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{81, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{82, 1\}, // Start Position Fx=0\par \{82, 1\}, // Start Position Fx=0\par
\{83, 5\}, // End Position Fx=1\par \{83, 5\}, // End Position Fx=1\par
\{84, 1\}, // Current Position\par \{84, 1\}, // Current Position\par
\{85, 1\}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{85, 1\}, //F11 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{86, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{86, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{87, 1\}, // Start Position Fx=0\par \{87, 1\}, // Start Position Fx=0\par
\{88, 5\}, // End Position Fx=1\par \{88, 5\}, // End Position Fx=1\par
\{89, 1\}, // Current Position\par \{89, 1\}, // Current Position\par
\{90, 1\}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{90, 1\}, //F12 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{91, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{91, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{92, 1\}, // Start Position Fx=0\par \{92, 1\}, // Start Position Fx=0\par
\{93, 20\}, // End Position Fx=1\par \{93, 20\}, // End Position Fx=1\par
\{94, 1\}, // Current Position\par \{94, 1\}, // Current Position\par
\{95, 3\}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{95, 3\}, //F13 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{96, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{96, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{97, 1\}, // Start Position Fx=0\par \{97, 1\}, // Start Position Fx=0\par
\{98, 35\}, // End Position Fx=1\par \{98, 35\}, // End Position Fx=1\par
\{99, 2\}, // Current Position\par \{99, 2\}, // Current Position\par
\{100, 0\}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{100, 0\}, //F14 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{101, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{101, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{102, 1\}, // Start Position Fx=0\par \{102, 1\}, // Start Position Fx=0\par
\{103, 4\}, // End Position Fx=1\par \{103, 4\}, // End Position Fx=1\par
\{104, 1\}, // Current Position\par \{104, 1\}, // Current Position\par
\{105, 3\}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{105, 3\}, //F15 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{106, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{106, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{107, 1\}, // Start Position Fx=0\par \{107, 1\}, // Start Position Fx=0\par
\{108, 60\}, // End Position Fx=1\par \{108, 60\}, // End Position Fx=1\par
\{109, 20\}, // Current Position\par \{109, 20\}, // Current Position\par
\{110, 0\}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=Double LED Blink\par \{110, 0\}, //F16 Config 0=On/Off,1=Blink,2=Servo,3=DBL LED Blink,4=Pulsed,5=fade\par
\{111, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par \{111, 1\}, // Rate Blink=Eate,PWM=Rate,Servo=Rate\par
\{112, 1\}, // Start Position Fx=0\par \{112, 1\}, // Start Position Fx=0\par
\{113, 4\}, // End Position Fx=1\par \{113, 4\}, // End Position Fx=1\par
@@ -151,7 +152,8 @@ For example \b F0\b0 is initially set for \b servo\b0 control:\par
\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 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 \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 \pard\par
} }

Binary file not shown.

View File

@@ -6,57 +6,58 @@
# Datatypes (KEYWORD1) # Datatypes (KEYWORD1)
####################################### #######################################
DCC_MSG KEYWORD1 DCC_MSG KEYWORD1
NmraDcc KEYWORD1 NmraDcc KEYWORD1
####################################### #######################################
# Methods and Functions (KEYWORD2) # Methods and Functions (KEYWORD2)
####################################### #######################################
NmraDcc KEYWORD2 NmraDcc KEYWORD2
pin KEYWORD2 pin KEYWORD2
init KEYWORD2 init KEYWORD2
process KEYWORD2 process KEYWORD2
getCV KEYWORD2 getCV KEYWORD2
setCV KEYWORD2 setCV KEYWORD2
isSetCVReady KEYWORD2 isSetCVReady KEYWORD2
notifyDccReset KEYWORD2 notifyDccReset KEYWORD2
notifyDccIdle KEYWORD2 notifyDccIdle KEYWORD2
notifyDccSpeed KEYWORD2 notifyDccSpeed KEYWORD2
notifyDccSpeedRaw notifyDccSpeedRaw KEYWORD2
notifyDccFunc KEYWORD2 notifyDccFunc KEYWORD2
notifyDccAccState KEYWORD2 notifyDccAccTurnoutBoard KEYWORD2
notifyDccAccTurnoutBoard notifyDccAccTurnoutOutput KEYWORD2
notifyDccAccTurnoutOutput notifyDccAccBoardAddrSet KEYWORD2
notifyDccSigState KEYWORD2 notifyDccAccOutputAddrSet KEYWORD2
notifyDccMsg KEYWORD2 notifyDccSigOutputState KEYWORD2
notifyCVValid KEYWORD2 notifyDccMsg KEYWORD2
notifyCVRead KEYWORD2 notifyCVValid KEYWORD2
notifyCVWrite KEYWORD2 notifyCVRead KEYWORD2
notifyIsSetCVReady KEYWORD2 notifyCVWrite KEYWORD2
notifyCVChange KEYWORD2 notifyIsSetCVReady KEYWORD2
notifyCVAck KEYWORD2 notifyCVChange KEYWORD2
notifyCVResetFactoryDefault KEYWORD2 notifyCVAck KEYWORD2
notifyCVResetFactoryDefault KEYWORD2
####################################### #######################################
# Constants (LITERAL1) # Constants (LITERAL1)
MAN_ID_JMRI LITERAL1 MAN_ID_JMRI LITERAL1
MAN_ID_DIY LITERAL1 MAN_ID_DIY LITERAL1
MAN_ID_SILICON_RAILWAY LITERAL1 MAN_ID_SILICON_RAILWAY LITERAL1
FLAGS_MY_ADDRESS_ONLY LITERAL1 FLAGS_MY_ADDRESS_ONLY LITERAL1
FLAGS_OUTPUT_ADDRESS_MODE LITERAL1 FLAGS_OUTPUT_ADDRESS_MODE LITERAL1
FLAGS_DCC_ACCESSORY_DECODER LITERAL1 FLAGS_DCC_ACCESSORY_DECODER LITERAL1
CV_ACCESSORY_DECODER_ADDRESS_LSB LITERAL1 CV_ACCESSORY_DECODER_ADDRESS_LSB LITERAL1
CV_ACCESSORY_DECODER_ADDRESS_MSB LITERAL1 CV_ACCESSORY_DECODER_ADDRESS_MSB LITERAL1
CV_MULTIFUNCTION_PRIMARY_ADDRESS LITERAL1 CV_MULTIFUNCTION_PRIMARY_ADDRESS LITERAL1
CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB LITERAL1 CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB LITERAL1
CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB LITERAL1 CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB LITERAL1
CV_VERSION_ID LITERAL1 CV_VERSION_ID LITERAL1
CV_MANUFACTURER_ID LITERAL1 CV_MANUFACTURER_ID LITERAL1
CV_29_CONFIG LITERAL1 CV_29_CONFIG LITERAL1
CV_OPS_MODE_ADDRESS_LSB LITERAL1 CV_OPS_MODE_ADDRESS_LSB LITERAL1
####################################### #######################################

View File

@@ -1,9 +1,9 @@
name=NmraDcc name=NmraDcc
version=1.2.1 version=2.0.0
author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky author=Alex Shepherd, Wolfgang Kuffer, Geoff Bunza, Martin Pischky, Franz-Peter Müller, Sven (littleyoda)
maintainer=Alex Shepherd <kiwi64ajs@gmail.com> maintainer=Alex Shepherd <kiwi64ajs@gmail.com>
sentence=Enables NMRA DCC Communication sentence=Enables NMRA DCC Communication
paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library currently supports the AVR ATTiny84/85 & ATMega88/168/328/32u4 using the INT0/1 Hardware Interrupt and Timer0 Compare Match B paragraph=This library allows you to interface to a NMRA DCC track signal and receive DCC commands. The library has been tested on AVR ATTiny84/85 & ATMega88/168/328/32u4, ESP8266 and Teensy 3.x using the INT0/1 Hardware Interrupt and micros() ONLY and no longer uses Timer0 Compare Match B, which makes it much more portable to other platforms.
category=Communication category=Communication
url=http://mrrwa.org/dcc-decoder-interface/ url=https://github.com/mrrwa/NmraDcc
architectures=avr architectures=*