// ------------------------------------------------- effect control CVs ------------------------------------------------
#define cvMarsMin 54 // mars and gyralite effect minimum PWM
#define cvRandMin 55 // random flicker effect minimum PWM
#define cvMars 59 // mars and gyralite effect cycle time in 0.1s
#define cvFlash 60 // flashing effect:
// hundreds and tens - flasher cycle time in 0.2s
// 0x = 0.2s cycle (5 times per second)
// 1x = 0.4s cycle (2.5 times per second)
// 2x = 0.6s cycle (1.7 times per second)
// . . . . . . . .
// 24x = 5.0s cycle
// ones digit xx0 = 10% on time
// xx1 = 20% on time
// . . . . . . . .
// xx9 = 100% on time
#define cvStrobe 61 // strobe effect:
// hundreds digit - strobe flash duration in 0.035s
// 0xx = 0.035s
// 1xx = 0.070s
// 2xx = 0.105s
// tens digit - strobe cycle time in 0.2s
// x0x = 0.2s
// x1x = 0.4s
// . . . . . . . .
// x9x = 2.0s
// ones digit - pause between double strobes in 0.05s
// xx0 = 0.05s
// xx1 = 0.10s
// . . . . . . . .
// xx9 = 0.50s
#define cvBeacon 62 // rotary beacon cycle time in 0.1s
#define cvSoftSt 63 // soft start effect time in 0.1s
#define cvDitch 64 // ditch lights:
// hundreds digit - low PWM pause:
// 0xx = 10% of cycle time
// 1xx = 20% of cycle time
// tens digit - minimum PWM:
// x0x = 0% (completely off)
// x1x = 5%
// . . . . . . . .
// x9x = 42%
// ones digit - cycle time:
// xx0 = 0.5s
// xx1 = 0.6s
// . . . . . . . .
// xx9 = 1.4s
#define cvCoupler 115 // coupler settings:
// hundreds and tens - max PWM time in 0.2s:
// 0x = 0.0s
// 1x = 0.2s
// 2x = 0.4s
// . . . . . . . .
// 24x = 4.8s
// ones digit - holding PWM:
// xx0 = 0%
// xx1 = 10%
// . . . . . . . .
// xx9 = 90%
#define cvFadeIn 190 // fade-in effect time in 0.1s
#define cvFadeOut 191 // fade-out effect time in 0.1s
// --------------------------------------------------- available CVs ---------------------------------------------------
#define cv147Available 147 // available FUTURE IMPLEMENTATION
// to
#define cv154Available 154 // available FUTURE IMPLEMENTATION
#define cv192Available 192 // available FUTURE IMPLEMENTATION
// to
#define cv199Available 199 // available FUTURE IMPLEMENTATION
// ---------------------------------------------- function output PWM CVs ----------------------------------------------
#define cvF0fPwm 209 // F0f PWM
#define cvF0rPwm 210 // F0r PWM
#define cvFA1Pwm 211 // FA1 PWM
#define cvFA2Pwm 212 // FA2 PWM
#define cvFA3Pwm 213 // FA3 PWM
#define cvFA4Pwm 214 // FA4 PWM
#define cvFA5Pwm 215 // FA5 PWM
#define cvFA6Pwm 216 // FA6 PWM
#define cvFA7Pwm 217 // FA7 PWM
#define cvFA8Pwm 218 // FA8 PWM
#define cvFA9Pwm 219 // FA9 PWM
#define cvFA10Pwm 220 // FA10 PWM
#define cvFA11Pwm 221 // FA11 PWM
#define cvFA12Pwm 222 // FA12 PWM
#define cvFA13Pwm 223 // FA13 PWM
#define cvFA14Pwm 224 // FA14 PWM
// -------------------------------------- function output memory and polarity CVs --------------------------------------
#define cvMem 200 // function state storage; uses 8 bytes for 29 inputs:
// +0 to +3 contain function state masks set by user
// +4 to +7 store function states saved by firmware on state change
#define cvFAPolLo 225 // F0f - FA6 output polarity: 0 - active low; 1 - active high
#define cvFAPolHi 226 // FA7 - FA14 output polarity as described above
// --------------------------------------------------- available CVs ---------------------------------------------------
#define cv227Available 227 // available FUTURE IMPLEMENTATION
// to
#define cv249Available 249 // available FUTURE IMPLEMENTATION
// ----------------------------------------------------- other CVs -----------------------------------------------------
#define cvDump 256 // write any non-zero value to this CV to dump CV values to serial
struct cvPair {int cv; byte value;};
byte defsCVCnt = 0;
int setCVInd = 0;
byte setCVVal = 0;
unsigned long cvChangeMillis = 0;
int getCVInd = 0;
int marsStep = 1;
unsigned long marsMillis = 0;
byte marsMin = 32;
byte randMin = 32;
unsigned long flashOnMillis = 0;
unsigned long flashOffMillis = 0;
unsigned long strobeOnMillis = 0;
unsigned long strobeOffMillis = 0;
unsigned long strobe2Millis = 0;
int beaconStep = 1;
unsigned long beaconMillis = 0;
int ditchCounter = 0;
int ditchStep = 1;
unsigned long ditchMillis = 0;
unsigned long oldDitchMillis = 0;
byte ditchMin = 32;
byte ditchPause = 25;
byte ditchFlag = 0;
unsigned long couplerMillis = 0;
word couplerPwm = 0;
int softStStep = 1;
unsigned long softStMillis = 0;
int fadeInStep = 1;
int fadeOutStep = 1;
unsigned long fadeInMillis = 0;
unsigned long fadeOutMillis = 0;
unsigned long pwmMicros = 0; // PWM µs storage
byte pwmCounter = 0; // PWM counter
cvPair factoryDefaults[] = { // default CV values table
{cvShortAddress, defaultAddress},
{cvLongAddressHi, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(defaultLongAddress)},
{cvLongAddressLo, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(defaultLongAddress)},
{cvConfig1, 6}, {cvSub, mfrSubver}, {cvDef, 0},
{cvStartV, 1}, {cvMaxV, 1}, {cvMidV, 1}, {cvAccel, 5}, {cvDecel, 5},
{cvMotorFreq, 95}, {cvMotorPI, 55}, {cvMotorVref, 0}, {cvMotorBEMF, 255},
{cvMomReduction, 0}, {cvHalfSpeedKey, 0}, {cvMomentumKey, 0},
{cvF0f, 1}, {cvF0r, 2}, {cvF1, 4}, {cvF2, 8},
{cvF3, 16}, {cvF4, 32}, {cvF5, 64}, {cvF6, 128},
{cvF7, 0}, {cvF8, 0}, {cvF9, 0}, {cvF10, 0},
{cvF11, 0}, {cvF12, 0},
{cvF0fe, 0}, {cvF0re, 0}, {cvF1e, 0}, {cvF2e, 0},
{cvF3e, 0}, {cvF4e, 0}, {cvF5e, 0}, {cvF6e, 0},
{cvF7e, 1}, {cvF8e, 2}, {cvF9e, 4}, {cvF10e, 8},
{cvF11e, 0}, {cvF12e, 0},
{cvF0fEffect, 0}, {cvF0rEffect, 0}, {cvFA1Effect, 0}, {cvFA2Effect, 0},
{cvFA3Effect, 0}, {cvFA4Effect, 0}, {cvFA5Effect, 0}, {cvFA6Effect, 0},
{cvFA7Effect, 0}, {cvFA8Effect, 0}, {cvFA9Effect, 0}, {cvFA10Effect, 0},
{cvFA11Effect, 0}, {cvFA12Effect, 0}, {cvFA13Effect, 0}, {cvFA14Effect, 0},
{cvMarsMin, 32}, {cvRandMin, 32}, {cvMars, 15}, {cvFlash, 53},
{cvStrobe, 57}, {cvBeacon, 30}, {cvSoftSt, 15}, {cvDitch, 35},
{cvCoupler, 0}, {cvFadeIn, 8}, {cvFadeOut, 8},
{cvF0fPwm, 160}, {cvF0rPwm, 160}, {cvFA1Pwm, 160}, {cvFA2Pwm, 160},
{cvFA3Pwm, 160}, {cvFA4Pwm, 160}, {cvFA5Pwm, 160}, {cvFA6Pwm, 160},
{cvFA7Pwm, 160}, {cvFA8Pwm, 160}, {cvFA9Pwm, 160}, {cvFA10Pwm, 160},
{cvFA11Pwm, 160}, {cvFA12Pwm, 160}, {cvFA13Pwm, 160}, {cvFA14Pwm, 160},
{cvFAPolLo, 0}, {cvFAPolHi, 0},
{cvMem + 0, 255}, {cvMem + 1, 255}, {cvMem + 2, 255}, {cvMem + 3, 255},
{cvMem + 4, 0}, {cvMem + 5, 0}, {cvMem + 6, 0}, {cvMem + 7, 0},
{cvDump, 0}
};
NmraDcc Dcc;
void setup() { // program setup
pinMode(motorPwm, OUTPUT);
pinMode(motorDir, OUTPUT);
for (int i = 0; i < outs; i++) { // initialize all function outputs
stateFA[i] = 0; // initialize output state
oldStateFA[i] = 0;
effectFA[i] = 0; // and effects (no effects)
effectMillis[i] = 0;
cEff[i] = 0;
} // for i
for (int i = 1; i < maxFuncs; i++) stateF[i] = 0; // initialize all function input states
stateF[0] = 1;
#ifdef digitalPinToInterrupt
Dcc.pin(dccPin, 1);
#else
Dcc.pin(0, dccPin, 1);
#endif
Dcc.init(mfrID, mfrVer, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0); // initialize DCC library
if (Dcc.getCV(cvSub) != mfrSubver) Dcc.setCV(cvSub, mfrSubver); // set sub version CV value
if (Dcc.getCV(cvDef) != 0) Dcc.setCV(cvDef, 0); // reset factory defaults CV value
if (Dcc.getCV(cvDump) != 0) Dcc.setCV(cvDump, 0); // reset dump CV value
getVvalues();
getMomentumValues();
getCouplerValues();
marsMin = Dcc.getCV(cvMarsMin); // load mars light minimum PWM
randMin = Dcc.getCV(cvRandMin); // load random flicker minimum PWM
getEffectMillis(cvMars, 43);
getEffectMillis(cvFlash, 43);
getEffectMillis(cvStrobe, 43);
getEffectMillis(cvBeacon, 43);
getEffectMillis(cvDitch, 43);
getEffectMillis(cvSoftSt, 43);
getEffectMillis(cvFadeIn, 128);
getEffectMillis(cvFadeOut, 43);
getLocoDir();
#ifdef debug_main // send decoder info if debug mode is enabled
Serial.begin(115200); // set up UART; needed for dumpCVs
Serial.println();
Serial.println("--- Function DCC Decoder --- Ivan Cankov ---");
Serial.print("Mfr ID: ");
Serial.print(Dcc.getCV(cvMfr));
Serial.print("; Version: ");
Serial.print(Dcc.getCV(cvVer));
Serial.print(".");
Serial.print(Dcc.getCV(cvSub));
Serial.print("; Address: ");
Serial.print(Dcc.getAddr());
Serial.print("; CV");
Serial.print(cvConfig1);
Serial.print(": ");
Serial.println(Dcc.getCV(cvConfig1));
Serial.println();
#endif
byte c = cvFAPolLo;
byte p = 1;
for (int i = 0; i < outs; i++) {
pwmFA[i] = Dcc.getCV(cvF0fPwm + i); // load output PWMs
foPol[i] = (Dcc.getCV(c) & p) ? 1 : 0;
digitalWrite(foPin[i], !foPol[i]); // deactivate function output
pinMode(foPin[i], OUTPUT); // initialize function output
if ((i & 7) == 7) {
c++;
p = 1;
} else p *= 2;
} // for i
c = cvMem;
p = 1;
for (int i = 0; i < maxFuncs; i++) { // read enabled function states from cvMem
stateF[i] = (Dcc.getCV(c) & Dcc.getCV(c + 4) & p) ? 1 : 0;
if ((i & 7) == 7) {
c++;
p = 1;
} else p *= 2;
} // for i
randomSeed(analogRead(A7));
if (Dcc.getAddr() > 9983) defsCVCnt = sizeof(factoryDefaults) / sizeof(cvPair); // make defsCVCnt non-zero and equal to number
// of CVs to be reset to flag the loop()
// function reset to factory defaults is needed
} // setup
void loop() { // main cycle
Dcc.process();
if (doFunctions || throttleReq) {
for (int i = 0; i < outs; i++) stateFA[i] = 0; // reset all function output states
for (int i = 0; i < maxFuncs; i++) doMapping(i); // apply function mapping to output states
doOutputs(); // check output states and apply effects as needed
doFunctions = false;
throttleReq = false;
} // if doFunctions
checkEffectInProgress();
if (doMotorFlag) doMotor();
if (defsCVCnt && Dcc.isSetCVReady()) { // check if factory reset of CVs was requested
defsCVCnt--; // decrement from initial size of array
Dcc.setCV(factoryDefaults[defsCVCnt].cv, factoryDefaults[defsCVCnt].value);
#ifdef debug_defaults
Serial.print("Load Factory Defaults: CV");
Serial.print(factoryDefaults[defsCVCnt].cv);
Serial.print(": ");
Serial.println(factoryDefaults[defsCVCnt].value);
#endif
if (!defsCVCnt) asm("jmp 0"); // done with factory defaults, restart program; comment if restart is not desired
// if (!defsCVCnt) requestFunctionCheck(); // uncomment if restart is not desired
} // if defsCVCnt
if (setCVInd && Dcc.isSetCVReady() && (millis() - cvChangeMillis > 63)) { // CV needs to reset immediately
Dcc.setCV(setCVInd, setCVVal); // after its value has been set
if (setCVInd == cvDump) dumpCVs(); // dump CVs if dump CV changed
setCVInd = 0; // clear request
} // if setCVInd
#ifdef dump_CVs_enabled
if (getCVInd && !setCVInd) { // check for CV readback to serial request
Serial.print("CV"); // CV readback to serial requested
Serial.print(getCVInd); // send CV to serial
Serial.print(",");
Serial.println(Dcc.getCV(getCVInd));
getCVInd = 0; // clear request
} // if getCVInd
#endif
} // loop
Продължението следва...
Иван