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