C_functions_menu.ino

This example demonstrates how to attach functions to the "lines" in the menu.

/*
* LiquidMenu library - functions_menu.ino
*
* This example demonstrates how to attach functions to the
* "lines" in the menu.
*
* Attaching functions to the different "lines" in the menu makes it
* possible to execute an action through the menu (e.g. dimming an LED,
* adjusting preferences...). To attach a function to a line you need
* to create with signature "void functionName(void)". After creating it,
* the function is ready to be attached to a line. To dothat call bool
* LiquidLine::attach_function(uint8_t number, void (*function)(void)).
* LiquidLine is the line object you wish to attach the function to,
* number is the "id" of the function for that line, void (*function)(void)
* is just the name of the function without the "()". The "id" of the function
* makes possible attaching multiple functions to a single line. An example use
* of multiple functions on a single line is for incrementing or decrementing
* some value (e.g. dimming an LED). It is convenient to attach all the different
* incrementing functions (e.g. increase_brightness(), increase_volume()) to the
* different lines (e.g. LED brightness: 5, Sound volume: 10) using the same id
* (e.g. 1). Same goes for the decrementing functions (e.g. LED brightness: 5 (line)
* with attached function decrease_brightness() (function) with id 2,
* Sound volume: 10 (line) with attached function decrease_volume() (function) with id 2).
* Similar functions should be attached to their corresponding lines with the same "id",
* because then they can be called from the same event (e.g. pressing button "UP"
* calls the incrementing function of whatever the focused line is).
* This example has a line that shows the current PWM of the LED and lines
* that allow a fade or blink loop to be turned ON/OFF and configured.
*
* The circuit:
* https://github.com/VasilKalchev/LiquidMenu/blob/master/examples/functions_menu/C_functions_menu.png
* - LCD RS pin to Arduino pin 12
* - LCD E pin to Arduino pin 11
* - LCD D4 pin to Arduino pin 5
* - LCD D5 pin to Arduino pin 4
* - LCD D6 pin to Arduino pin 3
* - LCD D7 pin to Arduino pin 2
* - LCD R/W pin to ground
* - LCD VSS pin to ground
* - LCD VDD pin to 5V
* - 10k ohm potentiometer: ends to 5V and ground, wiper to LCD V0
* - 150 ohm resistor from 5V to LCD Anode
* - LCD Cathode to ground
* - ----
* - Button (left) to Arduino pin A0 and ground
* - Button (right) to Arduino pin 7 and ground
* - Button (up) to Arduino pin 8 and ground
* - Button (down) to Arduino pin 9 and ground
* - Button (enter) to Arduino pin 10 and ground
* - A PWM controlled device (LED...) to Arduino pin 6
*
* Created July 24, 2016
* by Vasil Kalchev
*
* https://github.com/VasilKalchev/LiquidMenu
*
*/
#include <LiquidCrystal.h>
#include <LiquidMenu.h>
#include "Button.h"
// Pin mapping for the display
const byte LCD_RS = 12;
const byte LCD_E = 11;
const byte LCD_D4 = 5;
const byte LCD_D5 = 4;
const byte LCD_D6 = 3;
const byte LCD_D7 = 2;
//LCD R/W pin to ground
//10K potentiometer wiper to VO
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// This variable can be passed to the LiquidMenu object to set the starting screen.
const byte startingScreen = 2;
// Button objects instantiation
/*
* The Button class is not a part of the LiquidMenu library. The first
* parameter is the button's pin, the second enables or disables the
* internal pullup resistor (not required) and the third is the debounce
* time (not required).
*/
const bool pullup = true;
Button left(A0, pullup);
Button right(7, pullup);
Button up(8, pullup);
Button down(9, pullup);
Button enter(10, pullup);
/*
* An enumerator can be used for the callback functions. It sets the number
* for similar functions. Later when a function is attached it can be passed
* with this enum rather than a magic number.
*/
// There are two types of functions for this example, one that increases some
// value and one that decreases it.
enum FunctionTypes {
increase = 1,
decrease = 2,
};
// These are the pin definitions and variables for their PWM state.
const byte led = 6;
byte led_level = 0;
// Variables used for setting "preferences".
bool isFading = false;
char* isFading_text;
unsigned int fadePeriod = 100;
bool isBlinking = false;
char* isBlinking_text;
unsigned int blinkPeriod = 1000;
LiquidLine welcome_line1(1, 0, "LiquidMenu ", LIQUIDMENU_VERSION);
LiquidLine welcome_line2(1, 1, "Functions ex.");
LiquidScreen welcome_screen(welcome_line1, welcome_line2);
LiquidLine ledTitleLine(6, 0, "LED");
LiquidLine led_line(4, 1, "Level: ", led_level);
LiquidScreen led_screen(ledTitleLine, led_line);
LiquidLine fade_line(0, 0, "Fade - ", isFading_text);
LiquidLine fadePeriod_line(0, 1, "Period: ", fadePeriod, "ms");
LiquidScreen fade_screen(fade_line, fadePeriod_line);
LiquidLine blink_line(0, 0, "Blink - ", isBlinking_text);
LiquidLine blinkPeriod_line(0, 1, "Period: ", blinkPeriod, "ms");
LiquidScreen blink_screen(blink_line, blinkPeriod_line);
LiquidMenu menu(lcd, startingScreen);
// Callback functions
void increase_led_level() {
if (led_level < 225) {
led_level += 25;
} else {
led_level = 0;
}
analogWrite(led, led_level);
}
void decrease_led_level() {
if (led_level > 25) {
led_level -= 25;
} else {
led_level = 250;
}
analogWrite(led, led_level);
}
void fade_switch() {
led_off();
if (isFading == true) {
isFading = false;
isFading_text = (char*)"OFF";
} else {
isFading = true;
isFading_text = (char*)"ON";
isBlinking = false;
isBlinking_text = (char*)"OFF";
}
}
void increase_fadePeriod() {
if (fadePeriod < 3000) {
fadePeriod += 10;
}
}
void decrease_fadePeriod() {
if (fadePeriod > 10) {
fadePeriod -= 10;
}
}
void blink_switch() {
led_off();
if (isBlinking == true) {
isBlinking = false;
isBlinking_text = (char*)"OFF";
} else {
isBlinking = true;
isBlinking_text = (char*)"ON";
isFading = false;
isFading_text = (char*)"OFF";
}
}
void increase_blinkPeriod() {
if (blinkPeriod < 3000) {
blinkPeriod += 50;
}
}
void decrease_blinkPeriod() {
if (blinkPeriod > 50) {
blinkPeriod -= 50;
}
}
void led_off() {
led_level = 0;
analogWrite(led, led_level);
}
// Checks all the buttons.
void buttonsCheck() {
if (right.check() == LOW) {
menu.next_screen();
}
if (left.check() == LOW) {
menu.previous_screen();
}
if (up.check() == LOW) {
// Calls the function identified with
// increase or 1 for the focused line.
menu.call_function(increase);
}
if (down.check() == LOW) {
menu.call_function(decrease);
}
if (enter.check() == LOW) {
// Switches focus to the next line.
menu.switch_focus();
}
}
// The fading function.
void fade() {
static bool goingUp = true;
if (goingUp) {
led_level += 25;
} else {
led_level -= 25;
}
if (led_level > 225) {
goingUp = false;
led_level = 250;
}
if (led_level < 25 && goingUp == false) {
goingUp = true;
led_level = 0;
}
analogWrite(led, led_level);
}
// The blinking function.
void blink() {
static bool blinkState = LOW;
if (blinkState == LOW) {
blinkState = HIGH;
led_level = 255;
} else {
blinkState = LOW;
led_level = 0;
}
analogWrite(led, led_level);
}
void setup() {
Serial.begin(250000);
pinMode(led, OUTPUT);
lcd.begin(16, 2);
// The increasing functions are attached with identification of 1.
/*
* This function can later be called by pressing the 'UP' button
* when 'led_line' is focused. If some other line is focused it's
* corresponding function will be called.
*/
led_line.attach_function(increase, increase_led_level);
// The decreasing functions are attached with identification of 2.
led_line.attach_function(decrease, decrease_led_level);
// Here the same function is attached with two different identifications.
// It will be called on 'UP' or 'DOWN' button press.
fade_line.attach_function(1, fade_switch);
fade_line.attach_function(2, fade_switch);
fadePeriod_line.attach_function(increase, increase_fadePeriod);
fadePeriod_line.attach_function(decrease, decrease_fadePeriod);
blink_line.attach_function(1, blink_switch);
blink_line.attach_function(2, blink_switch);
blinkPeriod_line.attach_function(increase, increase_blinkPeriod);
blinkPeriod_line.attach_function(decrease, decrease_blinkPeriod);
menu.add_screen(welcome_screen);
menu.add_screen(led_screen);
menu.add_screen(fade_screen);
menu.add_screen(blink_screen);
isFading_text = (char*)"OFF";
isBlinking_text = (char*)"OFF";
menu.update();
}
void loop() {
buttonsCheck();
static unsigned long lastMillis_blink = 0;
if ((isFading == true) && ((millis() - lastMillis_blink) > fadePeriod)) {
lastMillis_blink = millis();
fade();
menu.update();
}
static unsigned long lastMillis_fade = 0;
if ((isBlinking == true) && ((millis() - lastMillis_fade) > blinkPeriod)) {
lastMillis_fade = millis();
blink();
menu.update();
}
}