Add Library

This commit is contained in:
Siwat Sirichai 2019-08-09 09:01:56 +07:00
parent e365b9dbd9
commit 3c47103b39
318 changed files with 56465 additions and 0 deletions

View file

@ -0,0 +1,13 @@
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Ivan Seidel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,208 @@
![ArduinoThread Logo](https://raw.githubusercontent.com/ivanseidel/ArduinoThread/master/extras/ArduinoThread.png)
## ArduinoThreads Motivation
Arduino does not support isolated parallel tasks ([Threads](https://en.wikipedia.org/wiki/Thread_(computing))),
but we can make the main `loop` switch function execution conditionally and
thus simulate threading with [Protothread](https://en.wikipedia.org/wiki/Protothread) mechanism.
This library implements it and helps you to:
- schedule, manage and simplify parallel, periodic tasks
- define fixed or variable time between runs
- organize the code in any type of project
- put all sensor readings in a thread
- keep the main loop clean
- hide the complexity of thread management
- run "pseudo-background" tasks using Timer interrupts
Blinking an LED is often the very first thing an Arduino user learns.
And this demonstrates that periodically performing one single task, like toggling the LED state, is really easy.
However, one may quickly discover that managing multiple periodic tasks is not so simple
if the tasks have different schedule.
The user defines a Thread object for each of those tasks, then lets the library manage their scheduled execution.
It should be noted that these are not “threads” in the real computer-science meaning of the term:
tasks are implemented as functions that are run periodically.
On the one hand, this means that the only way a task can *yield* the CPU is by returning to the caller,
and it is thus inadvisable to `delay()` or do long waits inside any task.
On the other hand, this makes ArduinoThreads memory friendly, as no stack need to be allocated per task.
## Installation
1. Download [the Master branch](https://github.com/ivanseidel/ArduinoThread/archive/master.zip) from gitHub.
2. Unzip and modify the Folder name to "ArduinoThread" (Remove the '-master' suffix)
3. Paste the modified folder on your Library folder (On your `Libraries` folder inside Sketchbooks or Arduino software).
4. Restart the Arduino IDE
**If you are here just because another library requires a class from ArduinoThread, then you are done now
.**
## Getting Started
There are many examples showing many ways to use it. We will explain Class itself,
what it does and how it does.
There are three main classes included in the library:
`Thread`, `ThreadController` and `StaticThreadController` (both controllers inherit from `Thread`).
- `Thread`: Basic class, witch contains methods to set and run callbacks,
check if the Thread should be run, and also creates a unique ThreadID on the instantiation.
- `ThreadController`: Responsible for managing multiple Threads. Can also be thought of
as "a group of Threads", and is used to perform `run` in every Thread ONLY when needed.
- `StaticThreadController`: Slightly faster and smaller version of the `ThreadController`.
It works similar to `ThreadController`, but once constructed it can't add or remove threads to run.
#### Create Thread instance:
```c++
Thread myThread = Thread();
// or, if initializing a pointer
Thread* myThread = new Thread();
```
#### Setup thread behaviour
You can configure many things:
```c++
myThread.enabled = true; // Default enabled value is true
myThread.setInterval(10); // Setts the wanted interval to be 10ms
/*
This is useful for debugging
(Thread Name is disabled by default, to use less memory)
(Enable it by definint USE_THREAD_NAMES on 'Thread.h')
*/
myThread.ThreadName = "myThread tag";
// This will set the callback of the Thread: "What should I run"?
myThread.onRun(callback_function); // callback_function is the name of the function
```
#### Running threads manually
Ok, creating threads isn't too hard, but what do we do with them?
```c++
// First check if our Thread should be run
if(myThread.shouldRun()){
// Yes, the Thread should run, let's run it
myThread.run();
}
```
#### Running threads via a controller
If you had 3, 5 or 100 threads, managing them manually could become tedious.
That's when `ThreadController` or `StaticThreadController` comes into play and saves you the repetitive thread management parts of code.
```c++
// Instantiate new ThreadController
ThreadController controller = ThreadController();
// Now, put bunch of Threads inside it, FEED it!
controller.add(&myThread); // Notice the '&' sign before the thread, IF it's not instantied as a pointer.
controller.add(&hisThread);
controller.add(&sensorReadings);
...
```
or
```c++
// Instantiate a new StaticThreadController with the number of threads to be supplied as template parameter
StaticThreadController<3> controller (&myThread, &hisThread, &sensorReadings);
// You don't need to do anything else, controller now contains all the threads.
...
```
You have created, configured, grouped it. What is missing? Yes, whe should RUN it!
The following will run all the threads that NEED to run.
```c++
// call run on a Thread, a ThreadController or a StaticThreadController to run it
controller.run();
```
Congratulations, you have learned the basics of the `ArduinoThread` library. If you want to learn more, see bellow.
### Tips and Warnings
* `ThreadController` is not of a dynamic size (like a `LinkedList`). The maximum number of threads that it can manage
is defined in `ThreadController.h` (default is 15)
* ☢ When extending the `Thread` class and overriding the `run()` function,
remember to always call `runned();` at the end, otherwise the thread will hang forever.
* It's a good idea, to create a `Timer` interrupt and call a `ThreadController.run()` there.
That way, you don't need to worry about reading sensors and doing time-sensitive stuff
in your main code (`loop`). Check `ControllerWithTimer` example.
* Inheriting from `Thread` or even `ThreadController` is always a good idea.
For example, I always create base classes of sensors that extends `Thread`,
so that I can "register" the sensors inside a `ThreadController`, and forget
about reading sensors, just having the values available in my main code.
Check the `SensorThread` example.
* Remember that `ThreadController` is in fact, a `Thread` itself. If you want to group threads and
manage them together (enable or disable), think about putting all of them inside a `ThreadController`,
and adding this `ThreadController` to another `ThreadController` (YES! One inside another).
Check `ControllerInController` example.
* `StaticThreadController` is optimal when you know the exact number of
threads to run. You cannot add or remove threads at runtime, but it
doesn't require additional memory to keep all the treads together, doesn't limit the number of thread
(except for available memory) and the code may be slightly
better optimized because all the threads always exist and no need to do any runtime checks.
* Check the full example `CustomTimedThread` for a cool application of threads that run
for a period, after a button is pressed.
* Running tasks on the `Timer` interrupts must be thought though REALLY carefully
- You mustn't use `sleep()` inside an interrupt, because it would cause an infinite loop.
- Things execute quickly. Waiting too loooong on a interrupt, means waiting too
loooong on the main code (`loop`)
- Things might get "scrambled". Since Timers interrupts actually "BREAK" your code in half
and start running the interrupt, you might want to call `noInterrupts` and `interrupts`
on places where cannot be interrupted:
```c++
noInterrupts();
// Put the code that CANNOT be interrupted...
interrupts(); // This will enable the interrupts egain. DO NOT FORGET!
```
## Library Reference
### Configuration options
#### Thread
- `bool Thread::enabled` - Enables or disables the thread. (doesn't prevent it from running, but will
return `false` when `shouldRun()` is called)
- `void Thread::setInterval()` - Schedules the thread run interval in milliseconds
- `bool Thread::shouldRun()` - Returns true, if the thread should be run.
(Basically,the logic is: (reached time AND is enabled?).
- `void Thread::onRun(<function>)` - The target callback function to be called.
- `void Thread::run()` - Runs the thread (executes the callback function).
- `int Thread::ThreadID` - Theoretically, it's the memory address. It's unique, and can
be used to compare if two threads are identical.
- `int Thread::ThreadName` - A human-readable thread name.
Default is "Thread ThreadID", eg.: "Thread 141515".
Note that to enable this attribute, you must uncomment the line that disables it on `Thread.h`
- protected: `void Thread::runned()` - Used to reset internal timer of the thread.
This is automatically called AFTER a call to `run()`.
#### ThreadController
- `void ThreadController::run()` - Runs the all threads grouped by the controller,
but only if needed (if `shouldRun()` returns true);
- `bool ThreadController::add(Thread* _thread)` - Adds a the thread to the controller,
and returns `true` if succeeded (returns false if the array is full).
- `void ThreadController::remove(Thread* _thread)` - Removes the thread from the controller
- `void ThreadController::remove(int index)` - Removes the thread at the `index` position
- `void ThreadController::clear()` - Removes ALL threads from the controller
- `int ThreadController::size(bool cached = true)` - Returns number of threads allocated
in the ThreadController. Re-calculates thread count if `cached` is `false`
- `Thread* ThreadController::get(int index)` - Returns the thread at the `index` position
#### StaticThreadController
- `void StaticThreadController::run()` - Runs all the threads within the controller,
but only if needed (if `shouldRun()` returns true);
- `int StaticThreadController::size()` - Returns how many Threads are allocated inside the controller.
- `Thread* ThreadController::get(int index)` - Returns the thread at the `index` position - or `nullptr` if `index`
is out of bounds.

View file

@ -0,0 +1,75 @@
/*
StaticThreadController.h - Controlls a list of Threads with different timings
Basicaly, what it does is to keep track of current Threads and run when
necessary.
StaticThreadController is an extended class of Thread, because of that,
it allows you to add a StaticThreadController inside another kind of ThreadController...
It works exact as ThreadController except you can't add or remove treads dynamically.
Created by Alex Eremin, September, 2016.
Released into the public domain.
*/
#ifndef StaticThreadController_h
#define StaticThreadController_h
#include "Thread.h"
template <int N>
class StaticThreadController: public Thread{
protected:
//since this is a static controller, the pointers themselves can be const
//it should be distinguished from 'const Thread* thread[N]'
Thread * const thread[N];
public:
template <typename... T>
StaticThreadController(T... params) :
Thread(),
thread{params...}
{
#ifdef USE_THREAD_NAMES
// Overrides name
ThreadName = "StaticThreadController ";
ThreadName = ThreadName + ThreadID;
#endif
};
// run() Method is overrided
void run() override
{
// Run this thread before
if(_onRun != nullptr && shouldRun())
_onRun();
for(int i = 0; i < N; i++){
// Is enabled? Timeout exceeded?
if(thread[i]->shouldRun()){
thread[i]->run();
}
}
// StaticThreadController extends Thread, so we should flag as runned thread
runned();
}
// Return the quantity of Threads
static constexpr int size() { return N; };
// Return the I Thread on the array
// Returns nullptr if index is out of bounds
Thread* get(int index) {
return (index >= 0 && index < N) ? thread[index] : nullptr;
};
// Return the I Thread on the array
// Doesn't perform any bounds checks and behaviour is
// unpredictable in case of index > N
Thread& operator[](int index) {
return *thread[index];
};
};
#endif

View file

@ -0,0 +1,52 @@
#include "Thread.h"
Thread::Thread(void (*callback)(void), unsigned long _interval){
enabled = true;
onRun(callback);
_cached_next_run = 0;
last_run = millis();
ThreadID = (int)this;
#ifdef USE_THREAD_NAMES
ThreadName = "Thread ";
ThreadName = ThreadName + ThreadID;
#endif
setInterval(_interval);
};
void Thread::runned(unsigned long time){
// Saves last_run
last_run = time;
// Cache next run
_cached_next_run = last_run + interval;
}
void Thread::setInterval(unsigned long _interval){
// Save interval
interval = _interval;
// Cache the next run based on the last_run
_cached_next_run = last_run + interval;
}
bool Thread::shouldRun(unsigned long time){
// If the "sign" bit is set the signed difference would be negative
bool time_remaining = (time - _cached_next_run) & 0x80000000;
// Exceeded the time limit, AND is enabled? Then should run...
return !time_remaining && enabled;
}
void Thread::onRun(void (*callback)(void)){
_onRun = callback;
}
void Thread::run(){
if(_onRun != NULL)
_onRun();
// Update last_run and _cached_next_run
runned();
}

View file

@ -0,0 +1,89 @@
/*
Thread.h - An runnable object
Thread is responsable for holding the "action" for something,
also, it responds if it "should" or "should not" run, based on
the current time;
For instructions, go to https://github.com/ivanseidel/ArduinoThread
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef Thread_h
#define Thread_h
#if defined(ARDUINO) && ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <inttypes.h>
/*
Uncomment this line to enable ThreadName Strings.
It might be usefull if you are loging thread with Serial,
or displaying a list of threads...
*/
// #define USE_THREAD_NAMES 1
class Thread{
protected:
// Desired interval between runs
unsigned long interval;
// Last runned time in Ms
unsigned long last_run;
// Scheduled run in Ms (MUST BE CACHED)
unsigned long _cached_next_run;
/*
IMPORTANT! Run after all calls to run()
Updates last_run and cache next run.
NOTE: This MUST be called if extending
this class and implementing run() method
*/
void runned(unsigned long time);
// Default is to mark it runned "now"
void runned() { runned(millis()); }
// Callback for run() if not implemented
void (*_onRun)(void);
public:
// If the current Thread is enabled or not
bool enabled;
// ID of the Thread (initialized from memory adr.)
int ThreadID;
#ifdef USE_THREAD_NAMES
// Thread Name (used for better UI).
String ThreadName;
#endif
Thread(void (*callback)(void) = NULL, unsigned long _interval = 0);
// Set the desired interval for calls, and update _cached_next_run
virtual void setInterval(unsigned long _interval);
// Return if the Thread should be runned or not
virtual bool shouldRun(unsigned long time);
// Default is to check whether it should run "now"
bool shouldRun() { return shouldRun(millis()); }
// Callback set
void onRun(void (*callback)(void));
// Runs Thread
virtual void run();
};
#endif

View file

@ -0,0 +1,114 @@
#include "Thread.h"
#include "ThreadController.h"
ThreadController::ThreadController(unsigned long _interval): Thread(){
cached_size = 0;
clear();
setInterval(_interval);
#ifdef USE_THREAD_NAMES
// Overrides name
ThreadName = "ThreadController ";
ThreadName = ThreadName + ThreadID;
#endif
}
/*
ThreadController run() (cool stuf)
*/
void ThreadController::run(){
// Run this thread before
if(_onRun != NULL)
_onRun();
unsigned long time = millis();
int checks = 0;
for(int i = 0; i < MAX_THREADS && checks < cached_size; i++){
// Object exists? Is enabled? Timeout exceeded?
if(thread[i]){
checks++;
if(thread[i]->shouldRun(time)){
thread[i]->run();
}
}
}
// ThreadController extends Thread, so we should flag as runned thread
runned();
}
/*
List controller (boring part)
*/
bool ThreadController::add(Thread* _thread){
// Check if the Thread already exists on the array
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i] != NULL && thread[i]->ThreadID == _thread->ThreadID)
return true;
}
// Find an empty slot
for(int i = 0; i < MAX_THREADS; i++){
if(!thread[i]){
// Found a empty slot, now add Thread
thread[i] = _thread;
cached_size++;
return true;
}
}
// Array is full
return false;
}
void ThreadController::remove(int id){
// Find Threads with the id, and removes
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i]->ThreadID == id){
thread[i] = NULL;
cached_size--;
return;
}
}
}
void ThreadController::remove(Thread* _thread){
remove(_thread->ThreadID);
}
void ThreadController::clear(){
for(int i = 0; i < MAX_THREADS; i++){
thread[i] = NULL;
}
cached_size = 0;
}
int ThreadController::size(bool cached){
if(cached)
return cached_size;
int size = 0;
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i])
size++;
}
cached_size = size;
return cached_size;
}
Thread* ThreadController::get(int index){
int pos = -1;
for(int i = 0; i < MAX_THREADS; i++){
if(thread[i] != NULL){
pos++;
if(pos == index)
return thread[i];
}
}
return NULL;
}

View file

@ -0,0 +1,53 @@
/*
ThreadController.h - Controlls a list of Threads with different timings
Basicaly, what it does is to keep track of current Threads and run when
necessary.
ThreadController is an extended class of Thread, because of that,
it allows you to add a ThreadController inside another ThreadController...
For instructions, go to https://github.com/ivanseidel/ArduinoThread
Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/
#ifndef ThreadController_h
#define ThreadController_h
#include "Thread.h"
#include "inttypes.h"
#define MAX_THREADS 15
class ThreadController: public Thread{
protected:
Thread* thread[MAX_THREADS];
int cached_size;
public:
ThreadController(unsigned long _interval = 0);
// run() Method is overrided
void run();
// Adds a thread in the first available slot (remove first)
// Returns if the Thread could be added or not
bool add(Thread* _thread);
// remove the thread (given the Thread* or ThreadID)
void remove(int _id);
void remove(Thread* _thread);
// Removes all threads
void clear();
// Return the quantity of Threads
int size(bool cached = true);
// Return the I Thread on the array
// Returns NULL if none found
Thread* get(int index);
};
#endif

View file

@ -0,0 +1,78 @@
#include <Thread.h>
#include <ThreadController.h>
int ledPin = 13;
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread
Thread myThread = Thread();
//His Thread
Thread hisThread = Thread();
//Blink Led Thread
Thread blinkLedThread = Thread();
//ThreadController, that will be added to controll
ThreadController groupOfThreads = ThreadController();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
// callback for blinkLedThread
void blinkLed(){
static bool ledStatus = false;
ledStatus = !ledStatus;
digitalWrite(ledPin, ledStatus);
Serial.print("blinking: ");
Serial.println(ledStatus);
}
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
// Configure myThread
myThread.onRun(niceCallback);
myThread.setInterval(500);
// Configure hisThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Configure blinkLedThread
blinkLedThread.onRun(blinkLed);
blinkLedThread.setInterval(100);
// Adds myThread to the controll
controll.add(&myThread);
// Adds hisThread and blinkLedThread to groupOfThreads
groupOfThreads.add(&hisThread);
groupOfThreads.add(&blinkLedThread);
// Add groupOfThreads to controll
controll.add(&groupOfThreads);
}
void loop(){
// run ThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

View file

@ -0,0 +1,100 @@
#include <Thread.h>
#include <ThreadController.h>
/*
This example, requires a Timer Interrupt Library.
If you are using Arduino NANO, UNO... (with ATmega168/328)
Please go to: http://playground.arduino.cc/code/timer1
If you are using Arduino DUE,
Please go to: https://github.com/ivanseidel/DueTimer
Include the library corresponding to your Arduino.
*/
// #include <DueTimer.h>
// #include <TimerOne.h>
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread
Thread myThread = Thread();
//His Thread
Thread hisThread = Thread();
// callback for myThread
void myThreadCallback(){
Serial.println("myThread\t\tcallback");
}
// callback for hisThread
void hisThreadCallback(){
Serial.println("\thisThread\tcallback");
}
// This is the callback for the Timer
void timerCallback(){
controll.run();
}
void setup(){
Serial.begin(9600);
// Configure myThread
myThread.onRun(myThreadCallback);
myThread.setInterval(500);
// Configure myThread
hisThread.onRun(hisThreadCallback);
hisThread.setInterval(200);
// Adds both threads to the controller
controll.add(&myThread); // & to pass the pointer to it
controll.add(&hisThread);
/*
If using DueTimer...
*/
// Timer1.attachInterrupt(timerCallback).start(20000);
/*
If using TimerOne...
*/
// Timer1.initialize(20000);
// Timer1.attachInterrupt(timerCallback);
// Timer1.start();
}
void waitSerial(){
while (!Serial.available());
delay(10);
while (Serial.available() && Serial.read());
}
void loop(){
while(1){
noInterrupts(); // Call to disable interrupts
Serial.println("Type anyting to stop myThread!");
interrupts(); // Call to enable interrupts
waitSerial();
myThread.enabled = false;
noInterrupts();
Serial.println("Type anyting to stop hisThread!");
interrupts();
waitSerial();
hisThread.enabled = false;
noInterrupts();
Serial.println("Type anyting to enable myThread!");
interrupts();
waitSerial();
myThread.enabled = true;
noInterrupts();
Serial.println("Type anyting to enable hisThread!");
interrupts();
waitSerial();
hisThread.enabled = true;
}
}

View file

@ -0,0 +1,257 @@
/*
This is an example from ArduinoThread. You can find more information
in https://github.com/ivanseidel/ArduinoThread.
Coded by Ivan Seidel, Jun/2014 - ivanseidel@gmail.com
Dont be afraid. 90% is commented lines. READ them, they will teach you.
*/
#include <Thread.h>
#include <ThreadController.h>
/*
This example provides an object-oriented approach to
develop a custom Thread that overrides the 'shouldRun'
method, to only run the thread after a button was pushed.
After the push, it should 'keep' running for a desired time.
It should also provide us, a way to easily implement this
controll multiple times, without trouble.
We are giving this Custom Thread the name 'ButtonThread'.
Exemplifying what it does:
+ ButtonThread added to our mainController ThreadList
=> Instantiated with a custom Pin #,
=> and a time duration (in miliseconds)
+ ButtonThread is not running.
+ When the button is pressed:
+ Thread will start and keep running.
+ If the thread runned for our defined period,
we stop it.
================ HOW TO SETUP HARDWARE ==================
In order to make this example work with any arduino, hook up
the pins on the board to 3 buttons. You can change the inputs
if you need below here.
The Buttons are being SOFTWARE pulled UP (to VCC), and when
pushed, should go LOW. Connect like this:
(Arduino Input) <----> (Btn) <----> GND (-)
We are using digital pins 9, 10 and 11 as input.
It also uses a LED, but we are using the default one in the board.
=============== WHAT YO LEARN WITH THIS =================
1) Threads are actually running in 'parallel'.
Since each thread process time is very tiny, they appear
as being runned in parallel.
Because of that, clicking multiple buttons at any time,
will looks like there is a program for each one of them.
2) If you keep the button 'pressed', it will continue to run.
Since we are 'enabling' the thread, and reseting the timer
flag (_lastButtonPushed) every time the button is pressed,
we should notice that in btn1Callback, where we print this
flag, it will never go beyond 0 if we keep pressing it.
3) The LED turns off, only because the Thread runs a last time
with the flag 'enabled' as false. This way, we can turn the
LED off and remain OFF until we press it egain.
I hope you enjoy, and learn some advanced-cool stuf with this tutorial.
Any feedback is apreciated!
*/
#define BTN1 9
#define BTN2 10
#define BTN3 11
#define LED 13
// ThreadController that will controll all button threads
ThreadController controll = ThreadController();
// Here we implement our custom ButtonThread, that Inherits from Thread
class ButtonThread: public Thread{
public:
// Our custom thread attributes
int pin;
long duration;
long _lastButtonPushed;
/*
Our Constructor. This will initialize the thread
with it's corresponding pin and duration after clicked.
*/
ButtonThread(int _pin, long _duration): Thread(){
// Set our attributes on construct
pin = _pin;
duration = _duration;
_lastButtonPushed = 0;
// Thread will start disabled
enabled = false;
// Configure the pin as INPUT and enable pull-up
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
}
/*
Override the method responsible for
checking if the thread should run.
It will first check if the button is pressed.
If so, we enable the thread, and then let the
"Old" default Thread method 'shouldRun' return if
it should run.
*/
bool shouldRun(unsigned long time){
// Override enabled on thread when pin goes LOW.
if(digitalRead(pin) == LOW){
enabled = true;
/*
Here, we save the current time in this object,
to compare it later.
the 'time' parameter in this method, is an override for the
'millis()' method. It allows who is checking the thread, to
pass a custom time.
This is sintax for writing an 'inline' if is very usefull,
it's the same as:
if(time > 0){
_lastButtonPushed = time;
}else{
_lastButtonPushed = millis();
}
*/
_lastButtonPushed = (time ? time : millis());
}
// Let default method check for it.
return Thread::shouldRun(time);
}
/*
We 'disable' the thread after the duration on the
'run' method.
What we should do here, is check if the time saved
in the _lastButtonPushed variable plus the duration,
is greater than our current time. If that's true, it
means we exceeded the thread time, and that we must
disable it and prevent from running.
*/
void run(){
// Check if time elapsed since last button push
if(millis() > _lastButtonPushed + duration){
// It exceeded time. We should disable it.
enabled = false;
}
/*
Run the thread.
Note that this method will only get called
from the ThreadList, IF the 'shouldRun' returns true.
If the thread is not enabled anymore, it will run a 'last'
time with the flag 'enabled' as false, meaning it's the last
run in the period. You can use it for doing something only
before it stops running.
*/
Thread::run();
}
};
/*
ButtonThreads objects instantiation
(we are instantiating 2 as a member, and one
as pointer in the setup, just to show you
different ways of doing it)
*/
// Thread 1 will be reading BTN1 pin, and will run for 3 secs
ButtonThread btn1Thread(BTN1, 3000);
// Thread 2 will be reading BTN1 pin, and will run for 5 secs
ButtonThread btn2Thread = ButtonThread(BTN2, 5000);
// Thread 3 will be instantiated in the setup()
ButtonThread *btn3Thread;
/*
Callback for ButtonThreads
*/
void btn1Callback(){
// When it's running, this thread will write to the serial.
/*
This math will print 'how long' the thread has been running,
since the button was/is pressed.
After pressing it, it should print as 0, and goes up untill
the thread duration (in this case, +-5000ms).
*/
Serial.print("BTN 1 Thread: ");
Serial.println(millis() - btn1Thread._lastButtonPushed);
}
void btn2Callback(){
/*
This thread will remain with the LED on pin 13 turned on
while it is running.
We detect that this method is called for the LAST time, if
the flag 'enabled' is FALSE on the btn2Thread object.
So, basically: If it's TRUE, we should turn ON the led, if not
we should turn OFF. We can simplify that into one line.
(Same 'inline' sintax as above)
*/
digitalWrite(LED, btn2Thread.enabled ? HIGH : LOW);
}
void btn3Callback(){
// When it's running, this thread will also write to the serial
Serial.println("BTN 3 Thread");
}
void setup(){
// Configure serial and output pins
Serial.begin(9600);
pinMode(LED, OUTPUT);
// Configure btn1Thread callback
// (During the 'enabled' time, it will run every 100ms, aka Interval)
btn1Thread.onRun(btn1Callback);
btn1Thread.setInterval(100);
// Configure btn2Thread callback and interval
btn2Thread.onRun(btn2Callback);
btn2Thread.setInterval(200);
// Instantiate btn3Thread
btn3Thread = new ButtonThread(BTN3, 4000);
// Configure btn3Thread callback and interval
btn3Thread->onRun(btn3Callback);
btn3Thread->setInterval(100);
// Adds all threads to the controller
controll.add(&btn1Thread); // & to pass the pointer to it
controll.add(&btn2Thread);
controll.add(btn3Thread); // Its already a pointer, no need for &
}
void loop(){
// Here we just run the main thread controller
controll.run();
}

View file

@ -0,0 +1,105 @@
#include "Thread.h"
#include "ThreadController.h"
/*
This is a more "complex" for of using Threads.
You can also inherit from Thread, and do your entire code on the class.
This allows you, to create for example:
Sensor Readings (aquire, filter, and save localy values)
Custom Blinks, Beeps...
Anything you can imagine.
Threads are more "usefull" when used within Timer interrupts
This way of coding is more "reusable", and "correct" (Object Oriented)
*/
/*
This example, requires a Timer Interrupt Library.
If you are using Arduino NANO, UNO... (with ATmega168/328)
Please go to: http://playground.arduino.cc/code/timer1
If you are using Arduino DUE,
Please go to: https://github.com/ivanseidel/DueTimer
Include the library corresponding to your Arduino.
*/
#include <DueTimer.h>
// #include <TimerOne.h>
// Create a new Class, called SensorThread, that inherits from Thread
class SensorThread: public Thread
{
public:
int value;
int pin;
// No, "run" cannot be anything...
// Because Thread uses the method "run" to run threads,
// we MUST overload this method here. using anything other
// than "run" will not work properly...
void run(){
// Reads the analog pin, and saves it localy
value = map(analogRead(pin), 0,1023,0,255);
runned();
}
};
// Now, let's use our new class of Thread
SensorThread analog1 = SensorThread();
SensorThread analog2 = SensorThread();
// Instantiate a new ThreadController
ThreadController controller = ThreadController();
// This is the callback for the Timer
void timerCallback(){
controller.run();
}
void setup(){
Serial.begin(9600);
// Configures Thread analog1
analog1.pin = A1;
analog1.setInterval(100);
// Configures Thread analog2
analog2.pin = A2;
analog2.setInterval(100);
// Add the Threads to our ThreadController
controller.add(&analog1);
controller.add(&analog2);
/*
If using DueTimer...
*/
Timer1.attachInterrupt(timerCallback).start(10000);
/*
If using TimerOne...
*/
// Timer1.initialize(20000);
// Timer1.attachInterrupt(timerCallback);
// Timer1.start();
}
void loop(){
// Do complex-crazy-timeconsuming-tasks here
delay(1000);
// Get the fresh readings
Serial.print("Analog1 Thread: ");
Serial.println(analog1.value);
Serial.print("Analog2 Thread: ");
Serial.println(analog2.value);
// Do more complex-crazy-timeconsuming-tasks here
delay(1000);
}

View file

@ -0,0 +1,35 @@
#include <Thread.h>
int ledPin = 13;
//My simple Thread
Thread myThread = Thread();
// callback for myThread
void niceCallback(){
static bool ledStatus = false;
ledStatus = !ledStatus;
digitalWrite(ledPin, ledStatus);
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
void setup(){
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
myThread.onRun(niceCallback);
myThread.setInterval(500);
}
void loop(){
// checks if thread should run
if(myThread.shouldRun())
myThread.run();
// Other code...
int x = 0;
x = 1 + 2;
}

View file

@ -0,0 +1,48 @@
#include <Thread.h>
#include <ThreadController.h>
// ThreadController that will controll all threads
ThreadController controll = ThreadController();
//My Thread (as a pointer)
Thread* myThread = new Thread();
//His Thread (not pointer)
Thread hisThread = Thread();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
void setup(){
Serial.begin(9600);
// Configure myThread
myThread->onRun(niceCallback);
myThread->setInterval(500);
// Configure myThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Adds both threads to the controller
controll.add(myThread);
controll.add(&hisThread); // & to pass the pointer to it
}
void loop(){
// run ThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

View file

@ -0,0 +1,56 @@
#include <Thread.h>
#include <StaticThreadController.h>
//My Thread (as a pointer)
Thread* myThread = new Thread();
//His Thread (not pointer)
Thread hisThread = Thread();
// callback for myThread
void niceCallback(){
Serial.print("COOL! I'm running on: ");
Serial.println(millis());
}
// callback for hisThread
void boringCallback(){
Serial.println("BORING...");
}
// callback for theThread
void justCallback(){
Serial.println("executing...");
}
//The Thread (as a pointer) with justCallback initialized
Thread* theThread = new Thread(justCallback);
// StaticThreadController that will controll all threads
// All non-pointers go with '&', but pointers go without '&',
StaticThreadController<3> controll (myThread, &hisThread, theThread);
void setup(){
Serial.begin(9600);
// Configure myThread
myThread->onRun(niceCallback);
myThread->setInterval(500);
// Configure hisThread
hisThread.onRun(boringCallback);
hisThread.setInterval(250);
// Set interval for theThread using StaticThreadController interface
controll[3].setInterval(375);
}
void loop(){
// run StaticThreadController
// this will check every thread inside ThreadController,
// if it should run. If yes, he will run it;
controll.run();
// Rest of code
float h = 3.1415;
h/=2;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View file

@ -0,0 +1,32 @@
#######################################
# Syntax Coloring
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Thread KEYWORD1
ThreadController KEYWORD1
StaticThreadController KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
runned KEYWORD2
setInterval KEYWORD2
shouldRun KEYWORD2
onRun KEYWORD2
run KEYWORD2
# Specific of ThreadController or StaticThreadController
add KEYWORD2
remove KEYWORD2
clear KEYWORD2
size KEYWORD2
get KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -0,0 +1,12 @@
{
"name": "Thread",
"keywords": "thread, task",
"description": "A library for managing the periodic execution of multiple tasks",
"repository":
{
"type": "git",
"url": "https://github.com/ivanseidel/ArduinoThread.git"
},
"frameworks": "arduino",
"platforms": "atmelavr"
}

View file

@ -0,0 +1,9 @@
name=ArduinoThread
version=2.1.1
author=Ivan Seidel <ivanseidel@gmail.com>
maintainer=Ivan Seidel <ivanseidel@gmail.com>
sentence=A simple way to run Threads on Arduino
paragraph=This Library helps to maintain organized and to facilitate the use of multiple tasks. We can use Timers Interrupts, and make it really powerfull, running "pseudo-background" tasks on the rug.
category=Timing
url=https://github.com/ivanseidel/ArduinoThread
architectures=*