Scope: I know this rough question has been around a few times. Once again, I would like to attach a non-static member function to an interrupt, but I know that is not directly possible.
Details: I am trying to write a lib for reading PWM signals. In particular, I want to read three PWM channels from an RGB controller. I presume that they are in sync, but lacking a multi channel oscilloscope, I do not know that for certain, so the plan is to read the three inputs in series, to get rid of problems with lost interrupt calls at both simultaneously rising and falling flanks.
Since I have multiple objects, the usually suggested hacks with global functions are not really feasible, at least not without severely cluttering my main code, which is already long enough. (I actually started the lib because I lose overview, due to a lack of keyword highlighting, a function index and all that stuff in the Arduino IDE.)
Any ideas how to solve this with minimal code in the main sketch? I am far from a C++ pro, actually I looked up syntax in a few other libs, but I do know OOP from other ... more forgiving languages.
Here is the code of how it would look if I COULD supply member functions to attachInterrupt. Note that I am on an ESP, so my interrupts are addressed with pin numbers and all pins support interrupts.
header:
#ifndef PWMREADER_H
#define PWMREADER_H
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
extern "C" {
typedef void (*callbackFunction)(void);
}
class PWMReader
{
public:
PWMReader(const unsigned int pwmPinAttr); // Constructor
void attachCallback(callbackFunction newFunction);
void probe();
void rising1InterrFunc();
void rising2InterrFunc();
void fallingInterrFunc();
uint8_t pwmPin;
volatile unsigned long pwm_value = 0;
volatile unsigned long riseTime = 0;
volatile unsigned long fallTime = 0;
private:
callbackFunction _valueFunc;
};
#endif
cpp:
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "PWMReader.h"
PWMReader::PWMReader(const unsigned int pwmPinAttr)
{
pwmPin = pwmPinAttr;
}
void PWMReader::attachCallback(callbackFunction newFunction)
{
_valueFunc = newFunction;
}
void PWMReader::probe()
{
attachInterrupt(pwmPin,PWMReader::rising1InterrFunc,RISING);
}
void PWMReader::rising1InterrFunc()
{
riseTime = micros();
attachInterrupt(pwmPin,fallingInterrFunc,FALLING);
}
void PWMReader::fallingInterrFunc()
{
fallTime = micros();
attachInterrupt(pwmPin,rising2InterrFunc,RISING);
}
void PWMReader::rising2InterrFunc()
{
unsigned long now = micros();
pwm_value = (fallTime - riseTime) * 100 / (now - riseTime);
if (_valueFunc) _valueFunc();
detachInterrupt(pwmPin);
}
Example sketch:
#include <PWMReader.h>
PWMReader pwmreader[] = {{D1}, {D2}, {D3}};
const uint8_t pwmreader_N = 3;
uint8_t pwmreader_current = 0;
void setup() {
Serial.begin(115200);
for (int i = 0; i < pwmreader_N; i++)
pwmreader[i].attachCallback(processNewPWM);
pwmreader[0].probe();
}
void loop() {
}
void processNewPWM() {
if (pwmreader_current == pwmreader_N-1)
{
for (int i = 0; i < pwmreader_N; i++)
{
Serial.print(pwmreader[i].pwm_value); // Output for Serial plotter
Serial.print(" ");
}
Serial.println();
}
pwmreader_current = (pwmreader_current+1)%pwmreader_N;
pwmreader[pwmreader_current].probe();
}
This is not primarily a learning project for me (though I take what I get!), so a ready made lib which deals with multiple, potentially simultaneous PWM signals would also be highly appreciated.