{"id":20275102,"url":"https://github.com/luni64/teensyhelpers","last_synced_at":"2025-07-30T23:36:28.357Z","repository":{"id":97961099,"uuid":"294880434","full_name":"luni64/TeensyHelpers","owner":"luni64","description":"A couple of utility functions and classes to improve usage of the Teensy IntervalTimer class, the attachInterrupt and the pinMode function.","archived":false,"fork":false,"pushed_at":"2023-02-15T08:51:35.000Z","size":87,"stargazers_count":22,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-10T23:45:13.099Z","etag":null,"topics":["attachinterrupt","initializer-list","intervaltimer","pin-interrupts","pinmode","std-function","teensy","timer","yield"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luni64.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-09-12T05:54:45.000Z","updated_at":"2025-03-29T06:15:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"cbb434ab-f23e-446f-89e6-44e169e8da8a","html_url":"https://github.com/luni64/TeensyHelpers","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/luni64/TeensyHelpers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luni64%2FTeensyHelpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luni64%2FTeensyHelpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luni64%2FTeensyHelpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luni64%2FTeensyHelpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luni64","download_url":"https://codeload.github.com/luni64/TeensyHelpers/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luni64%2FTeensyHelpers/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259831326,"owners_count":22918497,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attachinterrupt","initializer-list","intervaltimer","pin-interrupts","pinmode","std-function","teensy","timer","yield"],"created_at":"2024-11-14T13:07:58.949Z","updated_at":"2025-06-14T14:33:49.836Z","avatar_url":"https://github.com/luni64.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"This repository contains some helper functions and classes for the PJRC Teensy boards:\n\n# Content\n- [IntervalTimerEx](#intervaltimerex)\\\n    Subclasses the standard IntervalTimer to allow passing state to callbacks. You can choose between attaching `std::function\u003cvoid()\u003e` callbacks or the traditional void pointer pattern.\n\n- [attachInterruptEx](#attachinterruptex)\\\n    Overloads the attachInterrupt function to allow attaching `std::function\u003cvoid()\u003e` callbacks.\n\n- [pinModeEx](#pinModeEx)\\\n  Overloaded version of the pinMode function which can set the pin mode for a arbitrary long list of pins.\n\n- [attachYieldFunc](#attachyieldfunc)\\\n  Add your own function to the yield call stack\n\n- [teensy_clock](#teensy_clock)\\\n  Use the new c++11 ```std::chrono``` time system to implement a\n  `std::chrono` compliant clock which uses the cycle counter as time base. It counts time in 1.667ns steps (1/F_CPU)  since 0:00h 1970-01-01.\n\n- [instanceList](#instancelist)\\\n  Helper to automatically maintain a list of all active objects of a class and call\n  member functions on all of these objects. Helpful for example if you need to periodically tick all existing objects of a class.\n\n\n**All functions and classes use the underlying Teensyduino mechanisms and bookkeeping. They can mixed with the standard ones.**\n\n# Installation:\nI didn't bother to make this a library. To use it just copy the `*.h` and  `*.cpp` files from the corresponding  subfolders of `/src` into your sketch to use them.\n\n-----\n\n# IntervalTimerEx\n\n`IntervalTimerEx` subclasses the stock `IntervalTimer` so that you can\npass state to the timer callbacks. IntervalTimerEx provides either a traditional `void(*)(void*)` pattern or, more modern `std::function\u003c\u003e` typed callbacks. You can choose which to use with a preprocessor switch in `IntervalTimer.h`\n\n- **`std::function` approach:**\\\nUsage is exactly the same as with the normal IntervalTimer. However, it accepts more or less anything witch can be called (functions, member functions, lambdas, functors) as callbacks.\n\n- **Traditional void pointer approach:**\\\nMight be more familiar to some users. Uses less resources, doesn't use dynamic memory. You define the state which is passed to the callback function in `IntervalTimer.begin()`.\n\n# Examples:\n\n## **std::function approach**\n\n```c++\n#include \"IntervalTimerEx.h\"\n\n// plain vanilla void(*)() callback\nvoid myCallback_0(){\n    Serial.print(\"myCallback_0 \");\n    Serial.println(millis());\n}\n\n// need to manipulate the calling timer in the callback?\nvoid myCallback_1(IntervalTimer* caller){\n    Serial.print(\"--\u003e myCallback_1 \");\n    Serial.println(millis());\n\n    caller-\u003eend(); // e.g. do a one shot timer\n}\n\nIntervalTimerEx t1, t2;\n\nvoid setup(){\n    t1.begin(myCallback_0, 150'000);\n    t2.begin([] { myCallback_1(\u0026t2); }, 1'000'000);  // attach callback using a lambda\n}\n\nvoid loop(){\n}\n```\n\n### Embedding in a user class\n\n```c++\n#include \"IntervalTimerEx.h\"\n\nclass DeepThought\n{\n public:\n    void begin()\n    {\n        answer = 42;\n        t1.begin([this] { ISR(); }, 7.5E6);  // 7.5s\n    }\n\n protected:\n    IntervalTimerEx t1;\n    int answer;\n\n    void ISR()\n    {\n        Serial.printf(\"The answer is %d\\n\", answer);\n    }\n};\n\n//----------------------------\n\nDeepThought deepThought;\n\nvoid setup(){\n    deepThought.begin();\n}\n\nvoid loop(){\n}\n```\n\n## Traditional void pointer approach:\n\nComment out the preprocessor switch `#define USE_CPP11_CALLBACKS` in  `IntervalTimerEx.h` to use this pattern.\n\n### One shot timer\n```c++\n#include \"IntervalTimerEx.h\"\n\n// implement a one shot timer by using the timer address\n// passed to the callback\nvoid myCallback_1(void* state){\n    IntervalTimer* timer = (IntervalTimer*)state;\n    Serial.printf(\"Called @\\t%d ms\\n\", millis());\n    timer-\u003eend();\n}\n//------------------\n\nIntervalTimerEx t1;\n\nvoid setup(){\n    while(!Serial);\n    Serial.printf(\"Triggered @\\t%d ms\\n\", millis());\n    t1.begin(myCallback_1, \u0026t1, 200'000); // pass the address of the timer to the callback\n}\n\nvoid loop(){\n}\n```\nOutput:\n```\nTriggered @\t388 ms\nCalled @\t588 ms\n```\n\n\n### Embedding an IntervalTimer in a user class\n```c++\nclass DeepThought\n{\n public:\n    void begin()\n    {\n        answer = 42;\n        t1.begin(ISR, this, 7.5E6); // 7.5s\n    }\n\n protected:\n    IntervalTimerEx t1;\n    int answer;\n\n    static void ISR(void* obj)\n    {\n        DeepThought* THIS = (DeepThought*)obj;\n        Serial.printf(\"The answer is %d\\n\", THIS-\u003eanswer);\n    }\n};\n\nDeepThougth deepThought;\n\nvoid setup(){\n    deepThought.begin();\n}\n\nvoid loop(){\n}\n```\n\n# attachInterruptEx\n\nYou can use `attachInterruptEx` in exactly the same as you use the standard `attachInterrupt` function. However, it accepts more or less anything witch can be called (functions, member functions, lambdas, functors) as callbacks.\n\n## Examples\n\nShows how to encapsulate and setup a pin interrupt callback function in a user class. The EdgeCounter class simply counts all edges (rising/falling) it sees on a digital pin.  The pin to be monitored is settable with the `begin()` function.\n\n```c++\n#include \"attachInterruptEx.h\"\n\nclass EdgeCounter\n{\n public:\n    void begin(unsigned pin)\n    {\n        counter = 0;\n        pinMode(pin, INPUT_PULLUP);\n        attachInterruptEx(pin, [this] { this-\u003eISR(); }, CHANGE);\n    }\n\n    unsigned getCounter() { return counter; }\n\n protected:\n    void ISR(){\n        counter++;\n    }\n\n    unsigned counter;\n};\n\n//-------------------------\n\nEdgeCounter ec1, ec2;\n\nvoid setup(){\n    ec1.begin(0);\n    ec2.begin(1);\n}\n\nvoid loop(){\n    Serial.printf(\"Detected edges: Pin1: %u Pin2:%u\\n\", ec1.getCounter(), ec2.getCounter());\n    delay(250);\n}\n\n```\n\n# pinModeEx\nOne often has to define the pin mode for a bunch of pins which can be a bit tedious. In the folder `src/pinModeEx` you find an overloaded version of the `pinMode` function which allows to set the mode for an arbitrary large list of pins.\n\nUsage:\n```c++\n#include \"pinModeEx.h\"\n\nconst int pinA = 3, pinB = 17, switch1 = 3, switch2 = 4;\n\nvoid setup(){\n    pinMode({pinA, pinB, 17, LED_BUILTIN}, OUTPUT);  // set a bunch of pins to mode OUTPUT...\n    pinMode({switch1, switch2}, INPUT_PULLUP);       // others to INPUT\n}\n```\n\n# attachYieldFunc()\n\nSometimes your have code that needs to be called by the user as often as possible. Prominent examples are AccelStepper where you are required to call `run()` at high speed. Using the debounce library, you need to call `update()`. The PID library requires a frequent call to `Compute()` and so on.\n\nUsually, the user of these libraries just calls these functions in loop which works fine for simple code. As soon as there is longer running code or some delays in loop the call rate of these functions can get unacceptably low and the libraries don't work as expected.\n\n### yield()\nTeensyduino provides a yield() function which is called before each call to loop(), during delay() and probably during a lot of other long running core functions while they spin.\n\nIf you want to add your own functions to be called from yield without completely overriding it, you can use `attachYieldFunc(callback)` which is defined in the `src/attachYieldFunc` folder of the repository.\nHere an example which will call `myCallback()` from yield to toggle pin 0 in the background. The `delay(250)` in loop does not disturb the high frequency background toggling since `delay()` calls yield while it spins.\n\n```c++\n#include \"attachYieldFunc.h\"\n\nvoid myCallback(){ //will be called from yield\n  digitalToggleFast(0);\n}\n\nvoid setup(){\n  pinMode(LED_BUILTIN, OUTPUT);\n  pinMode(0, OUTPUT);\n\n  attachYieldFunc(myCallback); // attach our callback to the yield stack\n}\n\nvoid loop(){\n  digitalToggleFast(LED_BUILTIN);\n  delay(250);\n}\n```\n\n# teensy_clock\n\nThis extension implements a clock compliant to the new (\u003ec++11) `chrono::system_clock`.\n\nIt uses a 64bit extension of the cycle counter where rollover is handled  by the periodic timer of the SNVS_HPCR module.\n\nThe teensy_clock can be synced to the the built in RTC. It doesn't interfere with the normal use of the RTC functions and works with or without battery. Other than the usual Teensy RTC functions which are based on full seconds, the teensy_clock uses the full resolution of the cycle counter which is 1/600MHz = 1.6667 ns for a T4@ 600MHz.\n\nA full description of the code can be found in the Teensy User WIKI:\nhttps://github.com/TeensyUser/doc/wiki/fun-with-modern-cpp#start\n\n\nExample:\n\n```c++\n#include \u003cchrono\u003e\nusing namespace std::chrono;\n\ntypedef system_clock::time_point timePoint;               // save typing...\n\nvoid setup(){\n    while(!Serial){}\n}\n\nvoid loop()\n{\n    timePoint start = teensy_clock::now();                // generate two time points 1234ms apart\n    delay(1234);\n    timePoint stop = system_clock::now();\n\n    nanoseconds  dt    = stop - start;                    // system clock has an underlying ns counter\n    milliseconds dt_ms = duration_cast\u003cmilliseconds\u003e(dt); // cast dt to milliseconds (float)\n\n    Serial.printf(\"stop-start: %u ms\\n\", dt_ms.count());\n\n    time_t t = system_clock::to_time_t(start);            // convert the time_point 'start' to usual time_t\n    Serial.printf(\"Current Time: %s\\n\", ctime(\u0026t));       // pretty print date/time\n}\n```\n\nWhich prints out:\n```\nstop-start: 1234 ms\nCurrent Time: Sun Oct 18 21:01:37 2020\n\nstop-start: 1234 ms\nCurrent Time: Sun Oct 18 21:01:38 2020\n\nstop-start: 1234 ms\nCurrent Time: Sun Oct 18 21:01:39 2020\n\nstop-start: 1234 ms\nCurrent Time: Sun Oct 18 21:01:40 2020\n...\n```\n\nUse the system_clock to wait...\n\n```c++\n#include \u003cchrono\u003e\nusing namespace std::chrono;\n\nvoid setup(){\n}\n\nvoid loop()\n{\n    auto start = teensy_clock::now();  // current time point\n\n    while (teensy_clock::now() \u003c (start + 1h + 30min)) // use chrono literals\n    {\n        yield(); // waiting...\n    }\n\n    Serial.println(\"done\");\n}\n```\n\n# instanceList\n\nThis helper class automatically maintains a list of all currently existing instances of a class regardless if they are constructed on the stack, the heap or in global space. The list of instances is accessible using standard c++ iterators.\n\nPossible use cases are classes where you need to periodically call a function on all objects.\n\n## Example\nHere a very simple example which demonstrates the usage of the instanceList helper class.\n\nLet's assume we want to define a `Blinker` class which periodically toggles a pin. Pin number and toggling period will be set in the constructor.\n\nTo toggle the pin we implement a `blink()` member function. Whenever `blink()` is called, it simply checks an `elapsedMicros` variable to determine if it is time to toggle the pin. To get good performance, it is important to call `blink()` as often as possible.\n\n\n```c++\nclass Blinker\n{\n public:\n    Blinker(int _pin, unsigned ms)\n        : pin(_pin), period(ms * 1000)\n    {\n        pinMode(pin, OUTPUT);\n    }\n\n    void blink()\n    {\n        if (t \u003e period)\n        {\n            digitalToggleFast(pin);\n            t -= period;\n        }\n    }\n\n private:\n    elapsedMicros t;\n    unsigned pin, period;\n};\n```\n\nUsage\n```c++\nBlinker b(0,10); // toggles pin 0 every 10ms\n\nvoid setup()\n{\n}\n\nvoid loop()\n{\n    b.blink();\n}\n```\nSo far, so good. However, if you need a lot of those Blinkers, the code can get messy quickly. Also, those Blinkers might as well be defined in a different file or in some functions and it can get difficult to keep track of  all the existing Blinkers.\n```c++\nBlinker b1(0,10);\nBlinker b2(7,100);\nBlinker b3(2,24);\nBlinker b4(13,500);\n\nvoid setup()\n{\n}\n\nvoid loop()\n{\n    b1.blink();\n    b2.blink();\n    b3.blink();\n    b4.blink();\n}\n```\nOf course, it would be a lot simpler if one could call the `blink()` function for all currently existing Blinker instances at once. Using the `instanceList` this can be done easily. All we need to do is derive the Blinker class from `instanceList`. To blink all instances we define a static function `tick()` which\nuses the list of instances provides and calls blink on each of them:\n```c++\nclass Blinker : protected InstanceList\u003cBlinker\u003e  // \u003c- derive from InstanceList\n{\n public:\n    Blinker(int _pin, unsigned ms)\n        : pin(_pin), period(ms * 1000)\n    {\n        pinMode(pin, OUTPUT);\n    }\n\n    void blink()\n    {\n        if (t \u003e period)\n        {\n            digitalToggleFast(pin);\n            t -= period;\n        }\n    }\n\n    static void tick()\n    {\n        for (Blinker\u0026 b : instanceList) // for each Blinker b in the instance list\n        {\n            b.blink();\n        }\n    }\n\n private:\n    elapsedMicros t;\n    unsigned pin, period;\n};\n```\n\nUsage:\n```c++\nBlinker b0(0, 10);\nBlinker b1(1, 60);\nBlinker b2(2, 24);\nBlinker b3(3, 150);\nBlinker LED(13, 500);\n\nvoid setup()\n{\n}\n\nvoid loop()\n{\n    Blinker::tick();\n}\n```\nNow, we can add and remove Blinkers without having to to update the calls to blink() accordingly.\n\nYou can use the instanceList for other things as well. Assume you want to print out information about all currently exisiting Blinker instances. Just add the following member function to the Blinker class:\n\n```c++\nstatic void InstanceInfo()\n{\n  for (Blinker\u0026 b : instanceList) // for each object in objectList\n  {\n     Serial.printf(\"pin: %2d, period (µs): %6d, address: %p\\n\", b.pin, b.period, \u0026b);\n  }\n}\n```\nThen, you can print the information by:\n\n```c++\nBlinker b0(0, 10);\nBlinker b1(1, 60);\nBlinker b2(2, 24);\nBlinker b3(3, 150);\nBlinker LED(13, 500);\n\nvoid setup()\n{\n    while(!Serial){}\n    Blinker::InstanceInfo();\n}\n\nvoid loop()\n{\n    Blinker::tick();\n}\n```\n\nwhich prints:\n```\npin: 13, period (µs): 500000, address: 0x20001864\npin:  3, period (µs): 150000, address: 0x20001908\npin:  2, period (µs):  24000, address: 0x200018f8\npin:  1, period (µs):  60000, address: 0x200018e8\npin:  0, period (µs):  10000, address: 0x200018d8\n```\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluni64%2Fteensyhelpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluni64%2Fteensyhelpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluni64%2Fteensyhelpers/lists"}