Електроника и Електротехника | Electronics and Electrical Engineering > Цифрово / дигитално управление | Digital Command Control
Осветление на вагони
ivo:
Благодаря :)
Накрая намерих в Ebay :) https://www.ebay.de/itm/194615066415?hash=item2d4ff63f2f:g:7IgAAOSwwTlUn~wp от Benno002-22
IvanC:
Схемата на печатната платка:
Вместо диода за разряд на "златния" кондензатор C5 използвах съпротивление 0 ома, т.е. мост. Този стабилизатор на напрежение се справя много добре със зарядния ток на коднензаторите.
Иван
IvanC:
Това е програмата на функционалния декодер:
--- Код: ---
#include <NmraDcc.h> // Библиотека за DCC декодер - необходима за правилната работа на програмата
//#define debug_cvchange // Генерира код за дебъгване ако се махнат двете наклонени черти в началото на реда;
//#define debug_ack // нужно е само на автора на програмата
//#define debug_speed
//#define debug_functions
//#define debug_mapping
//#define debug_effects
#define debug_defaults
#define dump_CVs_enabled // uncomment to enable CV change readback and CV dump to serial
#if defined(debug_cvchange) or defined(debug_ack) or defined(debug_speed) or defined(debug_functions) or defined(debug_mapping) or defined(debug_effects) or defined(debug_defaults) or defined(dump_CVs_enabled)
#define debug_main
#endif
// ---------------- Константи за нормалната работа на програмата - да не се променят!!! ----------------
#define mfrID 13
#define mfrVer 11
#define mfrSubver 1
#define defaultAddress 3 // default decoder address
#define defaultLongAddress 128 // default long address
// ---------------------------------- Задаване функциите на изводите: ----------------------------------
#define dccPin 2 // Вход за DCC сигнала; стойност 2 или 3;
// да не се използват други стойности!!!
#define motorPwm 14 // Изход за ШИМ на мотора
#define motorDir 13 // Изход за посока на мотора
// FA0f FA0r FA1 FA2 FA3 FA4 FA5 FA6 FA7 FA8
const byte foPin[] = { 3, 5, 6, 9, 10, 11, 12, 8, 7, 4}; // Изводи за управление на функциите.
// Първите 6 извода да не се променят
// и да няма дублиране с dccPin!!!
const int outs = sizeof(foPin) / sizeof(foPin[0]);
byte foPol[outs]; // "Поляритет" на изводите - виж cvFAPolLo и cvFAPolHi:
// 0 - активно ниско ниво
// 1 - активно високо ниво
// -------------- Още константи за нормалната работа на програмата - да не се променят!!! --------------
#define maxFuncs 13
#define pwmTime 20 // time in µs for PWM counter increment
#define pwmStep 8 // PWM counter increment step
#define stopped false
#define moving true
#define reverse 0
#define forward 2
#define off 0
#define on 255
#define momentumConst 900000UL
// ------------------------------------- Променливи на програмата: -------------------------------------
struct throttleStruct {byte Value; byte Dir;};
throttleStruct throttle = {0, forward};
throttleStruct intThrottle = {0, forward};
byte locoDirFwd = DCC_DIR_FWD;
byte vMin = 1;
byte vMid = 85;
byte vMax = 255;
byte doMotorFlag = false;
unsigned long accelCount = momentumConst;
unsigned long decelCount = momentumConst;
unsigned long accelCounter = 0;
unsigned long decelCounter = 0;
unsigned long truePwmTime = pwmTime;
int deltaThrottle = 0;
byte stateF[maxFuncs];
byte stateFA[outs];
byte oldStateFA[outs];
byte pwmFA[outs];
byte effectFA[outs];
byte outPwm[outs];
unsigned long effectMillis[outs];
int cEff[outs];
byte doFunctions = true;
byte throttleReq = false;
byte cvChanged = false;
// CCCC VV VV
// CC CC VV VV SSS
// CC VV VV SS
// CC VV VV SSS
// CC CC VVV SS
// CCCC V SSS
// -------------------------------------------- ID and reset to defaults CVs -------------------------------------------
#define cvMfr 8 // manufacturer ID
#define cvVer 7 // decoder type and code
#define cvSub 65 // decoder software version
#define cvDef 11 // reset to defaults: write 11 to reset all CVs to defaults
// --------------------------------------- address and decoder configuration CVs ---------------------------------------
#define cvShortAddress 1 // decoder short address
#define cvLongAddressHi 17 // decoder long address high byte
#define cvLongAddressLo 18 // decoder long address low byte
#define cvConfig1 29 // decoder configuration I bits
// ----------------------------------------------- speed and momentum CVs ----------------------------------------------
#define cvStartV 2 // minimum motor PWM
#define cvMaxV 5 // maximum motor PWM
#define cvMidV 6 // motor PWM @63 throttle
#define cvAccel 3 // acceleration time from min to max motor PWM in 0.9s
#define cvDecel 4 // deceleration time from max to min motor PWM in 0.9s
#define cvMomReduction 124 // momentum reduction:
// 255 = no reduction
// 192 = reduced to 75%
// 128 = reduced to 50%
// 64 = reduced to 25%
// 0 = no momentum
#define cvHalfSpeedKey 155 // speed reduction key:
// 0 = no key assigned
// 1 - 28 = active when F1 - F28 (if supported) key on
// 29 = active when F0 key on
// 101 - 128 = active when F1 - F28 (if supported) key off
// 129 = active when F0 key off
#define cvMomentumKey 156 // momentum reduction key - same key assignment as cvHalfSpeedKey
// ------------------------------------------------- motor control CVs -------------------------------------------------
#define cvMotorFreq 9 // motor control frequency FUTURE IMPLEMENTATION
#define cvMotorPI 56 // motor control P and I FUTURE IMPLEMENTATION
#define cvMotorVref 57 // motor control reference voltage FUTURE IMPLEMENTATION
#define cvMotorBEMF 58 // motor control BEMF intensity FUTURE IMPLEMENTATION
// ------------------------------- "NMRA" (F0f-FA6) key-to-output mapping (no shift) CVs -------------------------------
#define cvF0f 33 // F0f key
#define cvF0r 34 // F0r key
#define cvF1 35 // F1 key
#define cvF2 36 // F2 key
#define cvF3 37 // F3 key
#define cvF4 38 // F4 key
#define cvF5 39 // F5 key
#define cvF6 40 // F6 key
#define cvF7 41 // F7 key
#define cvF8 42 // F8 key
#define cvF9 43 // F9 key
#define cvF10 44 // F10 key
#define cvF11 45 // F11 key
#define cvF12 46 // F12 key
// ----------------------------------- extended (FA7-FA14) key-to-output mapping CVs -----------------------------------
#define cvF0fe 133 // F0f key
#define cvF0re 134 // F0r key
#define cvF1e 135 // F1 key
#define cvF2e 136 // F2 key
#define cvF3e 137 // F3 key
#define cvF4e 138 // F4 key
#define cvF5e 139 // F5 key
#define cvF6e 140 // F6 key
#define cvF7e 141 // F7 key
#define cvF8e 142 // F8 key
#define cvF9e 143 // F9 key
#define cvF10e 144 // F10 key
#define cvF11e 145 // F11 key
#define cvF12e 146 // F12 key
// --------------------------------------------- function output effect CVs --------------------------------------------
#define cvF0fEffect 125 // F0f output effect
#define cvF0rEffect 126 // F0r output effect
#define cvFA1Effect 127 // FA1 output effect
#define cvFA2Effect 128 // FA2 output effect
#define cvFA3Effect 129 // FA3 output effect
#define cvFA4Effect 130 // FA4 output effect
#define cvFA5Effect 131 // FA5 output effect
#define cvFA6Effect 132 // FA6 output effect
#define cvFA7Effect 159 // FA7 output effect
#define cvFA8Effect 160 // FA8 output effect
#define cvFA9Effect 161 // FA9 output effect
#define cvFA10Effect 162 // FA10 output effect
#define cvFA11Effect 163 // FA11 output effect
#define cvFA12Effect 164 // FA12 output effect
#define cvFA13Effect 165 // FA13 output effect
#define cvFA14Effect 166 // FA14 output effect
// -------------------------------------------------- effect selectors -------------------------------------------------
#define outEffDir 3 // output direction mask
#define outEffBidir 0 // xxxxxx00 - active in both directions
#define outEffFwd 1 // xxxxxx01 - active only forward
#define outEffRev 2 // xxxxxx10 - active only in reverse
#define outEffMask 252 // output effect mask
#define outEffNone 0 // 000000xx - no effect (except direction)
#define outEffMars 4 // 000001xx - mars light
#define outEffRandom 8 // 000010xx - random flicker
#define outEffFlash 12 // 000011xx - flashing light
#define outEffStrobe1 16 // 000100xx - single pulse strobe
#define outEffStrobe2 20 // 000101xx - double pulse strobe
#define outEffBeacon 24 // 000110xx - rotary beacon
#define outEffGyra 28 // 000111xx - gyralite
#define outEffDitch1R 32 // 001000xx - ditch light 1, right
#define outEffDitch1L 36 // 001001xx - ditch light 1, left
#define outEffDitch2R 40 // 001010xx - ditch light 2, right
#define outEffDitch2L 44 // 001011xx - ditch light 2, left
#define outEffCoupler 48 // 001100xx - coupler per cv115
#define outEffSoft 52 // 001101xx - soft start per cv63
#define outEffBrake 56 // 001110xx - auto brake light FUTURE IMPLEMENTATION
#define outEffStand 60 // 001111xx - output active at standstill only
#define outEff5min 64 // 010000xx - output off after 5 minutes
#define outEff10min 68 // 010001xx - output off after 10 minutes
#define outEffSSmoke 72 // 010010xx - speed dependent steam smoke FUTURE IMPLEMENTATION
#define outEffLowVin 76 // 010011xx - relay protection for servos, off at low input voltage FUTURE IMPLEMENTATION
#define outEffDSmoke 80 // 010100xx - driving dependent diesel smoke FUTURE IMPLEMENTATION
#define outEffFade 88 // 010110xx - fade-in per cv190, fade-out per cv191
#define outEffFluo 92 // 010111xx - fluorescent lamp effect
#define outEffSparks 96 // 011000xx - sparks with heavy braking FUTURE IMPLEMENTATION
// --------------------------------------------------- available CVs ---------------------------------------------------
#define cv47Available 47 // available FUTURE IMPLEMENTATION
// to
#define cv53Available 53 // available FUTURE IMPLEMENTATION
--- Край на кода ---
Продължението следва...
Иван
IvanC:
--- Код: ---
// ------------------------------------------------- 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
--- Край на кода ---
Продължението следва...
Иван
IvanC:
--- Код: ---
void notifyDccCVChange(unsigned int cv, byte value) { // called when DCC packet changes CV value
#ifdef debug_cvchange
Serial.print("notifyDccCVChange: CV");
Serial.print(cv);
Serial.print(": ");
Serial.println(value);
#endif
switch (cv) {
case cvDef: // factory defaults CV has changed
if (value == cvDef) // change to reset to factory defaults
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
break;
case cvSub: // subversion has been changed
setCVInd = cvSub; // flag the loop() to restore it
setCVVal = mfrSubver;
break;
case cvStartV:
case cvMaxV:
case cvMidV:
getVvalues();
case cvAccel:
case cvDecel:
getMomentumValues();
break;
case cvMarsMin: // mars light minimum PWM value changed
marsMin = Dcc.getCV(cv); // load mars light minimum PWM
break;
case cvRandMin: // random flicker minimum PWM value changed
randMin = Dcc.getCV(cv); // load random flicker minimum PWM
break;
case cvMars: // mars light value changed
case cvFlash: // flash value changed
case cvStrobe: // strobe value changed
case cvBeacon: // rotary beacon value changed
case cvDitch: // ditch lights value changed
case cvSoftSt: // fade-in value changed
case cvFadeOut: // fade-out value changed
getEffectMillis(cv, 43);
break;
case cvFadeIn: // fade-in value changed
getEffectMillis(cv, 128);
break;
case cvCoupler:
getCouplerValues();
break;
#ifdef dump_CVs_enabled
case cvDump: // CV dump is requested
setCVInd = cvDump; // flag the loop() to reset the value
setCVVal = 0; // and dump the CVs to serial
break;
#endif
default:
cvChanged = cv;
requestFunctionCheck();
break;
} // switch cv
if ((cv == cvFAPolLo) || (cv == cvFAPolHi)) { // output polarity value changed
byte c = cvFAPolLo;
byte p = 1;
for (int i = 0; i < outs; i++) {
foPol[i] = (Dcc.getCV(c) & p) ? 1 : 0;
if ((i & 7) == 7) {
c++;
p = 1;
} else p *= 2;
} // for i
} // if cv
if ((cv >= cvF0fPwm) && (cv < cvF0fPwm + outs))
for (int i = 0; i < outs; i++)
pwmFA[i] = Dcc.getCV(cvF0fPwm + i); // load output PWMs
cvChangeMillis = millis(); // get current millis for CV change blocking
getCVInd = cv; // flag the loop() to send a CV readback to serial
} // notifyDccCVChange
void notifyCVAck(void) { // called when ACK needs to be sent for a CV read
#ifdef debug_ack
Serial.println("notifyCVAck") ;
#endif
digitalWrite(motorPwm, on);
delay(8);
digitalWrite(motorPwm, off);
} // notifyCVAck
void notifyDccSpeed(unsigned int a, DCC_ADDR_TYPE at, byte s, DCC_DIRECTION d, DCC_SPEED_STEPS ss) { // called when a DCC speed packet with decoder address is received
byte ts = (s <= 1) ? stopped : moving;
byte td = (d == locoDirFwd) ? forward : reverse;
throttleReq = ((throttle.Dir + (throttle.Value > 0)) != (td + ts));
doMotorFlag = ((throttle.Value != s) || (throttle.Dir != td));
if (s) s--;
else {
digitalWrite(motorPwm, off);
intThrottle.Value = s;
intThrottle.Dir = td;
accelCounter = 0;
decelCounter = 0;
} // if s
if (s) {
byte hs = ss >> 1;
if (s < hs) s = map(s, 1, hs, vMin, vMid);
else s = map(s, hs, ss, vMid, vMax);
} // if s
throttle.Value = s;
throttle.Dir = td;
#ifdef debug_speed
Serial.print("notifyDccSpeed: Address: ");
Serial.print(a);
Serial.print((at == DCC_ADDR_SHORT) ? "-S" : "-L");
Serial.print("; Speed: ");
Serial.print(s);
Serial.print((d == DCC_DIR_FWD) ? "-F" : "-R" );
Serial.print("; Steps: ");
Serial.print(ss);
Serial.print("; State: ");
Serial.print((ts == moving) ? "Moving " : "Stopped ");
Serial.print((throttle.Dir == forward) ? "forward" : "in reverse");
Serial.println();
#endif
} // notifyDccSpeed
void notifyDccFunc(unsigned int a, DCC_ADDR_TYPE aType, FN_GROUP fGroup, byte fState) { // called when a DCC function packet with decoder address is received
#ifdef debug_functions
Serial.print("notifyDccFunc: Address: ");
Serial.print(a);
Serial.print((aType == DCC_ADDR_SHORT) ? "-S" : "-L");
Serial.print("; Function Group: ");
switch (fGroup) {
case FN_0_4: Serial.print(" F0-F4: "); break;
case FN_5_8: Serial.print(" F5-F8: "); break;
case FN_9_12: Serial.print(" F9-F12: "); break;
case FN_13_20: Serial.print("F13-F20: "); break;
case FN_21_28: Serial.print("F21-F28: "); break;
} // switch fGroup
#endif
switch (fGroup) {
case FN_0_4:
stateF[0] = (fState & FN_BIT_00) ? 1 : 0;
#ifdef debug_functions
Serial.print(stateF[0]);
#endif
setFuncState(FN_BIT_01, fState, 1, 4); break;
case FN_5_8: setFuncState(FN_BIT_05, fState, 5, 8); break;
case FN_9_12: setFuncState(FN_BIT_09, fState, 9, 12); break;
case FN_13_20: setFuncState(FN_BIT_13, fState, 13, 20); break;
case FN_21_28: setFuncState(FN_BIT_21, fState, 21, 28); break;
} // switch fGroup
#ifdef debug_functions
Serial.println();
#endif
doFunctions = 1;
byte m = 0;
byte p = 1;
byte c = cvMem + 4;
for (int i = 0; i < maxFuncs; i++) { // store input states to cvMem
m += (stateF[i]) ? p : 0;
if ((i == 7) || (i == maxFuncs - 1)) {
if (Dcc.getCV(c) != m) Dcc.setCV(c, m);
m = 0;
p = 1;
c++;
} else p *= 2;
} // for i
} // notifyDccFunc
void getVvalues() {
byte b = Dcc.getCV(cvStartV);
vMin = (b < 2) ? 1 : ((b > 252) ? 252 : b);
b = Dcc.getCV(cvMaxV);
vMax = (b < 2) ? 255 : ((b < (vMin + 3)) ? (vMin + 3) : b);
b = Dcc.getCV(cvMidV);
vMid = (b < 2) ? ((vMax - vMin) / 3 + vMin) : ((b < (vMin + 1)) ? (vMin + 1): ((b > (vMax - 2)) ? (vMax - 2) : b));
#ifdef debug_speed
Serial.print(vMin);
Serial.print(" - ");
Serial.print(vMid);
Serial.print(" - ");
Serial.println(vMax);
#endif
doMotorFlag = true;
} // getVvalues
void getMomentumValues(){
accelCount = momentumConst * Dcc.getCV(cvAccel) / (vMax - vMin);
decelCount = momentumConst * Dcc.getCV(cvDecel) / (vMax - vMin);
} // getMomentumValues
// ---------------------------------------------------------------------------- doMotor ----------------------------------------------------------------------------
void doMotor() {
if ((!accelCounter) || (!decelCounter)) {
byte f = false;
byte tv = throttle.Value;
byte mr;
byte hsk = Dcc.getCV(cvHalfSpeedKey);
byte k = hsk % 100;
if (k) {
if (k == 29) k = 0;
if (k < maxFuncs) {
f = stateF[k];
if (hsk / 100 == 1) f = !f;
if (f) tv = tv >> 1;
} // if hsk
} // if hsk
f = false;
hsk = Dcc.getCV(cvMomentumKey);
k = hsk % 100;
if (k) {
if (k == 29) k = 0;
if (k < maxFuncs) {
f = stateF[k];
if (hsk / 100 == 1) f = !f;
if (f) mr = Dcc.getCV(cvMomReduction);
} // if hsk
} // if hsk
int accel = 0; // constant speed
if (!intThrottle.Value) {
intThrottle.Dir = throttle.Dir;
throttleReq = true;
} // if !intThrottle.Value
if (intThrottle.Dir == throttle.Dir) {
if (intThrottle.Value < tv) accel = 1; // accelerating
else if (intThrottle.Value > tv) accel = -1; // decelerating
} else accel = -1; // decelerating
if (((accel > 0) && (!accelCounter)) || ((accel < 0) && (!decelCounter))) {
intThrottle.Value += accel;
throttleReq = true;
deltaThrottle = (intThrottle.Dir == throttle.Dir) ? tv : -tv;
deltaThrottle -= intThrottle.Value;
if (intThrottle.Value != tv) {
if (accel > 0) {
accelCounter = expo(accelCount, intThrottle.Value, true) / truePwmTime;
if (f) accelCounter = (accelCounter * mr) >> 8;
} // if accel > 0
else if (accel < 0) {
decelCounter = expo(decelCount, intThrottle.Value, true) / truePwmTime;
if (f) decelCounter = (decelCounter * mr) >> 8;
} // if accel < 0
} else if (!intThrottle.Value) {
intThrottle.Dir = throttle.Dir;
throttleReq = true;
} // if !intThrottle.Value
} // if accel
} // if intThrottle.Dir
digitalWrite(motorDir, intThrottle.Dir);
digitalWrite(motorPwm, intThrottle.Value > pwmCounter);
// analogWrite(motorPwm, intThrottle.Value);
doMotorFlag = false;
} // doMotor
void getEffectMillis(word cv, byte d) {
int s;
unsigned long m;
byte b = Dcc.getCV(cv);
switch (cv) {
case cvFlash:
m = b / 10 + 1;
m *= 20;
b %= 10;
flashOnMillis = m * (1 + b);
flashOffMillis = m * (9 - b);
return;
case cvStrobe:
m = b / 100;
strobeOnMillis = 35 * (1 + m);
m = (b / 10) % 10;
strobeOffMillis = 200 * (1 + m) - strobeOnMillis;
m = b % 10;
strobe2Millis = 50 * (1 + m);
return;
case cvDitch:
ditchPause = (b / 100 + 1) * 25;
ditchMin = ((b / 10) % 10) * 12;
b %= 10;
b += 5;
default:
b = max(b, 1);
s = int(d / b);
s = max(s, 1);
m = (unsigned long)(s * b / 2.56);
break;
} // switch cv
switch (cv) {
case cvMars: marsStep = s; marsMillis = m; break;
case cvBeacon: beaconStep = s; beaconMillis = m; break;
case cvDitch: ditchStep = s; ditchMillis = m; break;
case cvSoftSt: softStStep = s; softStMillis = m; break;
case cvFadeIn: fadeInStep = s; fadeInMillis = m; break;
case cvFadeOut: fadeOutStep = s; fadeOutMillis = m; break;
} // switch cv
} // getEffectMillis
void getCouplerValues() {
unsigned long l = Dcc.getCV(cvCoupler);
couplerMillis = (l / 10) * 200;
couplerPwm = (l % 10) * 25;
} // getCouplerValues
unsigned long expo(unsigned long m, byte c, byte t) {
if (t) {
if (c < 10) return (m * 8);
if (c < 25) return (m * 4);
} // if t
if (c < 51) return (m * 2);
if (c < 102) return (m * 1.290);
if (c < 153) return (m * 0.831);
if (c < 240) return (m * 0.535);
return (m * 0.345);
} // expo
void requestFunctionCheck() {
doFunctions = true;
throttleReq = true;
getLocoDir();
} // requestFunctionCheck
byte getFAEffectIndex(byte cv) { // returns the function output index based on output effect CV
for (int i = 0; i < outs; i++) {
byte j = ((i < 8) ? cvF0fEffect : (cvFA7Effect - 8)) + i; // check all output effects
if (cv == (((i < 8) ? cvF0fEffect : (cvFA7Effect - 8)) + i)) return (i);
} // for i
return (outs);
} // getFAEffectIndex
void dumpCVs() { // dump all CVs to serial
#ifdef dump_CVs_enabled
Serial.println("--- CV Dump Start ---");
Serial.println("CV,Value");
for (int i = 1; i <= 256; i++) { // cycle thru all (256 supported) CVs
int p = ((i == cvVer) || (i == cvMfr)) ? i : 0; // CV7 and CV8 are not in defaults array
if (!p)
for (int c = 0; c < sizeof(factoryDefaults) / sizeof(cvPair); c++)
if (i == factoryDefaults[c].cv) p = i; // get index if CV in defaults array
if (p) { // check if CV found
Serial.print("CV"); // send CV to serial
Serial.print(p);
Serial.print(",");
Serial.println(Dcc.getCV(p));
} // if p
} // for i
Serial.println("---- CV Dump End ----");
#endif
} // dumpCVs
void getLocoDir() {locoDirFwd = (Dcc.getCV(cvConfig1) & CV29_LOCO_DIR) ^ DCC_DIR_FWD;} // get direction from CV29.0
void setFuncState (byte g, byte s, byte b, byte e) {
byte m = g;
for (int c = b; c <= min(e, maxFuncs - 1); c++) {
stateF[c] = (s & m) ? 1 : 0;
m *= 2;
#ifdef debug_functions
Serial.print(stateF[c]);
#endif
} // for c
} // setFuncState
// --------------------------------------------------------------------------- doMapping ---------------------------------------------------------------------------
void doMapping(int i) {
byte m = Dcc.getCV((i) ? (cvF0r + i) : ((intThrottle.Dir == forward) ? cvF0f : cvF0r)); // get function mapping CV value
for (int c = 0; c < outs; c++) { // check all mapping
if ((c < outs) && (m & 1)) {
if (stateF[i]) stateFA[c] = stateF[i]; // output is controlled by input - store "new" state
#ifdef debug_mapping
Serial.print("State of F");
if (i) Serial.print(i); else Serial.print((intThrottle.Dir == forward) ? "0f" : "0r");
Serial.print(": ");
Serial.print(stateF[i]);
Serial.print("; Mask: ");
Serial.print(m);
Serial.print("; State of FA");
Serial.print(c);
Serial.print(": ");
Serial.println(stateFA[c]);
#endif
} // if c
if ((c & 7) == 7) m = Dcc.getCV((i != 0) ? (cvF0re + i) : ((intThrottle.Dir == forward) ? cvF0fe : cvF0re)); else m /= 2;
} // for c
} // doMapping
--- Край на кода ---
Продължението следва...
Иван
Навигация
[0] Списък на темите
Премини на пълна версия