Multitasking with Arduino | Relay Timer Controller | using millis
Introduction
In this demonstration, I show a Relay Timer Controller. The multitasking is achieve using the power of millis function.
The following task are achieve:
- The On state of the relay (simulated through the LED).
- Navigating the LCD menu using buttons.
Circuit Diagram
Video Demonstration
Call To Action
If you like this article, please give me thumbs up and share this to your friends.
If you have question, please write it in the comment box.
Please do not forget to Subscribe:
Click this to Subscribe
Thank you and have a good day.
Source Code
1#include "LiquidCrystal.h"
2
3// LED definitions for easy reference
4#define RED_LED A0
5#define YEL_LED A1
6#define BLU_LED A2
7#define LEFT_SW A3
8#define ENTR_SW A4
9#define RGHT_SW A5
10
11// Variables for the LCD
12LiquidCrystal lcd(13, 12, 11, 10, 9, 8);
13byte charUp[8] = {
14 B00100,
15 B01110,
16 B11111,
17 B00000,
18 B00000,
19 B00000,
20 B00000,
21 B00000
22};
23byte charDown[8] = {
24 B00000,
25 B00000,
26 B00000,
27 B00000,
28 B00000,
29 B11111,
30 B01110,
31 B00100
32};
33byte charUpDown[8] = {
34 B00100,
35 B01110,
36 B11111,
37 B00000,
38 B00000,
39 B11111,
40 B01110,
41 B00100
42};
43
44// Variables for the button switch
45#define DEFAULT_DELAY 300
46char buttonPressed = '0';
47byte menu = 1;
48byte sub = 1;
49byte menuLevel = 0; // Level 0: no menu display, display anything you like
50 // Level 1: display main menu
51 // Level 2: display sub menu
52 // Level 3: display sub menu of sub menu
53unsigned long relay_val_1 = 0;
54unsigned long relay_val_2 = 0;
55unsigned long relay_val_3 = 0;
56
57// Variables for the button debouncing
58bool currState_L = HIGH;
59bool currState_E = HIGH;
60bool currState_R = HIGH;
61bool prevState_L = HIGH;
62bool prevState_E = HIGH;
63bool prevState_R = HIGH;
64unsigned long prevTime_L = 0;
65unsigned long prevTime_E = 0;
66unsigned long prevTime_R = 0;
67unsigned long waitTime_L = 50;
68unsigned long waitTime_E = 50;
69unsigned long waitTime_R = 50;
70
71// Variables for the LED
72bool ledState_RED = LOW; // this holds the current state of the LED
73bool ledState_YEL = LOW;
74bool ledState_BLU = LOW;
75unsigned long prevMillis_RED = 0; // this holds the start time of millis for computing the elapse time
76unsigned long prevMillis_YEL = 0;
77unsigned long prevMillis_BLU = 0;
78unsigned long interval_RED = 3000; // this holds the interval of each toggle of LED
79unsigned long interval_YEL = 5000;
80unsigned long interval_BLU = 7000;
81unsigned long currMillis_ALL = 0; // this holds the current time captured by the millis() function
82 // it is use in general for synchronization purpose
83unsigned long elapsed_RED = 0;
84unsigned long elapsed_YEL = 0;
85unsigned long elapsed_BLU = 0;
86
87bool run_RED = false;
88bool run_YEL = false;
89bool run_BLU = false;
90
91void setup() {
92 lcd.begin(16,2);
93 lcd.createChar(0, charUp);
94 lcd.createChar(1, charDown);
95 lcd.createChar(2, charUpDown);
96 lcd.println(" TechToTinker ");
97
98 // Set the pin directions for LEDs
99 pinMode(RED_LED, OUTPUT);
100 pinMode(YEL_LED, OUTPUT);
101 pinMode(BLU_LED, OUTPUT);
102
103 pinMode(LEFT_SW, INPUT_PULLUP);
104 pinMode(ENTR_SW, INPUT_PULLUP);
105 pinMode(RGHT_SW, INPUT_PULLUP);
106
107 updateLevel_0();
108}
109
110void loop() {
111 // Store the currently time
112 // Notice: it use a single current time for synchonization with other function
113 currMillis_ALL = millis();
114 checkButton();
115 // Virtually process all the task
116 process_RED();
117 process_YEL();
118 process_BLU();
119}
120
121void checkButton() {
122 // Button Debouncing
123 bool currRead_L = digitalRead(LEFT_SW);
124 bool currRead_E = digitalRead(ENTR_SW);
125 bool currRead_R = digitalRead(RGHT_SW);
126 if (currRead_L != prevState_L) {
127 prevTime_L = millis();
128 }
129 if (currRead_E != prevState_E) {
130 prevTime_E = millis();
131 }
132 if (currRead_R != prevState_R) {
133 prevTime_R = millis();
134 }
135
136 if ((millis() - prevTime_L) > waitTime_L) {
137 if (currRead_L != currState_L) {
138 currState_L = currRead_L;
139 if (currState_L == LOW) {
140 buttonPressed = 'L';
141 }
142 }
143 } else buttonPressed = '0';
144 if ((millis() - prevTime_E) > waitTime_E) {
145 if (currRead_E != currState_E) {
146 currState_E = currRead_E;
147 if (currState_E == LOW) {
148 buttonPressed = 'E';
149 }
150 }
151 } else buttonPressed = '0';
152 if ((millis() - prevTime_R) > waitTime_R) {
153 if (currRead_R != currState_R) {
154 currState_R = currRead_R;
155 if (currState_R == LOW) {
156 buttonPressed = 'R';
157 } else {
158 //buttonPressed = '0';
159 }
160 }
161 } else buttonPressed = '0';
162
163 prevState_L = currRead_L;
164 prevState_E = currRead_E;
165 prevState_R = currRead_R;
166 processButton(buttonPressed);
167}
168
169void processButton(char buttonPressed) {
170 switch(menuLevel) {
171 case 0: // Level 0, home screen
172 switch ( buttonPressed ) {
173 case 'E': // Enter
174 menu = 1;
175 menuLevel = 1; // go to main menu
176 updateLevel_1(); // show main menu
177 delay(DEFAULT_DELAY);
178 break;
179 case 'L': // Left button
180 break;
181 case 'R': // Right button
182 break;
183 default:
184 break;
185 }
186 break;
187 case 1: // Level 1, main menu
188 switch ( buttonPressed ) {
189 case 'E': // Enter
190 if (menu == 4) { // Hide menu is selected
191 menuLevel = 0; // go to home screen
192 updateLevel_0(); // show home screen
193 } else {
194 sub = 1;
195 menuLevel = 2; // go to sub menu
196 updateLevel_2(); // show sub menu
197 }
198 delay(DEFAULT_DELAY);
199 break;
200 case 'L': // Left
201 menu--;
202 updateLevel_1(); // show main menu
203 delay(DEFAULT_DELAY);
204 break;
205 case 'R': // Right
206 menu++;
207 updateLevel_1(); // show main menu
208 delay(DEFAULT_DELAY);
209 break;
210 default:
211 break;
212 }
213 break;
214 case 2: // Level 2, sub menu
215 switch ( buttonPressed ) {
216 case 'E': // Enter
217 if (sub == 2) { // Edit
218 menuLevel = 3; // go to sub menu of sub menu
219 updateLevel_3(); // show sub menu of sub menu
220 } else if (sub == 3) { // Execute
221 executeAction();
222 delay(1000);
223 menuLevel = 2; // go to sub menu
224 updateLevel_2(); // show sub menu
225 } else if (sub == 4) { // Back
226 menuLevel = 1; // go back to level 1
227 updateLevel_1(); // show main menu
228 }
229 delay(DEFAULT_DELAY);
230 break;
231 case 'L': // Left button
232 sub--;
233 updateLevel_2();
234 delay(DEFAULT_DELAY);
235 break;
236 case 'R': // Right button
237 sub++;
238 updateLevel_2(); // show main menu
239 delay(DEFAULT_DELAY);
240 break;
241 default:
242 break;
243 }
244 break;
245 case 3: // Level 3, sub menu of sub menu
246 switch ( buttonPressed ) {
247 case 'E': // Enter
248 menuLevel = 2; // go back to level 2
249 updateLevel_2(); // show sub menu
250 delay(DEFAULT_DELAY);
251 break;
252 case 'L': // Left
253 if (sub == 2) { // edit value
254 if (menu == 1) {
255 if (relay_val_1 == 0) {
256 relay_val_1 = 0;
257 } else {
258 relay_val_1 = relay_val_1 - 1;
259 }
260 } else if (menu == 2) {
261 if (relay_val_2 == 0) {
262 relay_val_2 = 0;
263 } else {
264 relay_val_2 = relay_val_2 - 1;
265 }
266 } else if (menu == 3) {
267 if (relay_val_3 == 0) {
268 relay_val_3 = 0;
269 } else {
270 relay_val_3 = relay_val_3 - 1;
271 }
272 }
273 }
274 updateLevel_3(); // show sub menu
275 delay(DEFAULT_DELAY);
276 break;
277 case 'R': // Right
278 if (sub == 2) { // edit value
279 if (menu == 1) {
280 if (relay_val_1 < 3600000) { // 1 hour max
281 relay_val_1 = relay_val_1 + 1;
282 } else {
283 relay_val_1 = 3600000;
284 }
285 } else if (menu == 2) {
286 if (relay_val_2 < 3600000) { // 1 hour max
287 relay_val_2 = relay_val_2 + 1;
288 } else {
289 relay_val_2 = 3600000;
290 }
291 } else if (menu == 3) {
292 if (relay_val_3 < 3600000) { // 1 hour max
293 relay_val_3 = relay_val_3 + 1;
294 } else {
295 relay_val_3 = 3600000;
296 }
297 }
298 }
299 updateLevel_3(); // show sub menu
300 delay(DEFAULT_DELAY);
301 break;
302 default:
303 break;
304 }
305 break;
306 default:
307 break;
308 }
309}
310
311void updateLevel_0() {
312 lcd.clear();
313 lcd.println(" TechToTinker ");
314 lcd.setCursor(0,1);
315 lcd.println(" - E for menu ");
316}
317
318void updateLevel_1 () {
319 switch (menu) {
320 case 0:
321 menu = 1;
322 break;
323 case 1:
324 lcd.clear();
325 lcd.print(">Relay RED ");
326 lcd.setCursor(0, 1);
327 lcd.print(" Relay YEL ");
328 lcd.setCursor(15,1);
329 lcd.write((byte)1); // down arrow
330 break;
331 case 2:
332 lcd.clear();
333 lcd.print(" Relay RED ");
334 lcd.setCursor(0, 1);
335 lcd.print(">Relay YEL ");
336 lcd.setCursor(15,1);
337 lcd.write((byte)2); // up and down arrow
338 break;
339 case 3:
340 lcd.clear();
341 lcd.print(">Relay BLU ");
342 lcd.setCursor(0, 1);
343 lcd.print(" Hide Menu ");
344 lcd.setCursor(15,1);
345 lcd.write((byte)2); // up and down arrow
346 break;
347 case 4:
348 lcd.clear();
349 lcd.print(" Relay BLU ");
350 lcd.setCursor(0, 1);
351 lcd.print(">Hide Menu ");
352 lcd.setCursor(15,1);
353 lcd.write((byte)0); // up arrow
354 break;
355 case 5:
356 menu = 4;
357 break;
358 }
359}
360
361void updateLevel_2 () {
362 switch (menu) {
363 case 0:
364 break;
365 case 1: // Relay RED
366 switch (sub) {
367 case 0:
368 break;
369 case 1:
370 lcd.clear();
371 lcd.print(" Relay RED: ");
372 lcd.setCursor(0, 1);
373 lcd.print(" Duration = ");
374 lcd.print(relay_val_1);
375 lcd.setCursor(15,1);
376 lcd.write((byte)1); // down arrow
377 break;
378 case 2:
379 lcd.clear();
380 lcd.print(" Relay RED: ");
381 lcd.setCursor(0, 1);
382 lcd.print(" Edit ");
383 lcd.print(relay_val_1);
384 lcd.setCursor(15,1);
385 lcd.write((byte)2); // up and down arrow
386 break;
387 case 3:
388 lcd.clear();
389 lcd.print(" Relay RED: ");
390 lcd.setCursor(0, 1);
391 lcd.print(" Execute ");
392 lcd.setCursor(15,1);
393 lcd.write((byte)2); // up and down arrow
394 break;
395 case 4:
396 lcd.clear();
397 lcd.print(" Relay RED: ");
398 lcd.setCursor(0, 1);
399 lcd.print(" Back ");
400 lcd.setCursor(15,1);
401 lcd.write((byte)0); // up arrow
402 default:
403 break;
404 }
405 break;
406 case 2: // Relay YEL
407 switch (sub) {
408 case 0:
409 break;
410 case 1:
411 lcd.clear();
412 lcd.print(" Relay YEL: ");
413 lcd.setCursor(0, 1);
414 lcd.print(" Duration = ");
415 lcd.print(relay_val_2);
416 lcd.setCursor(15,1);
417 lcd.write((byte)1); // down arrow
418 break;
419 case 2:
420 lcd.clear();
421 lcd.print(" Relay YEL: ");
422 lcd.setCursor(0, 1);
423 lcd.print(" Edit ");
424 lcd.setCursor(15,1);
425 lcd.write((byte)2); // up and down arrow
426 break;
427 case 3:
428 lcd.clear();
429 lcd.print(" Relay YEL: ");
430 lcd.setCursor(0, 1);
431 lcd.print(" Execute ");
432 lcd.setCursor(15,1);
433 lcd.write((byte)0); // up arrow
434 break;
435 case 4:
436 lcd.clear();
437 lcd.print(" Relay YEL: ");
438 lcd.setCursor(0, 1);
439 lcd.print(" Back ");
440 lcd.setCursor(15,1);
441 lcd.write((byte)0); // up arrow
442 default:
443 break;
444 }
445 break;
446 case 3: // Relay BLU
447 switch (sub) {
448 case 0:
449 break;
450 case 1:
451 lcd.clear();
452 lcd.print(" Relay BLU ");
453 lcd.setCursor(0, 1);
454 lcd.print(" Duration = ");
455 lcd.print(relay_val_3);
456 lcd.setCursor(15,1);
457 lcd.write((byte)1); // down arrow
458 break;
459 case 2:
460 lcd.clear();
461 lcd.print(" Relay BLU: ");
462 lcd.setCursor(0, 1);
463 lcd.print(" Edit ");
464 lcd.setCursor(15,1);
465 lcd.write((byte)2); // up and down arrow
466 break;
467 case 3:
468 lcd.clear();
469 lcd.print(" Relay BLU: ");
470 lcd.setCursor(0, 1);
471 lcd.print(" Execute ");
472 lcd.setCursor(15,1);
473 lcd.write((byte)2); // up and down arrow
474 break;
475 case 4:
476 lcd.clear();
477 lcd.print(" Relay BLU: ");
478 lcd.setCursor(0, 1);
479 lcd.print(" Back ");
480 lcd.setCursor(15,1);
481 lcd.write((byte)0); // up arrow
482 break;
483 default:
484 break;
485 }
486 break;
487 case 4:
488 //sub = 3;
489 break;
490 }
491}
492
493void updateLevel_3 () {
494 switch (menu) {
495 case 0:
496
497 break;
498 case 1:
499 lcd.clear();
500 lcd.print(" Relay RED: ");
501 lcd.setCursor(0, 1);
502 lcd.print(" Duration = ");
503 lcd.print(relay_val_1);
504 break;
505 case 2:
506 lcd.clear();
507 lcd.print(" Relay YEL: ");
508 lcd.setCursor(0, 1);
509 lcd.print(" Duration = ");
510 lcd.print(relay_val_2);
511 break;
512 case 3:
513 lcd.clear();
514 lcd.print(" Relay BLU: ");
515 lcd.setCursor(0, 1);
516 lcd.print(" Duration = ");
517 lcd.print(relay_val_3);
518 break;
519 case 4:
520 sub = 3;
521 break;
522 }
523}
524
525void executeAction () {
526 switch (menu) {
527 case 0:
528
529 break;
530 case 1:
531 lcd.clear();
532 lcd.print(" Executing RED ");
533 run_RED = true; // execute the timer
534 prevMillis_RED = millis(); // record the start time
535 interval_RED = relay_val_1 * 1000;// duration in seconds
536 digitalWrite(RED_LED, HIGH);
537 break;
538 case 2:
539 lcd.clear();
540 lcd.print(" Executing YEL ");
541 run_YEL = true;
542 prevMillis_YEL = millis(); // record the start time
543 interval_YEL = relay_val_2 * 1000;// duration in seconds
544 digitalWrite(YEL_LED, HIGH);
545 break;
546 case 3:
547 lcd.clear();
548 lcd.print(" Executing BLU ");
549 run_BLU = true;
550 prevMillis_BLU = millis(); // record the start time
551 interval_BLU = relay_val_3 * 1000;// duration in seconds
552 digitalWrite(BLU_LED, HIGH);
553 break;
554 case 4:
555 sub = 3;
556 break;
557 }
558}
559
560void process_RED() {
561 if (run_RED) {
562 if (millis() - prevMillis_RED >= interval_RED) {
563 // Elapse time has reached the interval
564 // Save the current time as previous time
565 //prevMillis_RED = currMillis_ALL;
566 run_RED = false;
567 digitalWrite(RED_LED, LOW);
568 }
569 }
570}
571
572void process_YEL() {
573 if (run_YEL) {
574 if (millis() - prevMillis_YEL >= interval_YEL) {
575 // Elapse time has reached the interval
576 // Save the current time as previous time
577 //prevMillis_RED = currMillis_ALL;
578 run_YEL = false;
579 digitalWrite(YEL_LED, LOW);
580 }
581 }
582}
583
584void process_BLU() {
585 if (run_BLU) {
586 if (millis() - prevMillis_BLU >= interval_BLU) {
587 // Elapse time has reached the interval
588 // Save the current time as previous time
589 //prevMillis_RED = currMillis_ALL;
590 run_BLU = false;
591 digitalWrite(BLU_LED, LOW);
592 }
593 }
594}
Posts in this series
- How to Get Started with ATTiny85 in Arduino IDE
- Tutorial: How to use MFRC522 RFID module using Arduino
- SOS Flasher Using Millis Function with Enable Switch
- Tutorial: How to use DS3231 RTC in Arduino
- Tutorial: How to use 0.96 OLED - a small and cute display
- Tutorial: Getting Started with the NRF24L01 | How to use | Arduino
- Tutorial: How to use SIM800L GSM Module for Controlling Anything | Arduino
- Tutorial: How to use Keypad | Text Entry Mode | Arduino
- Tutorial: How to use 4x4 Keypad | Arduino
- Project Idea: Arduino Voltmeter
- Project Idea: Door Lock Security | Arduino
- Tutorial Understanding Blink Without Delay | How to millis
- Arduino Simple LCD Menu
- How to use SIM800L GSM Module using Arduino | Make or Answer Voice Calls
- Tutorial: How to Use Arduino Uno as HID | Part 2: Arduino Mouse Emulation
- Tutorial: How to Use Arduino Uno as HID | Part 1: Arduino Keyboard Emulation
- Tutorial: How to use SIM800L DTMF to Control Anything | Arduino
- Tutorial: Arduino EEPROM
- How to use SIM800L GSM Module | Arduino | Send and Receive SMS
- 16x2 LCD Menu for Arduino
- Tutorial: Arduino GPIO | How to use Arduino Pins
- MIT App Inventor for Arduino
- RC Car using L298N, HC-06, and Arduino Uno
- How to Use LCD Keypad Shield for Arduino
- How to Use Arduino Interrupts
- Project: Automatic Alcohol Dispenser
- TUTORIAL: How to use HC-SR04 Ultrasonic Sensor with Arduino
- Source Code: Astronomia Meme and Funeral Dance | melodies the Arduino way
- How to Get Started with L293D Motor Driver Shield with Arduino
- How to Get Started with L298N Motor Driver module using Arduino
- Part 2: Wav Music Player with Lyrics Using Arduino and SD Card
- Interfacing Infrared to Arduino Uno
- Part 1: Wav Music Player Using Arduino Uno and SD Card
- How to Interface Stepper Motor to Arduino Uno
- How To Play MP3 Files on Arduino from SD Card
- What is Arduino Software Serial
- How to Interface SD card to Arduino (without SD card shield)?
- Playing Melodies Using Arduino
- 8 Degrees Of Freedom (DOF) Robot Using Arduino Uno
- How to Interface PS2 Controller to Arduino Uno
- Part 3: DF Player Mini Tinkering with Arduino Nano and LCD
- How to Interface HC-06 to Arduino
- How to make a Remote Control RC car using Arduino and HC-06 bluetooth module
- Part 2: DF Player Mini Tinkering with Arduino Nano
- Part 1: DF Player Mini - a mini cheap mp3 player
No comments yet!