Page Navigation Using Arduino
Introduction
Arduinos are very common microcontroller boards used to study and design programmable electronics. It is often used with multiple peripherals such as buttons, sliders, sensors and motors.
Together with a TIMI acting as a small fancy display, Arduino boards become a lot more powerful and interesting to use in prototyping.
Requirements
To proceed with the project, the following are required.
Hardware
- TIMI-96
- Mates Programmer
- USB Type A to microUSB cable (for the Mates Programmer)
- USB Type A to Type B cable (for the Arduino, replace as necessary)
- Connecting Wires
- Arduino Uno
- Breadboard
Software
Graphics Design
Step 1: Open Mates Studio and create a Commander project for TIMI-96 with Reversed Landscape orientation.
Step 2: Browse the library for appropriate page designs.
- For this project, the following pages are used:
-
Category: Date and Time, Page: Digital Clock
-
-
Category: Notifications, Page: 8 x Flat Round Led
-
-
Category: Graphs, Page: Various Gauges Green
-
-
Category: Miscellaneous, Page: Various Digits
-
-
Category: Notifications, Page: 6-Line Black BG Print Area
-
-
Category: Notifications, Page: 6-Line Hex Print Area
-
-
Category: Audio, Page: Media Spectrum
-
-
Category: Graphs, Page: Full Scope
-
-
Category: Notifications, Page: Full Dot Matrix
-
Step 3: After finalizing the design, connect TIMI-96 to your computer
Step 4: Upload the project to the appropriate COM port
Step 5: When prompted, click Proceed to continue with upload.
Note
It is recommended that the graphics design is finalized before moving to the next steps when working on a project.
Programming the Arduino
Step 1: Install the MatesController library using Arduino’s Library Manager.
Step 2: Include MatesController.h to your project.
Step 3: Create a MatesController instance named mates
This will initialize the MatesController instance to the default reset pin 4 using a LOW pulse.
Step 4: (Optional) Create a function for toggling the built-in LED of the Arduino board. This can be used for debugging or showing errors if the Serial monitor can’t be used.
int errLedStatus = LOW;
void ErrorLed_Toggle() {
errLedStatus = ~errLedStatus;
digitalWrite(LED_BUILTIN, errLedStatus);
}
Step 5: (Optional) At the beginning of the setup function, set the built-in LED pin to OUTPUT and set it to LOW.
Step 6: To start using the MatesController instance, use the begin
function
This will initialize the Serial UART at the default baudrate of 9600
Step 7: (Optional) The begin
function can be enclosed in an if condition to handle initialization errors.
if (!mates.begin()) {
// Display didn't send ready signal in time
while (1) {
ErrorLed_Toggle();
delay(100);
}
}
Step 8: To simulate each of the pages, functions to handle simulated animations can be prepared.
void Day_and_Time_Animation(void) {
// Days of Week Strings
const char * daysOfWeek[] = {
"SUNDAY",
"MONDAY",
"TUESDAY",
"WEDNESDAY",
"THURSDAY",
"FRIDAY",
"SATURDAY"
};
// Test Start Values: Monday, 23:59:47 (will actually start at 48 seconds)
uint8_t lastDay = 1;
uint8_t day = 1;
int16_t hrs = 23;
int16_t min = 59;
int16_t sec = 47;
mates.updateTextArea(0, daysOfWeek[day]);
// Simulated Timer Variable
unsigned long lastUpdate = millis() - 1000; // Ensures first write
// stop at Day 2, Tuesday, 00:00:0 7
while (day != 2 || hrs != 0 || min != 0 || sec != 7) {
if (millis() - lastUpdate >= 1000) {
lastUpdate = millis();
sec++;
if (sec == 60) {
sec = 0;
min++;
}
if (min == 60) {
min = 0;
hrs++;
}
if (hrs == 24) {
hrs = 0;
day++;
}
day %= 7;
// mates.setWidgetValue(MATES_LED_DIGITS, 0, hrs);
// mates.setWidgetValue(MATES_LED_DIGITS, 1, min);
// mates.setWidgetValue(MATES_LED_DIGITS, 2, sec);
mates.setLedDigitsValue(0, hrs);
mates.setLedDigitsValue(1, min);
mates.setLedDigitsValue(2, sec);
if (lastDay != day) {
mates.updateTextArea(0, daysOfWeek[day]);
lastDay = day; // prevents writing the same text to TextArea
}
}
}
}
void Numbered_LEDs_Animation(void) {
mates.setWidgetValue(MATES_MEDIA_LED, 0, 1);
uint8_t ledOff = 0;
uint8_t ledOn = 1;
for (int i = 0; i < 20; i++) {
delay(500);
mates.setWidgetValue(MATES_MEDIA_LED, ledOff, 0);
mates.setWidgetValue(MATES_MEDIA_LED, ledOn, 1);
ledOff = ledOn;
ledOn++;
ledOn %= 8;
}
mates.setWidgetValue(MATES_MEDIA_LED, ledOff, 0);
}
void Various_Gauges_Animation(void) {
int16_t value = 0;
int8_t inc = 1;
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 10000) {
value += inc;
if (value == 100) inc = -1;
if (value == 0) inc = 1;
mates.setWidgetValue(MATES_GAUGE_A, 0, value);
mates.setWidgetValue(MATES_LED_DIGITS, 3, value);
mates.setWidgetValue(MATES_MEDIA_GAUGE_B, 0, value);
}
}
void Various_Digits_Animation(void) {
int16_t value = 0;
int32_t longValue = 100000;
float floatValue = 3.1416;
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 5000) {
// mates_setWidgetValue(MATES_LED_DIGITS, 4, value);
mates.setLedDigitsValue(4, value);
mates.setLedDigitsValue(5, longValue);
mates.setLedDigitsValue(6, floatValue);
value++;
longValue += 12345;
floatValue += 3.1416;
}
}
void Print_Strings_Animation(void) {
const char * msg = "Mates Studio offers a variety of widgetswhich includes this Print Area. For moreinfo, please refer to our manuals.";
uint8_t len = (uint8_t) strlen(msg);
char str[2];
mates.appendToPrintArea(0, msg);
delay(2000);
mates.clearPrintArea(0);
for (uint8_t i = 0; i < len; i++) {
str[0] = msg[i];
str[1] = 0;
mates.appendToPrintArea(0, str);
delay(50);
}
}
void Print_Hex_Values_Animation(void) {
const int16_t colors[] = {
(int16_t) 0xFFFF, (int16_t) 0xF800, (int16_t) 0x07E0, (int16_t) 0x001F,
(int16_t) 0x07FF, (int16_t) 0xF81F, (int16_t) 0xFFE0, (int16_t) 0x39FF
};
int8_t val = 0;
int8_t ctr = 0;
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 5000) {
if (ctr >= 42) {
mates.clearPrintArea(0);
ctr = 0;
}
mates.setPrintAreaColor(1, colors[ctr % 8]);
mates.appendToPrintArea(1, &val, 1);
ctr++;
val++;
delay(100);
}
}
void Audio_Spectrum_Animation(void) {
uint8_t col = 1;
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 5000) {
// mates.setSpectrumValue(MATES_MEDIA_SPECTRUM, 0, (uint8_t) (rand() % 101));
mates.setMediaSpectrumValue(0, col, (uint8_t) (rand() % 101));
col++;
if (col == 6) col = 0;
}
}
void Updating_Scope_Animation(void) {
// uint16_t deg = 270; // Use for computed version
int16_t value = 18;
const int16_t values[] = {
40, 50, 59, 67, 73, 77, 79, 77, 73, 67, 59, 50,
40, 29, 20, 12, 6, 2, 1, 2, 6, 12, 20, 29
};
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 5000) {
// Computed version START
/*
deg += 15;
if (deg >= 360) {
deg %= 360;
}
// 180 / PI = 57.29578
// value = (int16_t) (39 * sin(deg * 3.1416 / 180)) + 40;
value = (int16_t) (39 * sin(deg / 57.29578)) + 40;
// Float computations can take a significant time
mates.setWidgetValue(MATES_SCOPE, 0, value);
*/
// Computed version END
// Pre-computed version START
value++;
if (value >= 24) value = 0;
mates.setWidgetValue(MATES_SCOPE, 0, values[value]);
// Pre-computed version END
}
}
void Update_Dot_Matrix(void) {
char buffer[25] = "DotMatrxVal1 XXXVal2 XXX"; // 24 characters + null terminator (8 * 3 + 1 = 25)
char * val1ptr = buffer + 13;
char * val2ptr = buffer + 21;
uint8_t val1 = 0;
uint8_t val2 = 255;
unsigned long lastUpdate = millis();
while (millis() - lastUpdate <= 5000) {
// START of Simulated Values
val1++;
val2--;
if (val1 < 100) {
val1ptr[0] = ' ';
} else {
val1ptr[0] = '0' + (val1 / 100);
}
if (val1 < 10) {
val1ptr[1] = ' ';
} else {
val1ptr[1] = '0' + ((val1 % 100) / 10);
}
val1ptr[2] = '0' + (val1 % 10);
if (val2 < 100) {
val2ptr[0] = ' ';
} else {
val2ptr[0] = '0' + (val2 / 100);
}
if (val2 < 10) {
val2ptr[1] = ' ';
} else {
val2ptr[1] = '0' + ((val2 % 100) / 10);
}
val2ptr[2] = '0' + (val2 % 10);
// END of Simulated Values
mates.updateDotMatrix(0, buffer);
}
}
Step 9: Each function can then be defined into a function pointer array
void (* animations[])(void) = {
Day_and_Time_Animation,
Numbered_LEDs_Animation,
Various_Gauges_Animation,
Various_Digits_Animation,
Print_Strings_Animation,
Print_Hex_Values_Animation,
Audio_Spectrum_Animation,
Updating_Scope_Animation,
Update_Dot_Matrix
};
Step 10: In the loop function, the page navigation is done every iteration.
void loop() {
static uint16_t page = 0;
(*animations[page])();
page++;
page %= 9;
mates.setPage(page);
}
As shown, the loop starts by performing the animation. The page counter is then incremented until the last page number and reset as necessary. The next page is then activated at the end of the loop.
Running the Project
After designing the user interface for TIMI and writing code for the Arduino and programming them, it is time to connect the devices together. Follow the diagram below for the connection between TIMI and Arduino.
Finally, supply power to the Arduino and observe the behavior of the project.
Downloadable Resources
Here are the links to the software applications, libraries and completed project files.