/**********************************************************************
MULTITASKING
Code by lingib
Last update 6 February 2016
This code uses a task scheduler to implement multi-tasking on an arduino.
----------
COPYRIGHT
----------
This code is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License. If
not, see .
***************************************************************************/
// ----- libraries
#include // required for I2C
#include // from http://arduino-info.wikispaces.com/LCD-Blue-I2C#v1
#define LED 13 // onboard LED
// ----- define LCD pinouts: addr,en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// ----- custom bargraph patterns
byte column0[8] = { // 1 column
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111
};
byte column1[8] = { // 2 columns
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111
};
byte column2[8] = { // 3 columns
B00000,
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111
};
byte column3[8] = { // 4 columns
B00000,
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
B11111
};
byte column4[8] = { // 4 columns
B00000,
B00000,
B00000,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte column5[8] = { // 4 columns
B00000,
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte column6[8] = { // 4 columns
B00000,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
byte column7[8] = { // 4 columns
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111,
B11111
};
// ----- message generator
char
MessageArray[] = " Multi-tasking DEMO: The arduino is controlling the LED, the text, and the custom bar graph. ";
int
MessageLength = strlen(MessageArray);
String
Message = MessageArray,
Display;
// ----- task scheduler (Interrupt Service Routine)
int
TaskTimer1 = 0,
TaskTimer2 = 0,
TaskTimer3 = 0;
bool
TaskFlag1 = false,
TaskFlag2 = false,
TaskFlag3 = false;
/******************************
setup()
*******************************/
void setup() {
// ----- configure serial port (optional)
Serial.begin(9600); //serial port
// ----- configure LCD display
lcd.begin(16, 2); //16 char x 2 line LCD display
// ----- install custom characters
lcd.createChar(0, column0);
lcd.createChar(1, column1);
lcd.createChar(2, column2);
lcd.createChar(3, column3);
lcd.createChar(4, column4);
lcd.createChar(5, column5);
lcd.createChar(6, column6);
lcd.createChar(7, column7);
// ----- configure LED
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
// ----- configure Timer 2 to generate a compare-match interrupt every 1mS
noInterrupts(); // disable interrupts
TCCR2A = 0; // clear control registers
TCCR2B = 0;
TCCR2B |= (1 << CS22) | // 16MHz/128=8uS
(1 << CS20) ;
TCNT2 = 0; // clear counter
OCR2A = 125 - 1; // 8uS*125=1mS (allow for clock propagation)
TIMSK2 |= (1 << OCIE2A); // enable output compare interrupt
interrupts(); // enable interrupts
}
// ------------------------------
// loop()
// ------------------------------
void loop() {
/*
Tasks are only performed if the TaskFlag
has been set by the task-scheduler.
*/
// ----- toggle LED
if (TaskFlag1) {
TaskFlag1 = false;
digitalWrite(LED, !digitalRead(LED));
}
// ----- scroll message
if (TaskFlag2) {
TaskFlag2 = false;
scrollMessage();
}
// ----- bargraph
if (TaskFlag3) {
TaskFlag3 = false;
bargraph();
}
// // ----- title for Instructable
// lcd.setCursor(0,0);
// lcd.print("How to multitask");
// lcd.setCursor(0,1);
// lcd.print(" your ARDUINO ");
}
// -------------------------------
// task scheduler (1mS interrupt)
// -------------------------------
ISR(TIMER2_COMPA_vect)
{
// ----- timers
/*
Each timer counts the number of milliseconds since its associated task was
last performed. Each additional task requires another timer and flag.
*/
TaskTimer1++;
TaskTimer2++;
TaskTimer3++;
// ----- task1
if (TaskTimer1 > 300 - 1) { // toggle LED (300mS)
TaskTimer1 = 0;
TaskFlag1 = true;
}
// ----- task2
if (TaskTimer2 > 250 - 1) { // scroll message (250mS)
TaskTimer2 = 0;
TaskFlag2 = true;
}
// ----- task3
if (TaskTimer3 > 100 - 1) { // bargraph (100mS)
TaskTimer3 = 0;
TaskFlag3 = true;
}
}
// ----------------------------
// displayMessage()
// ----------------------------
void scrollMessage() {
// ----- locals
/*
static variables remember the last value
when the subroutine is re-entered.
*/
static int index = 0;
// ----- grab the next 16 characters from the message
lcd.setCursor(0, 0);
Display = Message.substring(index, index + 16);
lcd.print(Display);
index++;
if (index > MessageLength - 15) index = 0;
}
// -------------------------------
// bargraph()
// -------------------------------
void bargraph() {
// ----- locals
static int column = 0;
// ----- reset display
if (column == 0) {
lcd.setCursor(0, 1);
lcd.print("Volume: ");
}
// ----- display next symbol
lcd.setCursor(8 + column, 1);
lcd.write(byte(0 + column));
column++;
if (column > 7) column = 0;
}