Skip to content

Commit 366c7aa

Browse files
author
Ivan Seidel
committed
New Example: CustomTimedThread
1 parent 7cb4d7d commit 366c7aa

2 files changed

Lines changed: 253 additions & 0 deletions

File tree

README.textile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ h3. TIPs and Warnings
9393

9494
* Remember that @ThreadController@ is in fact, a Thread. If you want to enable or disable a GROUP of Threads, think about putting all of them inside a ThreadController, and adding this ThreadController to another ThreadController (YES! One ThreadController inside another). Check @ControllerInController@ example.
9595

96+
* Check the full example @CustomTimedThread@ for a cool application of Threads that runs for a period, after a button is pressed.
97+
9698
* Running tasks on the Timer interrupts must be tought REALLY carefully
9799
You cannot use "sleep()" inside a interrupt, because it will get into a infinite loop.
98100
Things must do stuff quickly. Waiting too loooong on a interrupt, means waiting too loooong on the main code (loop)
@@ -131,6 +133,7 @@ h3. You don't need to know:
131133

132134
h2. Version History
133135

136+
* @(Jun/2014): New Example: ControllerWithTimer@
134137
* @1.0 (2013-05-11): Initial release.@
135138

136139
!https://d2weczhvl823v0.cloudfront.net/ivanseidel/ArduinoThread/trend.png(ArduinoThread)!
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
This is an example from ArduinoThread. You can find more information
3+
in https://github.com/ivanseidel/ArduinoThread.
4+
5+
Coded by Ivan Seidel, Jun/2014 - ivanseidel@gmail.com
6+
7+
Dont be afraid. 90% is commented lines. READ them, they will teach you.
8+
*/
9+
10+
#include <Thread.h>
11+
#include <ThreadController.h>
12+
13+
/*
14+
This example provides an object-oriented approach to
15+
develop a custom Thread that overrides the 'shouldRun'
16+
method, to only run the thread after a button was pushed.
17+
18+
After the push, it should 'keep' running for a desired time.
19+
20+
It should also provide us, a way to easily implement this
21+
controll multiple times, without trouble.
22+
23+
We are giving this Custom Thread the name 'ButtonThread'.
24+
25+
Exemplifying what it does:
26+
+ ButtonThread added to our mainController ThreadList
27+
=> Instantiated with a custom Pin #,
28+
=> and a time duration (in miliseconds)
29+
30+
+ ButtonThread is not running.
31+
32+
+ When the button is pressed:
33+
+ Thread will start and keep running.
34+
+ If the thread runned for our defined period,
35+
we stop it.
36+
37+
================ HOW TO SETUP HARDWARE ==================
38+
In order to make this example work with any arduino, hook up
39+
the pins on the board to 3 buttons. You can change the inputs
40+
if you need below here.
41+
42+
The Buttons are being SOFTWARE pulled UP (to VCC), and when
43+
pushed, should go LOW. Connect like this:
44+
(Arduino Input) <----> (Btn) <----> GND (-)
45+
46+
We are using digital pins 9, 10 and 11 as input.
47+
It also uses a LED, but we are using the default one in the board.
48+
49+
=============== WHAT YO LEARN WITH THIS =================
50+
1) Threads are actually running in 'parallel'.
51+
52+
Synce each thread process time is very tiny, they appear
53+
as being runned in parallel.
54+
55+
Because of that, clicking multiple buttons at any time,
56+
will looks like there is a program for each one of them.
57+
58+
2) If you keep the button 'pressed', it will continue to run.
59+
60+
Since we are 'enabling' the thread, and reseting the timer
61+
flag (_lastButtonPushed) every time the button is pressed,
62+
we should notice that in btn1Callback, where we print this
63+
flag, it will never go beyond 0 if we keep pressing it.
64+
65+
3) The LED turns off, only because the Thread runs a last time
66+
with the flag 'enabled' as false. This way, we can turn the
67+
LED off and remain OFF until we press it egain.
68+
69+
I hope you enjoy, and learn some advanced-cool stuf with this tutorial.
70+
Any feedback is apreciated!
71+
*/
72+
#define BTN1 9
73+
#define BTN2 10
74+
#define BTN3 11
75+
76+
#define LED 13
77+
78+
// ThreadController that will controll all button threads
79+
ThreadController controll = ThreadController();
80+
81+
// Here we implement our custom ButtonThread, that Inherits from Thread
82+
class ButtonThread: public Thread{
83+
public:
84+
// Our custom thread attributes
85+
int pin;
86+
long duration;
87+
long _lastButtonPushed;
88+
89+
/*
90+
Our Constructor. This will initialize the thread
91+
with it's corresponding pin and duration after clicked.
92+
*/
93+
ButtonThread(int _pin, long _duration): Thread(){
94+
// Set our attributes on construct
95+
pin = _pin;
96+
duration = _duration;
97+
_lastButtonPushed = 0;
98+
99+
// Thread will start disabled
100+
enabled = false;
101+
102+
// Configure the pin as INPUT and enable pull-up
103+
pinMode(pin, INPUT);
104+
digitalWrite(pin, HIGH);
105+
}
106+
107+
/*
108+
Override the method responsible for
109+
checking if the thread should run.
110+
111+
It will first check if the button is pressed.
112+
If so, we enable the thread, and then let the
113+
"Old" default Thread method 'shouldRun' return if
114+
it should run.
115+
*/
116+
bool shouldRun(long time){
117+
// Override enabled on thread when pin goes LOW.
118+
if(digitalRead(pin) == LOW){
119+
enabled = true;
120+
/*
121+
Here, we save the current time in this object,
122+
to compare it later.
123+
124+
the 'time' parameter in this method, is an override for the
125+
'millis()' method. It allows who is checking the thread, to
126+
pass a custom time.
127+
128+
This is sintax for writing an 'inline' if is very usefull,
129+
it's the same as:
130+
if(time > 0){
131+
_lastButtonPushed = time;
132+
}else{
133+
_lastButtonPushed = millis();
134+
}
135+
*/
136+
_lastButtonPushed = (time ? time : millis());
137+
}
138+
139+
// Let default method check for it.
140+
return Thread::shouldRun(time);
141+
}
142+
143+
/*
144+
We 'disable' the thread after the duration on the
145+
'run' method.
146+
147+
What we should do here, is check if the time saved
148+
in the _lastButtonPushed variable plus the duration,
149+
is greater than our current time. If that's true, it
150+
means we exceeded the thread time, and that we must
151+
disable it and prevent from running.
152+
*/
153+
void run(){
154+
// Check if time elapsed since last button push
155+
if(millis() > _lastButtonPushed + duration){
156+
// It exceeded time. We should disable it.
157+
enabled = false;
158+
}
159+
160+
/*
161+
Run the thread.
162+
163+
Note that this method will only get called
164+
from the ThreadList, IF the 'shouldRun' returns true.
165+
166+
If the thread is not enabled anymore, it will run a 'last'
167+
time with the flag 'enabled' as false, meaning it's the last
168+
run in the period. You can use it for doing something only
169+
before it stops running.
170+
*/
171+
Thread::run();
172+
}
173+
};
174+
175+
/*
176+
ButtonThreads objects instantiation
177+
(we are instantiating 2 as a member, and one
178+
as pointer in the setup, just to show you
179+
different ways of doing it)
180+
*/
181+
182+
// Thread 1 will be reading BTN1 pin, and will run for 3 secs
183+
ButtonThread btn1Thread(BTN1, 3000);
184+
185+
// Thread 2 will be reading BTN1 pin, and will run for 5 secs
186+
ButtonThread btn2Thread = ButtonThread(BTN2, 5000);
187+
188+
// Thread 3 will be instantiated in the setup()
189+
ButtonThread *btn3Thread;
190+
191+
192+
/*
193+
Callback for ButtonThreads
194+
*/
195+
void btn1Callback(){
196+
// When it's running, this thread will write to the serial.
197+
Serial.print("BTN 1 Thread: ");
198+
Serial.println(millis() - btn1Thread._lastButtonPushed);
199+
}
200+
201+
void btn2Callback(){
202+
/*
203+
This thread will remain with the LED on pin 13 turned on
204+
while it is running.
205+
206+
We detect that this method is called for the LAST time, if
207+
the flag 'enabled' is FALSE on the btn2Thread object.
208+
209+
So, basically: If it's TRUE, we should turn ON the led, if not
210+
we should turn OFF. We can simplify that into one line.
211+
(Same 'inline' sintax as above)
212+
*/
213+
digitalWrite(LED, btn2Thread.enabled ? HIGH : LOW);
214+
}
215+
216+
void btn3Callback(){
217+
// When it's running, this thread will also write to the serial
218+
Serial.println("BTN 3 Thread");
219+
}
220+
221+
void setup(){
222+
// Configure serial and output pins
223+
Serial.begin(9600);
224+
pinMode(LED, OUTPUT);
225+
226+
// Configure btn1Thread callback
227+
// (During the 'enabled' time, it will run every 50ms, aka Interval)
228+
btn1Thread.onRun(btn1Callback);
229+
btn1Thread.setInterval(100);
230+
231+
// Configure btn2Thread callback and interval
232+
btn2Thread.onRun(btn2Callback);
233+
btn2Thread.setInterval(200);
234+
235+
// Instantiate btn3Thread
236+
btn3Thread = new ButtonThread(BTN3, 4000);
237+
// Configure btn3Thread callback and interval
238+
btn3Thread->onRun(btn3Callback);
239+
btn3Thread->setInterval(100);
240+
241+
// Adds all threads to the controller
242+
controll.add(&btn1Thread); // & to pass the pointer to it
243+
controll.add(&btn2Thread);
244+
controll.add(btn3Thread); // Its already a pointer, no need for &
245+
}
246+
247+
void loop(){
248+
// Here we just run the main thread controller
249+
controll.run();
250+
}

0 commit comments

Comments
 (0)