but I have not had any success getting things to work. See below:
unsigned long nextVoidNoArgsFunction = 0;
unsigned long nextVoidOneArgFunction = 0;
long returnedValue = 0;
void setup() {
Serial.begin(9600);
}
void doFunctionAtInterval( void ( *callBackFunction )(), unsigned long *nextEvent, unsigned long interval ) {
unsigned long now = millis();
if ( now >= *nextEvent ) {
*nextEvent = now + interval;
callBackFunction();
}
}
/*
// Trying to overload doFunctionAtInterval here, but get compiler error on callbackFunction(*alue); line
void doFunctionAtInterval( void ( *callBackFunction )(float *value), unsigned long *nextEvent, unsigned long interval ) {
unsigned long now = millis();
if ( now >= *nextEvent ) {
*nextEvent = now + interval;
callBackFunction(*alue);
}
}
*/
void loop() {
doFunctionAtInterval(voidNoArgsFunction, &nextVoidNoArgsFunction, 400);
/*
// No success here with efforts so far, but this is the shape of how I'd like it to work
doFunctionAtInterval(voidOneArgFunction(&returnedValue), &nextVoidOneArgFunction, 1000);
*/
// This works, but feels like cheating
doFunctionAtInterval(encapsulatingVoidOneArgFunction, &nextVoidOneArgFunction, 1000);
}
void voidOneArgFunction(long *value) {
*value = random(0,100);
}
void voidNoArgsFunction() {
Serial.println(returnedValue);
}
void encapsulatingVoidOneArgFunction() {
voidOneArgFunction(&returnedValue);
}
void doFunctionAtInterval( void ( *callBackFunction )(), unsigned long *nextEvent, unsigned long interval ) {
unsigned long now = millis();
if ( now >= *nextEvent ) {
*nextEvent = now + interval;
callBackFunction();
}
}
Making the last-sent variable local to the function means that no other function can mess with it. You could use the same name for that in every function and they don't interfere with each other. Making it static means that its value is preserved after the function exits.
void doFunctionAtInterval( void ( *callBackFunction )(), unsigned long *nextEvent, unsigned long interval ) {
unsigned long now = millis();
if ( now >= *nextEvent ) {
*nextEvent = now + interval;
callBackFunction();
}
}
Your method is flawed. What happens when now is a value close to the upper limit such that now+interval rolls over? Immediately, you next event will be triggered.
There is a reason why you can only use the 'now-startTime' type of calculations
but I have not had any success getting things to work. See below:
A general solution to this is possible, but far from easy. It requires extensive use of overloading, templates, and virtual member functions to create a versatile function object that can be used in the same way as a function pointer. If you need to ask what any of those things are, you're nowhere near good enough to try rolling your own solution to this.
The ArduinoSTL library appears to have a workable implementation of the functional library, but I haven't personally used it.
The easier way to do this is to create a void(void) function in your sketch that wraps around the function you want to use, and use that as the timer's callback.
MorganS:
Did this get split off from another topic? It doesn't seem to start with a question.
I read the sticky at the top of this forum regarding millis();
MorganS:
I prefer the first method... snipped for brevity
Thanks MorganS. Notwithstanding the flaws in the function I originally posted, sometimes I might call a function out of the regular timing sequence (especially updating displays etc). The timing logic within the function would prevent this from happening.
Updated code thanks to those who pointed out flaws...
void doFunctionAtInterval( void ( *callBackFunction )(), unsigned long *lastEvent, unsigned long interval ) {
unsigned long now = millis();
if(now - *lastEvent < interval) return;
*lastEvent = now;
callBackFunction();
}
Jiggy-Ninja:
A general solution to this is possible, but far from easy. It requires extensive use of overloading, templates, and virtual member functions to create a versatile function object that can be used in the same way as a function pointer. If you need to ask what any of those things are, you're nowhere near good enough to try rolling your own solution to this.
The ArduinoSTL library appears to have a workable implementation of the functional library, but I haven't personally used it.
The easier way to do this is to create a void(void) function in your sketch that wraps around the function you want to use, and use that as the timer's callback.
Thanks Jiggy. I was hoping there was just something relatively simple I was missing.
wiifm:
Thanks MorganS. Notwithstanding the flaws in the function I originally posted, sometimes I might call a function out of the regular timing sequence (especially updating displays etc). The timing logic within the function would prevent this from happening.
IMHO this suggests a flawed approach to program design.
As the creator you must know when writing the program which functions will need to operate at regular intervals and which ones may need to work at regular as well as irregular intervals.
The first type can have the timing code within them. The second type can be programmed to work whenever some control variable is true and that "truth" can be set by another function with regular timing and separately by some other part of the program that responds to some other event.
I have been writing a program that sends a standard response to the PC in reply to messages from the PC (which are regular) or whenever an LDR is triggered (which is asynchronous).
Whandall:
I've never seen or used the version without the dereferencing star, thanks for the info.
Any idea which C++ version started this behaviour?
It's been that way in C since just about forever, and probably the same in C++, because there's only one thing it could possibly mean (call the function pointed to by the function pointer). It's the same reason you don't need to use & to get the address of a function--a function name without parentheses already decays to a pointer to the function.
wiifm:
I read the sticky at the top of this forum regarding millis();
Thanks MorganS. Notwithstanding the flaws in the function I originally posted, sometimes I might call a function out of the regular timing sequence (especially updating displays etc). The timing logic within the function would prevent this from happening.
Well, display code can be different. My displays usually look like...
Some of my displays go right down to the individual characters, so that it doesn't need to redraw "12" when the displayed value changes from "123" to "124".