This question/issue is a follow-on to this thread.
Taking Paul MurrayCBR’s suggestion I’ve been looking into virtual functions to realize multiple timer types. I have an example which works but it’s not exactly what I want.
For background, the previous incarnation of the attached code consisted of a derived class with no added functionality, that is, essentially a clone of the base PLCtimer
class. This did work just like the base class only with a different name.
Specifically, what I thought I could do is: Make the set/get functions, the timer increment part and the setting/resetting of the done, timing, and one-shot statuses common to all timer types and break out how and when the timer resets into a virtual function (see the commented out ‘----- Time to reset?’ section in the code)
The attached code does work but, there should be noReset()
in the main code. Resetting the timer should be handled automatically and invisibly within the derived class. To wit – the given timer type runs and sets done true when preset is reached based on_Reset
being false and _Enable
being true. For all other conditions the timer is reset.
I hope this makes some kind of sense.
I don’t know if these are even valid questions but:
Is it possible to do this or, do I need to make a complete, unique update function (implementation?) for each timer class?
If it is possible, is there any difference in flash memory usage or execution time between the two?
Will uninstantiated versions consume any flash memory or are they optimized away at compile time? I lean toward the latter but, I don't know.
/*
Attempt to convert basic timer to polymorhic/inherited form
*/
#include <Bounce2.h>
#define BUTTON_PIN 8 // to enable the timer
#define LED_PIN 13
#define RESET_PIN 9
// Instantiate a Bounce object
Bounce debouncer = Bounce();
// create a class called 'PLCtimer'
class PLCtimer {
/*
All types:
> produce a positive-going one-scan pulse 'os' upon reaching
preset value.
> respond to a reset command by setting accumulated value to
zero and resetting done and tt.
> set the done bit upon reaching preset.
*/
public:
// constructor - permits setting of variables upon instantiation
PLCtimer::PLCtimer(unsigned long pre)
{
_Preset = pre;
negativePresetWarning(pre); // preset validation
}; // end constructor
/*
User-added error handler from pert @ Arduino.cc, post #13
thread http://forum.arduino.cc/index.php?topic=559655.new#new
*/
void negativeError( void ) __attribute__((error("Negative PLCtimer preset! Check instantiations!")));
void negativePresetWarning(int number) {
if (number < 0) {
negativeError();
}
}
/*
===== Access functions for timer status/controls
*/
void setEN(bool en) {
_Enable = en;
}
void setres(bool res) {
_Reset = res;
}
byte getEN() {
return _Enable;
}
bool getres() {
return _Reset;
}
bool getDn() {
return _Done;
}
bool getTt() {
return _TimerRunning;
}
bool getIntv() {
return _TimerRunning;
}
bool getOSRise() {
return _OSRise;
}
bool getOSFall() {
return _OSFall;
}
/*
Virtual timer Reset function
*/
// virtual void Reset() ;
unsigned long currentMillis;
// Function to operate timers created under PLCtimer
// ----------------------------------------
// Update timer accumulated value & condition
// flags 'tt' (timer timing) and 'dn' (done) based
// on timer type.
// Function returns boolean status of done, 'dn'
// ===========================
boolean update() {
currentMillis = millis();
if (_Enable) { // timer is enabled to run
_TimeDelta = currentMillis - _LastMillis;
_LastMillis = currentMillis;
_Accumulator = _Accumulator + _TimeDelta;
if (_Accumulator >= _Preset) { // timer done?
_Accumulator = _Preset;
_Done = true;
}
}
else { // timer not enabled
_LastMillis = currentMillis;
}
/*
----- Time to reset? Reset feature moved to individual derived classes
*/
// if (_Reset == true or (!_Enable and !_Type == RTO)
// or (_Type == OSGEN and _OSRise)) {
// _Done = false; // show timer as not done
// _Accumulator = 0; // reset accumulated value to zero
// }
/*
----- Generate a positive going one-shot pulse on timer done f-t transition
*/
_OSRise = (_Done and _OSRSetup);
_OSRSetup = !_Done;
/*
----- and another positive going one-shot pulse on timer done t-f transition
*/
_OSFall = (!_Done and _OSFSetup);
_OSFSetup = _Done;
/*
----- condition the timer timing bit
*/
if (_Enable and !_Done and !_Reset) {//experiment to simplify tt logic
_TimerRunning = true;
}
else _TimerRunning = false;
/*
if (_Reset) _TimerRunning = false;
if (!_Enable) _TimerRunning = false;
if (_Enable and _Done) _TimerRunning = false;
*/
return _Done;
}; // end of update Timer operation
public:
unsigned long _Preset;
unsigned long _Accumulator = 0;
unsigned long _LastMillis = 0;
byte _Done: 1;
byte _TimerRunning: 1;
byte _OSRise: 1;
byte _OSFall: 1;
byte _OSRSetup: 1;
bool _OSFSetup: 1;
bool _Enable: 1;
byte _Reset: 1;
unsigned long _TimeDelta;
}; // end of class PLCtimer
class OnDelay_tmr: public PLCtimer
// successfully instantiated sans self-contained reset capability
{
public:
OnDelay_tmr(unsigned long pre): PLCtimer(pre)
{}
void Reset() {
if (_Reset or !_Enable) {
_Done = false; // show timer as not done
_Accumulator = 0; // reset accumulated value to zero
}
// return _Done;
}
};
//---------------
// Instantiate timer object(s)
//---------------
//
OnDelay_tmr TimerTwo(1500UL);
void setup() {
// Configure pushbuttons with an internal pull-up :
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RESET_PIN, INPUT_PULLUP);
// After setting up the button, setup the Bounce instance :
debouncer.attach(BUTTON_PIN);
debouncer.interval(5); // interval in ms
//Setup the LED :
pinMode(LED_PIN, OUTPUT);
//
Serial.begin(230400); // open serial monitor comms.
}
void loop() {
static int count;
TimerTwo.update(); // update timer status
TimerTwo.Reset(); // check if timer needs to be reset
Serial.print(TimerTwo.getDn());
if (TimerTwo.getOSRise()) {
count++;
Serial.println(count);
}
TimerTwo.setEN( digitalRead(BUTTON_PIN));
TimerTwo.setres( !digitalRead(RESET_PIN));
if (TimerTwo.getDn())
digitalWrite(LED_PIN, HIGH); // tell when timer is done
else digitalWrite(LED_PIN, LOW); // tell when timer is not done
} //end of loop
Thanks.