|
| 1 | +# ArduinoThread |
| 2 | + |
| 3 | +A simple way to run multiple stuff in Arduino. |
| 4 | + |
| 5 | +NO, Arduino does not support "REAL" parallel tasks, but we can make use of this Class to |
| 6 | +improve our code, and easily schedule tasks with fixed (or variable) time between runs. |
| 7 | + |
| 8 | +This Library helps to maintain organized and to facilitate the use of multiple tasks. We can |
| 9 | +use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks on the rug. |
| 10 | + |
| 11 | +For example, I personaly use it for all my projects, and put all sensor aquisition and |
| 12 | +filtering inside it, leaving the main loop, just for logic and "cool" part. |
| 13 | + |
| 14 | +## Instalation |
| 15 | + |
| 16 | +1. "Download":https://github.com/ivanseidel/ArduinoThread/archive/master.zip the Master branch from gitHub. |
| 17 | +2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master') |
| 18 | +3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software). |
| 19 | + |
| 20 | +**If you are here, because another Library requires this class, just don't waste time reading bellow. Install and ready.** |
| 21 | + |
| 22 | + |
| 23 | +## Getting Started |
| 24 | + |
| 25 | +There are many examples showing many ways to use it. Here, we will explain Class itself, |
| 26 | +what it does and "how" it does. |
| 27 | + |
| 28 | +There are basicaly, two Classes included in this Library: |
| 29 | +`Thread` and `ThreadController` (that inherits from Thread). |
| 30 | + |
| 31 | +- `Thread class`: This is the basic class, witch contains methods to set and run callbacks, |
| 32 | + check if the Thread should be runned, and also creates a unique ThreadID on the instantiation. |
| 33 | + |
| 34 | +- `ThreadController class`: Responsable for "holding" multiple Threads. Can also be called |
| 35 | + as "a group of Threads", and is used to perform run in every Thread ONLY when needed. |
| 36 | + |
| 37 | +* The instantiation of a Thread class is very simple: |
| 38 | + |
| 39 | +```c++ |
| 40 | +Thread myThread = Thread(); |
| 41 | +// or, if initializing a pointer |
| 42 | +Thread* myThread = new Thread(); |
| 43 | +``` |
| 44 | + |
| 45 | + |
| 46 | +* Setting up a thread is essential. You can configure many things: |
| 47 | + |
| 48 | +```c++ |
| 49 | +myThread.enabled = true; // Default enabled value is true |
| 50 | +myThread.setInterval(10); // Setts the wanted interval to be 10ms |
| 51 | +/* |
| 52 | + This is useful for debugging |
| 53 | + (Thread Name is disabled by default, to use less memory) |
| 54 | + (Enable it by definint USE_THREAD_NAMES on 'Thread.h') |
| 55 | +*/ |
| 56 | +myThread.ThreadName = "myThread tag"; |
| 57 | +// This will set the callback of the Thread: "What should I run"? |
| 58 | +myThread.onRun(callback_function); // callback_function is the name of the function |
| 59 | + |
| 60 | + |
| 61 | +Ok, creating Threads are not so hard. But what do we do with them now? |
| 62 | + |
| 63 | +* First, let's see how Threads should work, to understand what a `ThreadController` is and does |
| 64 | +
|
| 65 | +```c++ |
| 66 | +// First check if our Thread "should" be runned |
| 67 | +if(myThread.shouldRun()){ |
| 68 | + // Yes, the Thread should be runned, let's run it |
| 69 | + myThread.run(); |
| 70 | +} |
| 71 | + |
| 72 | +Now that you got the idea, let's think a little bit: What if i have 3, 5, 100 Threads. Do I need to check EACH one?!? |
| 73 | +
|
| 74 | +* The answer is: NO. Create a `ThreadController`, and put all your boring-complex Threads inside it! |
| 75 | +
|
| 76 | +```c++ |
| 77 | +// Instantiate a new ThreadController |
| 78 | +ThreadController controller = ThreadController(); |
| 79 | +// Now, put a bunch of Threads inside it, FEED it! |
| 80 | +controller.add(&myThread); // Notice the & before the thread, IF it's not instantied as a pointer. |
| 81 | +controller.add(&hisThread); |
| 82 | +controller.add(&sensorReadings); |
| 83 | +... |
| 84 | + |
| 85 | +* You have created, configured, grouped it. What is missing? Yes, whe should RUN it! |
| 86 | + |
| 87 | +```c++ |
| 88 | +// call run on a Thread or a ThreadController to run it |
| 89 | +controller.run(); |
| 90 | + |
| 91 | +This will run all the Threads that NEED to be runned. |
| 92 | + |
| 93 | +Congratulations, you have learned the basics of `ArduinoThread`. If you want some TIPS, see bellow. |
| 94 | + |
| 95 | + |
| 96 | +### TIPs and Warnings |
| 97 | + |
| 98 | +* ThreadController is not a `LinkedList`. It's "MAXIMUM" size (the maximum Threads that it can |
| 99 | + store) is defined on ThreadController.h (default is 15) |
| 100 | +
|
| 101 | +* !!!! VERY IMPORTANT !!!! When extending `Thread` class and implementing the function |
| 102 | + `run()`, always remember to put `runned();` after all, otherwhise the `Thread` will ALWAYS run. |
| 103 | +
|
| 104 | +* It's a good idea, to create a Timer interrupt and call a ThreadController.run() there. |
| 105 | +That way, you don't need to worry about reading sensors and doing time-sensitive stuff |
| 106 | +on your main code (loop). Check `ControllerWithTimer` example. |
| 107 | +
|
| 108 | +* Inheriting from `Thread` or even `ThreadController` is always a good idea. |
| 109 | +For example, I always create base classes of sensors that extends `Thread`, |
| 110 | +so that I can "register" the sensors inside a ThreadController, and forget |
| 111 | +about really reading sensors, just getting theirs values within my main code. |
| 112 | +Checkout `SensorThread` example. |
| 113 | +
|
| 114 | +* Remember that `ThreadController` is in fact, a Thread. If you want to enable |
| 115 | +or disable a GROUP of Threads, think about putting all of them inside a ThreadController, |
| 116 | +and adding this ThreadController to another ThreadController (YES! One ThreadController |
| 117 | +inside another). Check `ControllerInController` example. |
| 118 | +
|
| 119 | +* Check the full example `CustomTimedThread` for a cool application of Threads that runs |
| 120 | +for a period, after a button is pressed. |
| 121 | +
|
| 122 | +* Running tasks on the Timer interrupts must be tought REALLY carefully |
| 123 | + |
| 124 | + You cannot use "sleep()" inside a interrupt, because it will get into a infinite loop. |
| 125 | + |
| 126 | + Things must do stuff quickly. Waiting too loooong on a interrupt, means waiting too |
| 127 | + loooong on the main code (loop) |
| 128 | +
|
| 129 | + Things might get "scrambled". Since Timers interrupts actualy "BREAK" your code in half |
| 130 | + and start running the interrupt, you might want to call `noInterrupts` and `interrupts` |
| 131 | + on places where cannot be interrupted: |
| 132 | +
|
| 133 | +```c++ |
| 134 | +noInterrupts(); |
| 135 | +// Put the code that CANNOT be interrupted... |
| 136 | +interrupts(); // This will enable the interrupts egain. DO NOT FORGET! |
| 137 | +
|
| 138 | +
|
| 139 | +## Library Reference |
| 140 | +
|
| 141 | +### You should know: |
| 142 | +
|
| 143 | +- `bool Thread::enabled` - Enables or disables the Thread. (do not stop it from running, but will |
| 144 | + return false when shouldRun() is called) |
| 145 | +
|
| 146 | +- `void Thread::setInterval()` - Setts the desired interval for the Thread (in Ms). |
| 147 | +
|
| 148 | +- `bool Thread::shouldRun()` - Returns true, if the Thread should be runned. |
| 149 | + (Basicaly,the logic is: (reached time AND is enabled?). |
| 150 | +
|
| 151 | +- `void Thread::onRun(<function>)` - The target callback function to be called. |
| 152 | +
|
| 153 | +- `void Thread::run()` - This will run the Thread (call the callback function). |
| 154 | +
|
| 155 | +- `int Thread::ThreadID` - Theoretically, it's the address of memory. It's unique, and can |
| 156 | + be used to compare if two threads are identical. |
| 157 | +
|
| 158 | +- `int Thread::ThreadName` - A human-redable thread name. Default is "Thread ThreadID" |
| 159 | + eg.: "Thread 141515"; Note that to enable this attribute, you must uncomment the line that disables it on 'Thread.h'; |
| 160 | +
|
| 161 | +- protected: `void Thread::runned()` - Used to reset internal timer of the Thread. |
| 162 | + This is automaticaly called AFTER a call to `run()`. |
| 163 | +
|
| 164 | +
|
| 165 | +- `void ThreadController::run()` - This will run the all `Threads` within the `ThreadController`, |
| 166 | + only if needed (if shouldRun returns true); |
| 167 | +
|
| 168 | +- `bool ThreadController::add(Thread* _thread)` - This will add a the thread to the ThreadController, |
| 169 | + and return `true` if suceeded (it the array is full, returns false). |
| 170 | +
|
| 171 | +- `void ThreadController::remove(Thread* _thread)` - This will remove the Thread from the ThreadController. |
| 172 | +
|
| 173 | +- `void ThreadController::remove(int index)` - This will remove the thread on the position `index`. |
| 174 | +
|
| 175 | +- `void ThreadController::clear()` - This will remove ALL threads from the ThreadController array. |
| 176 | +
|
| 177 | +- `void ThreadController::size(bool cached = true)` - Returns how many Threads are allocated |
| 178 | + inside the ThreadController. If cached is `false`, will force the calculation of threads. |
| 179 | +
|
| 180 | +- `Thread* ThreadController::get(int index)` - Returns the Thread on the position `index`. |
| 181 | +
|
| 182 | +### You don't need to know: |
| 183 | +- Nothing, yet ;) |
| 184 | + |
| 185 | +## Version History |
| 186 | + |
| 187 | +* `(Jun/2014): New Example: ControllerWithTimer` |
| 188 | +* `1.0 (2013-05-11): Initial release.` |
| 189 | + |
| 190 | +!https://d2weczhvl823v0.cloudfront.net/ivanseidel/ArduinoThread/trend.png(ArduinoThread)! |
0 commit comments