1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2024-11-30 03:26:13 +01:00

Merge pull request #4 from Asbelos/overcurrent-sense

Overcurrent sense
This commit is contained in:
Asbelos 2020-07-12 18:54:15 +01:00 committed by GitHub
commit cb4d9823b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 52 additions and 12 deletions

View File

@ -71,7 +71,14 @@ DCCEXParser serialParser;
// Try monitoring the memory // Try monitoring the memory
#include "freeMemory.h" #include "freeMemory.h"
// TODO: this should be automated instead of ifdef
#if defined(ARDUINO_AVR_MEGA2560)
int minMemory=32767; int minMemory=32767;
#elif defined(ARDUINO_AVR_UNO)
int minMemory=2048;
#else
#error CANNOT COMPILE - Unkown board, can not determine amount of RAM available.
#endif
void setup() { void setup() {
@ -89,8 +96,10 @@ void setup() {
// and a 9600 baud rate. // and a 9600 baud rate.
// setup(serial, F(router name), F(password) , port) // setup(serial, F(router name), F(password) , port)
// //
#ifdef WIFI
Serial1.begin(115200); Serial1.begin(115200);
WifiInterface::setup(Serial1, F("BTHub5-M6PT"), F("49de8d4862"),3532); // (3532 is 0xDCC decimal... ) WifiInterface::setup(Serial1, F("BTHub5-M6PT"), F("49de8d4862"),3532); // (3532 is 0xDCC decimal... )
#endif
// This is just for demonstration purposes // This is just for demonstration purposes
DIAG(F("\n===== CVReader demonstrating DCC::getLocoId() call ==========\n")); DIAG(F("\n===== CVReader demonstrating DCC::getLocoId() call ==========\n"));
@ -116,7 +125,9 @@ void loop() {
serialParser.loop(Serial); serialParser.loop(Serial);
// Responsibility 3: Optionally handle any incoming WiFi traffic // Responsibility 3: Optionally handle any incoming WiFi traffic
#ifdef WIFI
WifiInterface::loop(Serial1); WifiInterface::loop(Serial1);
#endif
// Your additional code e.g. Report any decrease in memory // Your additional code e.g. Report any decrease in memory
int freeNow=freeMemory(); int freeNow=freeMemory();

View File

@ -1,22 +1,29 @@
#ifndef Config_h #ifndef Config_h
#define Config_h #define Config_h
// Define this if you have a WiFi board on Serial1
// #define WIFI
// This hardware configuration would normally be setup using a bunch of #ifdefs. // This hardware configuration would normally be setup using a bunch of #ifdefs.
const byte UNUSED_PIN = 255;
const byte MAIN_POWER_PIN = 3; const byte MAIN_POWER_PIN = 3;
const byte MAIN_SIGNAL_PIN = 12; const byte MAIN_SIGNAL_PIN = 12;
const byte MAIN_SIGNAL_PIN_ALT = 0; // for hardware that flipflops signal pins const byte MAIN_SIGNAL_PIN_ALT = UNUSED_PIN; // for hardware that flipflops signal pins
const byte MAIN_SENSE_PIN = A0; const byte MAIN_SENSE_PIN = A0;
const byte MAIN_BRAKE_PIN = 9; const byte MAIN_BRAKE_PIN = 9;
const byte MAIN_FAULT_PIN = UNUSED_PIN;
const int MAIN_MAX_MILLIAMPS=2000; const int MAIN_MAX_MILLIAMPS=2000;
const float MAIN_SENSE_FACTOR=2.99; // analgRead(MAIN_SENSE_PIN) * MAIN_SENSE_FACTOR = milliamps const float MAIN_SENSE_FACTOR=2.99; // analgRead(MAIN_SENSE_PIN) * MAIN_SENSE_FACTOR = milliamps
const byte PROG_POWER_PIN = 11; const byte PROG_POWER_PIN = 11;
const byte PROG_SIGNAL_PIN = 13; const byte PROG_SIGNAL_PIN = 13;
const byte PROG_SIGNAL_PIN_ALT = 0; // for hardware that flipflops signal pins const byte PROG_SIGNAL_PIN_ALT = UNUSED_PIN; // for hardware that flipflops signal pins
const byte PROG_SENSE_PIN = A1; const byte PROG_SENSE_PIN = A1;
const byte PROG_BRAKE_PIN = 8; const byte PROG_BRAKE_PIN = 8;
const byte PROG_FAULT_PIN = UNUSED_PIN;
const int PROG_MAX_MILLIAMPS=250; const int PROG_MAX_MILLIAMPS=250;
const float PROG_SENSE_FACTOR=2.99; // analgRead(PROG_SENSE_PIN) * PROG_SENSE_FACTOR = milliamps const float PROG_SENSE_FACTOR=2.99; // analgRead(PROG_SENSE_PIN) * PROG_SENSE_FACTOR = milliamps

View File

@ -93,7 +93,9 @@ POWERMODE DCCWaveform::getPowerMode() {
void DCCWaveform::setPowerMode(POWERMODE mode) { void DCCWaveform::setPowerMode(POWERMODE mode) {
powerMode = mode; powerMode = mode;
Hardware::setPower(isMainTrack, mode == POWERMODE::ON); bool ison = (mode == POWERMODE::ON);
Hardware::setPower(isMainTrack, ison);
Hardware::setBrake(isMainTrack, !ison);
if (mode == POWERMODE::ON) delay(200); if (mode == POWERMODE::ON) delay(200);
} }
@ -112,13 +114,20 @@ void DCCWaveform::checkPowerOverload() {
case POWERMODE::ON: case POWERMODE::ON:
// Check current // Check current
lastCurrent = Hardware::getCurrentRaw(isMainTrack); lastCurrent = Hardware::getCurrentRaw(isMainTrack);
if (lastCurrent <= tripValue) sampleDelay = POWER_SAMPLE_ON_WAIT; if (lastCurrent <= tripValue) {
else { sampleDelay = POWER_SAMPLE_ON_WAIT;
if(power_good_counter<100)
power_good_counter++;
else
if (power_sample_overload_wait>POWER_SAMPLE_OVERLOAD_WAIT) power_sample_overload_wait=POWER_SAMPLE_OVERLOAD_WAIT;
} else {
setPowerMode(POWERMODE::OVERLOAD); setPowerMode(POWERMODE::OVERLOAD);
unsigned int mA=Hardware::getCurrentMilliamps(isMainTrack,lastCurrent); unsigned int mA=Hardware::getCurrentMilliamps(isMainTrack,lastCurrent);
unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,tripValue); unsigned int maxmA=Hardware::getCurrentMilliamps(isMainTrack,tripValue);
DIAG(F("\n*** %S TRACK POWER OVERLOAD current=%d max=%d ***\n"), isMainTrack ? F("MAIN") : F("PROG"), mA, maxmA); DIAG(F("\n*** %S TRACK POWER OVERLOAD current=%d max=%d offtime=%l ***\n"), isMainTrack ? F("MAIN") : F("PROG"), mA, maxmA, power_sample_overload_wait);
sampleDelay = POWER_SAMPLE_OVERLOAD_WAIT; power_good_counter=0;
sampleDelay = power_sample_overload_wait;
power_sample_overload_wait *= 2;
} }
break; break;
case POWERMODE::OVERLOAD: case POWERMODE::OVERLOAD:

View File

@ -22,7 +22,7 @@
const int POWER_SAMPLE_ON_WAIT = 100; const int POWER_SAMPLE_ON_WAIT = 100;
const int POWER_SAMPLE_OFF_WAIT = 1000; const int POWER_SAMPLE_OFF_WAIT = 1000;
const int POWER_SAMPLE_OVERLOAD_WAIT = 4000; const int POWER_SAMPLE_OVERLOAD_WAIT = 20;
const int MIN_ACK_PULSE_DURATION = 3000; const int MIN_ACK_PULSE_DURATION = 3000;
const int MAX_ACK_PULSE_DURATION = 8500; const int MAX_ACK_PULSE_DURATION = 8500;
@ -97,6 +97,8 @@ class DCCWaveform {
unsigned int sampleDelay; unsigned int sampleDelay;
int rawCurrentTripValue; int rawCurrentTripValue;
static const int ACK_CURRENT_TRIP=1000; // During ACK processing limit can be higher static const int ACK_CURRENT_TRIP=1000; // During ACK processing limit can be higher
unsigned long power_sample_overload_wait = POWER_SAMPLE_OVERLOAD_WAIT;
unsigned int power_good_counter = 0;
// ACK management (Prog track only) // ACK management (Prog track only)
bool ackPending; bool ackPending;

View File

@ -33,14 +33,18 @@
void Hardware::init() { void Hardware::init() {
pinMode(MAIN_POWER_PIN, OUTPUT); pinMode(MAIN_POWER_PIN, OUTPUT);
pinMode(MAIN_BRAKE_PIN, OUTPUT);
pinMode(MAIN_SIGNAL_PIN, OUTPUT); pinMode(MAIN_SIGNAL_PIN, OUTPUT);
if (MAIN_SIGNAL_PIN_ALT) pinMode(MAIN_SIGNAL_PIN_ALT, OUTPUT); if (MAIN_SIGNAL_PIN_ALT != UNUSED_PIN) pinMode(MAIN_SIGNAL_PIN_ALT, OUTPUT);
pinMode(MAIN_SENSE_PIN, INPUT); pinMode(MAIN_SENSE_PIN, INPUT);
if (MAIN_FAULT_PIN != UNUSED_PIN) pinMode(MAIN_FAULT_PIN, INPUT);
pinMode(PROG_POWER_PIN, OUTPUT); pinMode(PROG_POWER_PIN, OUTPUT);
pinMode(PROG_BRAKE_PIN, OUTPUT);
pinMode(PROG_SIGNAL_PIN, OUTPUT); pinMode(PROG_SIGNAL_PIN, OUTPUT);
if (PROG_SIGNAL_PIN_ALT) pinMode(PROG_SIGNAL_PIN_ALT, OUTPUT); if (PROG_SIGNAL_PIN_ALT != UNUSED_PIN) pinMode(PROG_SIGNAL_PIN_ALT, OUTPUT);
pinMode(PROG_SENSE_PIN, INPUT); pinMode(PROG_SENSE_PIN, INPUT);
if (PROG_FAULT_PIN != UNUSED_PIN) pinMode(PROG_FAULT_PIN, INPUT);
} }
void Hardware::setPower(bool isMainTrack, bool on) { void Hardware::setPower(bool isMainTrack, bool on) {
@ -54,10 +58,16 @@ void Hardware::setSignal(bool isMainTrack, bool high) {
byte pin = isMainTrack ? MAIN_SIGNAL_PIN : PROG_SIGNAL_PIN; byte pin = isMainTrack ? MAIN_SIGNAL_PIN : PROG_SIGNAL_PIN;
byte pin2 = isMainTrack ? MAIN_SIGNAL_PIN_ALT : PROG_SIGNAL_PIN_ALT; byte pin2 = isMainTrack ? MAIN_SIGNAL_PIN_ALT : PROG_SIGNAL_PIN_ALT;
WritePin(pin, high ? HIGH : LOW); WritePin(pin, high ? HIGH : LOW);
if (pin2) WritePin(pin2, high ? LOW : HIGH); if (pin2 != UNUSED_PIN) WritePin(pin2, high ? LOW : HIGH);
} }
int Hardware::getCurrentRaw(bool isMainTrack) { int Hardware::getCurrentRaw(bool isMainTrack) {
// tooo much crap for a interrupt routine. Will see how that goes.
byte faultpin = isMainTrack ? MAIN_FAULT_PIN : PROG_FAULT_PIN;
byte signalpin = isMainTrack ? MAIN_SIGNAL_PIN : PROG_SIGNAL_PIN;
if (faultpin != UNUSED_PIN && digitalRead(faultpin) == LOW && digitalRead(signalpin) == HIGH)
return 32767; // MAXINT because we don't know the actual current, return as high as we can
// IMPORTANT: This function can be called in Interrupt() time within the 56uS timer // IMPORTANT: This function can be called in Interrupt() time within the 56uS timer
// The default analogRead takes ~100uS which is catastrphic // The default analogRead takes ~100uS which is catastrphic
// so analogReadFast is used here. (-2uS) // so analogReadFast is used here. (-2uS)

View File

@ -51,6 +51,7 @@ void StringFormatter::send2(Print & stream,const __FlashStringHelper* format, va
case 'E': printEscapes(stream,(const __FlashStringHelper*)va_arg(args, char*)); break; case 'E': printEscapes(stream,(const __FlashStringHelper*)va_arg(args, char*)); break;
case 'S': stream.print((const __FlashStringHelper*)va_arg(args, char*)); break; case 'S': stream.print((const __FlashStringHelper*)va_arg(args, char*)); break;
case 'd': stream.print(va_arg(args, int), DEC); break; case 'd': stream.print(va_arg(args, int), DEC); break;
case 'l': stream.print(va_arg(args, long), DEC); break;
case 'b': stream.print(va_arg(args, int), BIN); break; case 'b': stream.print(va_arg(args, int), BIN); break;
case 'o': stream.print(va_arg(args, int), OCT); break; case 'o': stream.print(va_arg(args, int), OCT); break;
case 'x': stream.print(va_arg(args, int), HEX); break; case 'x': stream.print(va_arg(args, int), HEX); break;