initial useable status
This commit is contained in:
@@ -0,0 +1,550 @@
|
||||
// DCCMFL1616 - DIY DCC Multifunction Loco decoder
|
||||
// licensed under GPL v3
|
||||
//
|
||||
// based on NMRA Dcc Multifunction Motor Decoder Demo by Alex Shepherd
|
||||
//
|
||||
// This firmware requires these Arduino Libraries:
|
||||
//
|
||||
// 1) The NmraDcc Library from: http://mrrwa.org/download/
|
||||
//
|
||||
// These libraries can be found and installed via the Arduino IDE Library Manager
|
||||
//
|
||||
// Functionality implemented:
|
||||
// - motor control (speed & direction) with start and maximum PWM values defined in CV2 & CV5
|
||||
// - integrated acceleration / deceleration profile controlled by CV3 & CV4
|
||||
// - exterieur lighting (F0 white head lights, F1 red rear lights, in combination with F5 white head and rear lights) in regards to driving direction
|
||||
// - defined default Decoder address: 3 according to NMRA & NEM standard
|
||||
// - factory reset by setting CV8 to 255
|
||||
// - debugging on UART (TX) can be actived (may slow down reaction of the decoder to updated controls)
|
||||
//
|
||||
// Functionality NOT implemented yet:
|
||||
// analog DC driving mode --> DCC-timeout?
|
||||
//
|
||||
|
||||
#include <NmraDcc.h>
|
||||
// Uncomment any of the lines below to enable debug messages for different parts of the code
|
||||
//#define DEBUG_FUNCTIONS
|
||||
//#define DEBUG_SPEED
|
||||
//#define DEBUG_PWM
|
||||
//#define DEBUG_DCC_ACK
|
||||
//#define DEBUG_DCC_MSG
|
||||
//#define DEBUG_DCC_RESET
|
||||
|
||||
#if defined(DEBUG_FUNCTIONS) or defined(DEBUG_SPEED) or defined(DEBUG_PWM) or defined(DEBUG_DCC_ACK) or defined(DEBUG_DCC_MSG) or defined(DEBUG_DCC_RESET)
|
||||
#define DEBUG_PRINT
|
||||
#endif
|
||||
|
||||
// This is the default DCC Address
|
||||
#define DEFAULT_DECODER_ADDRESS 3
|
||||
|
||||
// default Version
|
||||
#define DEFAULT_VERSION_ID 1
|
||||
|
||||
// This section defines the Arduino UNO Pins to use --> for testing purposes; not used in production
|
||||
#ifdef __AVR_ATmega328P__
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN 2
|
||||
|
||||
#define LED_PIN_WHITE_FRONT 5
|
||||
#define LED_PIN_WHITE_REAR 6
|
||||
#define LED_PIN_RED_FRONT 12
|
||||
#define LED_PIN_RED_REAR 13
|
||||
#define LED_PIN_CABIN 9
|
||||
#define MOTOR_PIN_1 11
|
||||
#define MOTOR_PIN_2 10
|
||||
|
||||
// This section defines the Arduino ATTiny1616/1626/3216/3226 Pins to use
|
||||
#elif defined __AVR_ATtinyxy6__
|
||||
|
||||
// Define the Arduino input Pin number for the DCC Signal
|
||||
#define DCC_PIN PIN_PA1
|
||||
|
||||
#define LED_PIN_WHITE_FRONT PIN_PB0
|
||||
#define LED_PIN_WHITE_REAR PIN_PB1
|
||||
#define LED_PIN_RED_FRONT PIN_PA5
|
||||
#define LED_PIN_RED_REAR PIN_PC0
|
||||
#define LED_PIN_CABIN PIN_PA7
|
||||
#define MOTOR_PIN_1 PIN_PA3
|
||||
#define MOTOR_PIN_2 PIN_PA4
|
||||
|
||||
#else
|
||||
#error "Unsupported CPU, you need to add another configuration section for your CPU"
|
||||
#endif
|
||||
|
||||
// Some global state variables
|
||||
|
||||
byte FN_0_4_state = 0;
|
||||
byte FN_5_8_state = 0;
|
||||
byte FN_9_12_state = 0;
|
||||
byte FN_13_20_state = 0;
|
||||
byte FN_21_28_state = 0;
|
||||
|
||||
// if cabin LED are connected to white LED pins pull cabin LED pin low
|
||||
bool invert_cabin_light_logic = true;
|
||||
|
||||
uint8_t newDirection = 0;
|
||||
uint8_t lastDirection = 0;
|
||||
|
||||
//speed variables
|
||||
uint8_t newSpeed = 0;
|
||||
uint8_t targetSpeed = 0;
|
||||
uint32_t speedChangeTime = 0;
|
||||
uint8_t numSpeedSteps = SPEED_STEP_128;
|
||||
uint8_t currentPwm = 0;
|
||||
uint8_t targetPwm = 0;
|
||||
uint8_t lastPwm = 0;
|
||||
uint8_t accRate = 0;
|
||||
uint8_t decRate = 0;
|
||||
|
||||
uint8_t vStart;
|
||||
uint8_t vHigh;
|
||||
|
||||
// Structure for CV Values Table
|
||||
struct CVPair
|
||||
{
|
||||
uint16_t CV;
|
||||
uint8_t Value;
|
||||
};
|
||||
|
||||
// CV Addresses we will be using according to NMRA 9.2.2 Table 1
|
||||
#define CV_VSTART 2
|
||||
#define CV_ACC_RATE 3
|
||||
#define CV_DEC_RATE 4
|
||||
#define CV_VHIGH 5
|
||||
|
||||
|
||||
// Default CV Values Table
|
||||
CVPair FactoryDefaultCVs [] =
|
||||
{
|
||||
// The CV Below defines the Short DCC Address
|
||||
{CV_MULTIFUNCTION_PRIMARY_ADDRESS, DEFAULT_DECODER_ADDRESS},
|
||||
|
||||
// Three Step Speed Table
|
||||
{CV_VSTART, 120},
|
||||
{CV_VHIGH, 255},
|
||||
|
||||
//Acceleration and deceleration; defaults to 0 (deactivated)
|
||||
{CV_ACC_RATE, 0},
|
||||
{CV_DEC_RATE, 0},
|
||||
|
||||
// CV7 Manufacturer Version ID
|
||||
{ CV_VERSION_ID, DEFAULT_VERSION_ID},
|
||||
|
||||
// CV8 --> Decoder Reset? (set CV to 255 to initiate factory reset)
|
||||
{CV_MANUFACTURER_ID, MAN_ID_DIY},
|
||||
|
||||
// These two CVs define the Long DCC Address
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_MSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_MSB(DEFAULT_DECODER_ADDRESS)},
|
||||
{CV_MULTIFUNCTION_EXTENDED_ADDRESS_LSB, CALC_MULTIFUNCTION_EXTENDED_ADDRESS_LSB(DEFAULT_DECODER_ADDRESS)},
|
||||
|
||||
// ONLY uncomment 1 CV_29_CONFIG line below as approprate
|
||||
// {CV_29_CONFIG, 0}, // Short Address 14 Speed Steps
|
||||
{CV_29_CONFIG, CV29_F0_LOCATION}, // Short Address 28/128 Speed Steps
|
||||
// {CV_29_CONFIG, CV29_EXT_ADDRESSING | CV29_F0_LOCATION}, // Long Address 28/128 Speed Steps
|
||||
};
|
||||
|
||||
NmraDcc Dcc ;
|
||||
|
||||
uint8_t FactoryDefaultCVIndex = 0;
|
||||
|
||||
// This call-back function is called when a CV Value changes so we can update CVs we're using
|
||||
void notifyCVChange( uint16_t CV, uint8_t Value)
|
||||
{
|
||||
switch(CV)
|
||||
{
|
||||
case CV_VSTART:
|
||||
vStart = Value;
|
||||
break;
|
||||
|
||||
case CV_VHIGH:
|
||||
vHigh = Value;
|
||||
break;
|
||||
|
||||
case CV_ACC_RATE:
|
||||
accRate = Value;
|
||||
break;
|
||||
|
||||
case CV_DEC_RATE:
|
||||
decRate = Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DCC_RESET
|
||||
void notifyDccReset(uint8_t hardReset) {
|
||||
Serial.printf(F("notifyDccReset: %6s.\n"), hardReset ? "HARD" : "NORMAL");
|
||||
}
|
||||
#endif
|
||||
|
||||
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);
|
||||
#ifdef DEBUG_DCC_RESET
|
||||
Serial.println("Factory reset");
|
||||
#endif
|
||||
};
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Speed packet for our address
|
||||
void notifyDccSpeed( uint16_t Addr, DCC_ADDR_TYPE AddrType, uint8_t Speed, DCC_DIRECTION Dir, DCC_SPEED_STEPS SpeedSteps )
|
||||
{
|
||||
#ifdef DEBUG_SPEED
|
||||
Serial.print("notifyDccSpeed: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? "-S" : "-L" );
|
||||
Serial.print(" Speed: ");
|
||||
Serial.print(Speed,DEC);
|
||||
Serial.print(" Steps: ");
|
||||
Serial.print(SpeedSteps,DEC);
|
||||
Serial.print(" Dir: ");
|
||||
Serial.println( (Dir == DCC_DIR_FWD) ? "Forward" : "Reverse" );
|
||||
#endif
|
||||
|
||||
newDirection = Dir;
|
||||
newSpeed = Speed;
|
||||
numSpeedSteps = SpeedSteps;
|
||||
};
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Function packet for our address
|
||||
void notifyDccFunc(uint16_t Addr, DCC_ADDR_TYPE AddrType, FN_GROUP FuncGrp, uint8_t FuncState)
|
||||
{
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("notifyDccFunc: Addr: ");
|
||||
Serial.print(Addr,DEC);
|
||||
Serial.print( (AddrType == DCC_ADDR_SHORT) ? 'S' : 'L' );
|
||||
Serial.print(" Function Group: ");
|
||||
Serial.print(FuncGrp,DEC);
|
||||
#endif
|
||||
|
||||
/* Liste der Funktionen aus NEM 608 Betriebsart 1 (eine Ebene) / List of functions according to NEM608 operation mode 1 (one layer)
|
||||
Funk | Traktionsart | Dampf | Verbrennung | Elektrisch | SchaltFunktion | Bemerkung
|
||||
| Kategorie | | | | |
|
||||
F0 | Beleuchtung | Fahrtrichtung vorwärts / rückwärts | Fahrtrichtung vorwärts / rückwärts | Fahrtrichtung vorwärts / rückwärts | ein / aus |
|
||||
F1 | Beleuchtung | Rückwärtiges Licht | Rückwärtiges Licht / Schlusslicht | Rückwärtiges Licht / Schlusslicht | ein / aus |
|
||||
F2 | Betrieb | Achtungspfiff | Achtungspfiff / Signalhorn | Achtungspfiff | Moment | Pfiff oder Horn entsprechend der Ausrüstung. Länge des Pfiffs / Horns wird von der Zeit der Betätigung der Taste bestimmt.
|
||||
F3 | Geräusche | Stand, Anfahren, Fahren, Bremsen | Anlassen, Motor(en), Stand, Anfahren, Fahren, Bremsen, Abschalten Motor(en) | Stand, Anfahren, Fahren, Bremsen | ein / aus |
|
||||
F4 | Betrieb | Entkuppeln | Entkuppeln | Entkuppeln |Moment |
|
||||
F5 | Betrieb | Rangiergang | Rangiergang | Rangiergang | ein / aus | F0 und F1 schalten Beleuchtung ein / aus
|
||||
F6 | Beleuchtung | Führerstand | Führerstand | Führerstand | ein / aus | Bei zwei Führerständen entsprechend der Fahrtrichtung
|
||||
F7 | Beleuchtung | Feuerbüchse | Motorraum- / Innenbeleuchtung | Motorraum- / Innenbeleuchtung | ein / aus |
|
||||
F8 | Auf- /Abrüsten | Dampferzeuger | Abgaserzeuger | Pantograph | ein / aus bzw. auf / ab | Bei zwei Pantographen entsprechend der Fahrtrichtung
|
||||
F9 | Geräusche | Luftpumpe | Kompressor | Kompressor | ein / aus |
|
||||
*/
|
||||
|
||||
switch(FuncGrp) {
|
||||
case FN_0_4:
|
||||
FN_0_4_state = FuncState;
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.print(FuncState);
|
||||
Serial.print(" FN 0: ");
|
||||
Serial.print((FuncState & FN_BIT_00) ? 1 : 0);
|
||||
Serial.print(" FN 1: ");
|
||||
Serial.print((FuncState & FN_BIT_01) ? 1 : 0);
|
||||
Serial.print(" FN 2: ");
|
||||
Serial.print((FuncState & FN_BIT_02) ? 1 : 0);
|
||||
Serial.print(" FN 3: ");
|
||||
Serial.print((FuncState & FN_BIT_03) ? 1 : 0);
|
||||
Serial.print(" FN 4: ");
|
||||
Serial.print((FuncState & FN_BIT_04) ? 1 : 0);
|
||||
#endif
|
||||
break;
|
||||
case FN_5_8:
|
||||
FN_5_8_state = FuncState;
|
||||
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.print(FuncState);
|
||||
Serial.print(" FN 5: ");
|
||||
Serial.print((FuncState & FN_BIT_05) ? 1 : 0);
|
||||
Serial.print(" FN 6: ");
|
||||
Serial.print((FuncState & FN_BIT_06) ? 1 : 0);
|
||||
Serial.print(" FN 7: ");
|
||||
Serial.print((FuncState & FN_BIT_07) ? 1 : 0);
|
||||
Serial.print(" FN 8: ");
|
||||
Serial.print((FuncState & FN_BIT_08) ? 1 : 0);
|
||||
#endif
|
||||
break;
|
||||
case FN_9_12:
|
||||
FN_9_12_state = FuncState;
|
||||
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.print(FuncState);
|
||||
Serial.print(" FN 9: ");
|
||||
Serial.print((FuncState & FN_BIT_09) ? 1 : 0);
|
||||
Serial.print(" FN 10: ");
|
||||
Serial.print((FuncState & FN_BIT_10) ? 1 : 0);
|
||||
Serial.print(" FN 11: ");
|
||||
Serial.print((FuncState & FN_BIT_11) ? 1 : 0);
|
||||
Serial.print(" FN 12: ");
|
||||
Serial.print((FuncState & FN_BIT_12) ? 1 : 0);
|
||||
#endif
|
||||
break;
|
||||
case FN_13_20:
|
||||
FN_13_20_state = FuncState;
|
||||
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.print(FuncState);
|
||||
Serial.print(" FN 13: ");
|
||||
Serial.print((FuncState & FN_BIT_13) ? 1 : 0);
|
||||
Serial.print(" FN 14: ");
|
||||
Serial.print((FuncState & FN_BIT_14) ? 1 : 0);
|
||||
Serial.print(" FN 15: ");
|
||||
Serial.print((FuncState & FN_BIT_15) ? 1 : 0);
|
||||
Serial.print(" FN 16: ");
|
||||
Serial.print((FuncState & FN_BIT_16) ? 1 : 0);
|
||||
Serial.print(" FN 17: ");
|
||||
Serial.print((FuncState & FN_BIT_17) ? 1 : 0);
|
||||
Serial.print(" FN 18: ");
|
||||
Serial.print((FuncState & FN_BIT_18) ? 1 : 0);
|
||||
Serial.print(" FN 19: ");
|
||||
Serial.print((FuncState & FN_BIT_19) ? 1 : 0);
|
||||
Serial.print(" FN 20: ");
|
||||
Serial.print((FuncState & FN_BIT_20) ? 1 : 0);
|
||||
#endif
|
||||
break;
|
||||
case FN_21_28:
|
||||
FN_21_28_state = FuncState;
|
||||
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print(" FuncState: ");
|
||||
Serial.print(FuncState);
|
||||
Serial.print(" FN 21: ");
|
||||
Serial.print((FuncState & FN_BIT_21) ? 1 : 0);
|
||||
Serial.print(" FN 22: ");
|
||||
Serial.print((FuncState & FN_BIT_22) ? 1 : 0);
|
||||
Serial.print(" FN 23: ");
|
||||
Serial.print((FuncState & FN_BIT_23) ? 1 : 0);
|
||||
Serial.print(" FN 24: ");
|
||||
Serial.print((FuncState & FN_BIT_24) ? 1 : 0);
|
||||
Serial.print(" FN 25: ");
|
||||
Serial.print((FuncState & FN_BIT_25) ? 1 : 0);
|
||||
Serial.print(" FN 26: ");
|
||||
Serial.print((FuncState & FN_BIT_26) ? 1 : 0);
|
||||
Serial.print(" FN 27: ");
|
||||
Serial.print((FuncState & FN_BIT_27) ? 1 : 0);
|
||||
Serial.print(" FN 28: ");
|
||||
Serial.print((FuncState & FN_BIT_28) ? 1 : 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This call-back function is called whenever we receive a DCC Packet and message-debugging is activated
|
||||
#ifdef DEBUG_DCC_MSG
|
||||
void notifyDccMsg( DCC_MSG * Msg)
|
||||
{
|
||||
Serial.print("notifyDccMsg, Number of Preamble Bits: ") ;
|
||||
Serial.print (Msg->PreambleBits);
|
||||
Serial.print("; Data Bytes: ");
|
||||
for(uint8_t i = 0; i < Msg->Size; i++)
|
||||
{
|
||||
Serial.print(Msg->Data[i], HEX);
|
||||
Serial.write(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
// This call-back function is called by the NmraDcc library when a DCC ACK needs to be sent
|
||||
// Calling this function should cause an increased 60ma current drain on the power supply for 6ms to ACK a CV Read
|
||||
// So we will just turn the motor on for 8ms and then turn it off again.
|
||||
// Pay attention to your control station, as it may limit power consumption on the programming track
|
||||
// (e.g. EX-CommandStation needs the command <D PROGBOOST> sent before programming to allow a
|
||||
// power consumption of more than 250mA and ACK working properly)
|
||||
|
||||
void notifyCVAck(void)
|
||||
{
|
||||
#ifdef DEBUG_DCC_ACK
|
||||
Serial.println("notifyCVAck") ;
|
||||
#endif
|
||||
|
||||
digitalWrite(MOTOR_PIN_1, HIGH);
|
||||
digitalWrite(MOTOR_PIN_2, LOW);
|
||||
|
||||
delay( 8 );
|
||||
|
||||
digitalWrite(MOTOR_PIN_1, LOW);
|
||||
digitalWrite(MOTOR_PIN_2, LOW);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
Serial.begin(115200);
|
||||
uint8_t maxWaitLoops = 255;
|
||||
while(!Serial && maxWaitLoops--)
|
||||
delay(20);
|
||||
|
||||
Serial.println("DCCMFL1616 Debugging interface");
|
||||
Serial.print("Decoder-Address: ");
|
||||
Serial.println(Dcc.getCV(CV_MULTIFUNCTION_PRIMARY_ADDRESS), DEC);
|
||||
#endif
|
||||
|
||||
// Setup the Pins for the Fwd/Rev LED for Function 0 Headlight
|
||||
pinMode(LED_PIN_WHITE_FRONT, OUTPUT);
|
||||
pinMode(LED_PIN_WHITE_REAR, OUTPUT);
|
||||
pinMode(LED_PIN_RED_FRONT, OUTPUT);
|
||||
pinMode(LED_PIN_RED_REAR, OUTPUT);
|
||||
pinMode(LED_PIN_CABIN, OUTPUT);
|
||||
|
||||
// Setup the Pins for the Motor H-Bridge Driver
|
||||
pinMode(MOTOR_PIN_1, OUTPUT);
|
||||
pinMode(MOTOR_PIN_2, OUTPUT);
|
||||
|
||||
|
||||
// Setup which External Interrupt, the Pin it's associated with that we're using and enable the Pull-Up
|
||||
// Many Arduino Cores now support the digitalPinToInterrupt() function that makes it easier to figure out the
|
||||
// Interrupt Number for the Arduino Pin number, which reduces confusion.
|
||||
#ifdef digitalPinToInterrupt
|
||||
Dcc.pin(DCC_PIN, 0);
|
||||
#else
|
||||
Dcc.pin(0, DCC_PIN, 1);
|
||||
#endif
|
||||
|
||||
Dcc.init( MAN_ID_DIY, DEFAULT_VERSION_ID, FLAGS_MY_ADDRESS_ONLY | FLAGS_AUTO_FACTORY_DEFAULT, 0 );
|
||||
|
||||
// Uncomment to force CV Reset to Factory Defaults; usually not needed
|
||||
// notifyCVResetFactoryDefault();
|
||||
|
||||
// Read the current CV values
|
||||
vStart = Dcc.getCV(CV_VSTART);
|
||||
vHigh = Dcc.getCV(CV_VHIGH);
|
||||
accRate = Dcc.getCV(CV_ACC_RATE);
|
||||
decRate = Dcc.getCV(CV_DEC_RATE);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// You MUST call the NmraDcc.process() method frequently from the Arduino loop() function for correct library operation
|
||||
Dcc.process();
|
||||
// Handle Speed changes
|
||||
if(targetSpeed != newSpeed) {
|
||||
targetSpeed = newSpeed;
|
||||
if (newSpeed <= 1) {
|
||||
targetPwm = 0;
|
||||
}
|
||||
else {
|
||||
// Calculate PWM value in the range 1..255
|
||||
uint8_t vScaleFactor;
|
||||
|
||||
vScaleFactor = ((vHigh > 1) && (vHigh > vStart)) ? vHigh - vStart : 255 - vStart;
|
||||
|
||||
uint8_t modSpeed = newSpeed - 1;
|
||||
uint8_t modSteps = numSpeedSteps - 1;
|
||||
|
||||
targetPwm = (uint8_t) vStart + modSpeed * vScaleFactor / modSteps;
|
||||
|
||||
#ifdef DEBUG_PWM
|
||||
Serial.print("New Speed: vStart: ");
|
||||
Serial.print(vStart);
|
||||
Serial.print(" vHigh: ");
|
||||
Serial.print(vHigh);
|
||||
Serial.print(" modSpeed: ");
|
||||
Serial.print(modSpeed);
|
||||
Serial.print(" vScaleFactor: ");
|
||||
Serial.print(vScaleFactor);
|
||||
Serial.print(" modSteps: ");
|
||||
Serial.print(modSteps);
|
||||
Serial.print(" targetPwm: ");
|
||||
Serial.println(targetPwm);
|
||||
#endif
|
||||
}
|
||||
lastPwm = currentPwm;
|
||||
speedChangeTime = millis();
|
||||
}
|
||||
|
||||
if(targetPwm > currentPwm) {
|
||||
currentPwm = (accRate == 0) ? targetPwm : lastPwm + floor( (vHigh - vStart) * (millis() - speedChangeTime) / (accRate * 0.896 * 1000) + 0.5);
|
||||
if (currentPwm < vStart) {
|
||||
currentPwm = vStart;
|
||||
lastPwm = vStart;
|
||||
}
|
||||
else if (currentPwm > targetPwm) currentPwm = targetPwm;
|
||||
#ifdef DEBUG_PWM
|
||||
Serial.print("increase speed; accRate: ");
|
||||
Serial.print(accRate);
|
||||
Serial.print(" currentPwm: ");
|
||||
Serial.print(currentPwm);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
else if(targetPwm < currentPwm) {
|
||||
currentPwm = (decRate == 0) ? targetPwm : lastPwm - floor( (vHigh - vStart) * (millis() - speedChangeTime) / (decRate * 0.896 * 1000) + 0.5);
|
||||
if (currentPwm < targetPwm) currentPwm = targetPwm;
|
||||
if (currentPwm < vStart) currentPwm = 0;
|
||||
|
||||
#ifdef DEBUG_PWM
|
||||
Serial.print("reduce Speed; decRate: ");
|
||||
Serial.print(decRate);
|
||||
Serial.print(" currentPwm: ");
|
||||
Serial.print(currentPwm);
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
analogWrite(MOTOR_PIN_1, newDirection ? currentPwm : 0);
|
||||
analogWrite(MOTOR_PIN_2, newDirection ? 0 : currentPwm);
|
||||
|
||||
/*
|
||||
* lighting
|
||||
*/
|
||||
//F0 & F5 white LEDs front
|
||||
digitalWrite(LED_PIN_WHITE_FRONT, ( FN_0_4_state & FN_BIT_00 & (newDirection << 4 | FN_5_8_state << 4 ) ) ? HIGH : LOW);
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("whithe LEDs front: ");
|
||||
Serial.println( ( FN_0_4_state & FN_BIT_00 & (newDirection << 4 | FN_5_8_state << 4 ) ) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
//F0 & F5 white LEDs rear
|
||||
digitalWrite(LED_PIN_WHITE_REAR, ( FN_0_4_state & FN_BIT_00 & (~(newDirection << 4) | FN_5_8_state << 4 ) ) ? HIGH : LOW);
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("whithe LEDs rear: ");
|
||||
Serial.println( ( FN_0_4_state & FN_BIT_00 & (~(newDirection << 4) | FN_5_8_state << 4 ) ) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
//F1 red LEDs front
|
||||
digitalWrite(LED_PIN_RED_FRONT, ( FN_0_4_state & FN_BIT_00 & ~(newDirection << 4) & FN_0_4_state << 4 & ~(FN_5_8_state << 4) ) ? HIGH : LOW);
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("RED LEDs front: ");
|
||||
Serial.println( ( FN_0_4_state & FN_BIT_00 & ~(newDirection << 4) & FN_0_4_state << 4 & ~(FN_5_8_state << 4) ) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
//F1 red LEDs rear
|
||||
digitalWrite(LED_PIN_RED_REAR, ( FN_0_4_state & FN_BIT_00 & newDirection << 4 & FN_0_4_state << 4 & ~(FN_5_8_state << 4) ) ? HIGH : LOW);
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("RED LEDs rear: ");
|
||||
Serial.println( ( FN_0_4_state & FN_BIT_00 & newDirection << 4 & FN_0_4_state << 4 & ~(FN_5_8_state << 4) ) ? 1 : 0);
|
||||
#endif
|
||||
|
||||
//F6 cabin light (standard: only works if white LED front/rear active)
|
||||
digitalWrite(LED_PIN_CABIN, (FN_5_8_state & FN_BIT_06 & invert_cabin_light_logic << 1) ? LOW : HIGH );
|
||||
#ifdef DEBUG_FUNCTIONS
|
||||
Serial.print("CABIN LEDs: ");
|
||||
Serial.println( (FN_5_8_state & FN_BIT_06 & invert_cabin_light_logic << 1) ? LOW : HIGH );
|
||||
#endif
|
||||
|
||||
// Handle resetting CVs back to Factory Defaults
|
||||
if( FactoryDefaultCVIndex && Dcc.isSetCVReady())
|
||||
{
|
||||
FactoryDefaultCVIndex--; // Decrement first as initially it is the size of the array
|
||||
Dcc.setCV( FactoryDefaultCVs[FactoryDefaultCVIndex].CV, FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
#ifdef DEBUG_DCC_RESET
|
||||
Serial.print("Factory reset: ");
|
||||
Serial.print("CV");
|
||||
Serial.print(FactoryDefaultCVs[FactoryDefaultCVIndex].CV);
|
||||
Serial.print(" = ");
|
||||
Serial.println(FactoryDefaultCVs[FactoryDefaultCVIndex].Value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user