diff --git a/examples/TwoSimulators/TwoSimulators.ino b/examples/TwoSimulators/TwoSimulators.ino new file mode 100644 index 0000000..7adf02d --- /dev/null +++ b/examples/TwoSimulators/TwoSimulators.ino @@ -0,0 +1,33 @@ +#include "EncSim.h" + +EncSim e1(0, 1, 2); // A=0, B=1, Z=2 +EncSim e2(3, 4, 5); // A=2, B=3; Z=5 + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); + + e1 + .begin() + .setFrequency(1000) // 1000 pps + .setPeriod(500) // Index every 500 pulses + .setPhase(90) // 90° phase signal + .setTotalBounceDuration(0); // no bouncing + + e2 + .begin() + .setFrequency(7000) // 1000 pps + .setPeriod(1500) // Index every 500 pulses + .setPhase(90) // 90° phase signal + .setTotalBounceDuration(0); // no bouncing + + + e1.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647 + e2.moveRelAsync(INT32_MAX); // run for some time INT32_MAX = 2147483647 +} + +void loop() +{ + Serial.printf("e1: %d, e2: %d\n", e1.current, e2.current); + delay(100); +} \ No newline at end of file diff --git a/library.properties b/library.properties index 590ad84..cb8d63e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=EncSim -version=2.2.0.0 +version=2.3.0 author=Lutz Niggl maintainer=Lutz Niggl sentence=Quadrature Signal Generator diff --git a/src/EncSim.cpp b/src/EncSim.cpp index 2a9603e..395d608 100644 --- a/src/EncSim.cpp +++ b/src/EncSim.cpp @@ -1,10 +1,8 @@ #include "EncSim.h" -static EncSim* This; // hack, allows one instance only EncSim::EncSim(unsigned pinA, unsigned pinB, unsigned pinZ) { - This = this; this->A = pinA; this->B = pinB; this->Z = pinZ; @@ -12,8 +10,6 @@ EncSim::EncSim(unsigned pinA, unsigned pinB, unsigned pinZ) EncSim& EncSim::begin(/*unsigned pinA, unsigned pinB, int pinZ*/) { - //CCM_CSCMR1 &= ~CCM_CSCMR1_PERCLK_CLK_SEL; // set PIT clock to 150MHz - phaseA.begin(A); phaseB.begin(B); if (Z < UINT32_MAX) @@ -43,7 +39,7 @@ void EncSim::moveAbsAsync(int _target) direction = (target >= current) ? 1 : -1; if (!running) - mainTimer.begin([] { This->pitISR(); }, T[current & 1]); + mainTimer.begin([this] {pitISR(); }, T[current & 1]); running = true; } diff --git a/src/EncSim.h b/src/EncSim.h index 09c09fb..1cc4ef9 100644 --- a/src/EncSim.h +++ b/src/EncSim.h @@ -1,6 +1,7 @@ #pragma once #include "BouncingPin.h" +#include "IntervalTimerEx.h" #include "TeensyTimerTool.h" #include @@ -33,9 +34,7 @@ class EncSim EncSim& setBounceDurationMin(unsigned microseconds); EncSim& setBounceDurationMax(unsigned microseconds); - - protected: - + protected: void pitISR() { current += direction; @@ -47,7 +46,7 @@ class EncSim if (Z < UINT32_MAX) { - digitalWriteFast(Z, ((current - 2) % period) == 0); // current-2 to have the zero pulse on the rising edge of B + digitalWriteFast(Z, ((current - 2) % period) == 0); // current-2 to have the zero pulse on the rising edge of B } if (current & 1) @@ -71,5 +70,5 @@ class EncSim unsigned period; BouncingPin phaseA, phaseB; - IntervalTimer mainTimer; + IntervalTimerEx mainTimer; }; diff --git a/src/IntervalTimerEx.cpp b/src/IntervalTimerEx.cpp new file mode 100644 index 0000000..e5474aa --- /dev/null +++ b/src/IntervalTimerEx.cpp @@ -0,0 +1,51 @@ +#include "IntervalTimerEx.h" + + +IntervalTimerEx::~IntervalTimerEx() +{ + end(); +} + +void IntervalTimerEx::end() +{ + callbacks[index] = nullptr; + IntervalTimer::end(); +} + + +// generate and preset the callback storage +callback_t IntervalTimerEx::callbacks[4]{ + nullptr, + nullptr, + nullptr, + nullptr, +}; + +#if defined (USE_CPP11_CALLBACKS) + +relay_t IntervalTimerEx::relays[4]{ + [] { callbacks[0](); }, + [] { callbacks[1](); }, + [] { callbacks[2](); }, + [] { callbacks[3](); }, +}; + +#else + +// generate the static array of relay functions +relay_t IntervalTimerEx::relays[4]{ + [] { callbacks[0](states[0]); }, + [] { callbacks[1](states[1]); }, + [] { callbacks[2](states[2]); }, + [] { callbacks[3](states[3]); }, +}; + +// storage for the state values +void* IntervalTimerEx::states[4]{ + nullptr, + nullptr, + nullptr, + nullptr, +}; + +#endif \ No newline at end of file diff --git a/src/IntervalTimerEx.h b/src/IntervalTimerEx.h new file mode 100644 index 0000000..aa588c2 --- /dev/null +++ b/src/IntervalTimerEx.h @@ -0,0 +1,84 @@ +#pragma once + +#include "Arduino.h" + +#define USE_CPP11_CALLBACKS // comment out if you want to use the traditional void pointer pattern to pass state to callbacks + +#if defined(USE_CPP11_CALLBACKS) + #include + using callback_t = std::function; + using relay_t = void (*)(); + +#else + using callback_t = void (*)(void*); + using relay_t = void (*)(); +#endif + + +class IntervalTimerEx : public IntervalTimer +{ + public: + template // begin is implemented as template to avoid replication the various versions of IntervalTimer::begin + #if defined(USE_CPP11_CALLBACKS) + bool begin(callback_t callback, period_t period); + #else + bool begin(callback_t callback, void* state, period_t period); + #endif + + void end(); + ~IntervalTimerEx(); + + protected: + unsigned index = 0; + static callback_t callbacks[4]; // storage for callbacks + static relay_t relays[4]; // storage for relay functions + #if !defined(USE_CPP11_CALLBACKS) + static void* states[4]; // storage for state variables + #endif + +}; + +// Inline implementation =============================================== + + + #if defined(USE_CPP11_CALLBACKS) +template +bool IntervalTimerEx::begin(std::function callback, period_t period) +{ + for (index = 0; index < 4; index++) // find the next free slot + { + if (callbacks[index] == nullptr) // ->free slot + { + if (IntervalTimer::begin(relays[index], period)) // we got a slot but we need to also get an actual timer + { + callbacks[index] = callback; // if ok -> store callback + return true; + } + return false; + } + } + return false; // can never happen if bookkeeping is ok +} + +#else // traditional void pointer pattern to pass state to callbacks + + template + bool IntervalTimerEx::begin(callback_t callback, void* state, period_t period) + { + for (index = 0; index < 4; index++) // find the next free slot + { + if (callbacks[index] == nullptr) // ->free slot + { + if (IntervalTimer::begin(relays[index], period)) // we got a slot but we need to also get an actual timer + { + callbacks[index] = callback; // if ok -> store callback... + states[index] = state; // ...and state + return true; + } + return false; + } + } + return false; // can never happen if bookkeeping is ok + } + +#endif \ No newline at end of file