/*
* LiquidMenu library - hello_menu.ino
* https://github.com/VasilKalchev/LiquidMenu
*/
// Libraries
#include <LiquidCrystal.h>
// The menu wrapper library
#include <LiquidMenu.h>
// Rotary encoder
#include <SimpleRotary.h>
// button library
#include <Button.h>
// countdown
#include <CountDown.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);
//
// Rotary encoder setup
//A,B,SW
SimpleRotary rotary(9,7,8);
// pos counter for rotary
int pos = 0;
// Use button library for rotary encoder button
Button enter(8);
//
// Long button press functionality for "START" reseting countdown timer
bool longpressState = 0;
const int BUTTON_PIN = 8; // the number of the pushbutton pin
const int LONG_PRESS_TIME = 500; // 500 milliseconds
// Variables will change:
int lastState = LOW; // the previous state from the input pin
int currentState; // the current reading from the input pin
unsigned long pressedTime = 0;
unsigned long releasedTime = 0;
/*
* Variables used for periodic execution of code. The first one is the period
* in milliseconds and the second one is the last time the code executed.
*/
unsigned int period_check = 1000;
unsigned long lastMs_check = 0;
unsigned int period_nextScreen = 5000;
unsigned long lastMs_nextScreen = 0;
//
// time it takes for one revolution (secs) / default rev count
int timeperRev = 5;
// number of plater revs (1cw, 1ccw)
byte revCount = 2;
// calculated time to be counted down from
uint32_t totalTime = timeperRev * revCount;
uint32_t timeRemaining = totalTime;
//
// Initialize countdown timer function
CountDown CD(CountDown::SECONDS);
uint32_t start, stop;
//
// Liquid Menu objects & setup
/*
* LiquidLine objects represent a single line of text and/or variables
* on the display. The first two parameters are the column and row from
* which the line starts, the rest of the parameters are the text and/or
* variables that will be printed on the display. They can be up to four.
*/
// Here the line is set to column 1, row 0 and will print the passed
// string and the passed variable.
LiquidLine welcome_line1(2, 0, "Set Revs: ", revCount);
LiquidLine welcome_line2(2, 1, "Time Left:", timeRemaining);
LiquidLine welcome_line3(16, 1, "secs");
LiquidLine welcome_line41(0, 3, "START");
LiquidLine welcome_line42(6, 3, "| STOP");
LiquidLine welcome_line43(13, 3, "| EDIT");
/*
* LiquidScreen objects represent a single screen. A screen is made of
* one or more LiquidLine objects. Up to four LiquidLine objects can
* be inserted from here, but more can be added later in setup() using
* welcome_screen.add_line(someLine_object);.
*/
// Here the LiquidLine objects are the objects from above.
LiquidScreen welcome_screen(welcome_line1, welcome_line2, welcome_line41, welcome_line42);
// Here there is not only a text string but also a changing integer variable.
LiquidLine revCount_line(0, 0, "Change Revs: ", revCount);
LiquidLine goBack_line(0, 2, "BACK");
LiquidScreen secondary_screen(revCount_line, goBack_line);
/*
* The LiquidMenu object combines the LiquidScreen objects to form the
* menu. Here it is only instantiated and the screens are added later
* using menu.add_screen(someScreen_object);. This object is used to
* control the menu, for example: menu.next_screen(), menu.switch_focus()...
*/
LiquidMenu menu(lcd);
//
// Custom functions:
//
// button press for next screen
void nextScreen1() {
menu.next_screen();
}
// button press for next screen
void nextScreen2() {
menu.switch_focus();
menu.previous_screen();
}
byte statusLed = 13;
bool onoroff = false;
bool ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 700;
bool trigger = false;
// START button on menu
void togglePwr(){
onoroff = !onoroff;
//start timer
CD.cont();
// long press to start/reset timer
if (longpressState == 1){
start = millis();
CD.start(totalTime);
timeRemaining = CD.remaining();
longpressState = false;
ledState = HIGH;
digitalWrite(statusLed, ledState);
}
// pause functionality for "START" on menu
if (onoroff == false){
CD.stop();
}
// turn LED off if timer isn't running
if (CD.isRunning() == 0){
ledState = LOW;
digitalWrite(statusLed, ledState);
}
else {
ledState = HIGH;
digitalWrite(statusLed, ledState);
}
delay(100);
}
// STOP button on menu
void togglePwr2(){
// change state to off
onoroff = false;
//pause timer
CD.stop();
// turn off led
trigger = false;
ledState = LOW;
digitalWrite(statusLed, ledState);
}
// set revs, value adjust
bool flip = false;
void changerevFunc() {
while (flip == true){
byte i=0;
i = rotary.rotate();
if (i == 1){
revCount = revCount + 2;
menu.update();
}
if (i == 2){
revCount = revCount - 2;
menu.update();
}
if (enter.released()){
flip = !flip;
}
totalTime = timeperRev * revCount;
}
}
// focus symbol
uint8_t rFocus[8] = {
0b00011,
0b00110,
0b01100,
0b11000,
0b11000,
0b01100,
0b00110,
0b00011
};
void setup() {
Serial.begin(250000);
lcd.begin(20, 4);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(statusLed, OUTPUT);
// Liquid menu setup
menu.set_focusSymbol(Position::RIGHT, rFocus);
// Sets the focus position for this line to be on the right.
welcome_line41.set_focusPosition(Position::RIGHT);
welcome_line42.set_focusPosition(Position::RIGHT);
welcome_line43.set_focusPosition(Position::RIGHT);
// Attaching a function to a line makes the line focusable.
//welcome_line43.attach_function(1, func);
// Function to attach functions to LiquidLine objects.(function#,function name)
welcome_line43.attach_function(2, nextScreen1);
goBack_line.attach_function(3, nextScreen2);
revCount_line.attach_function(4, changerevFunc);
welcome_line41.attach_function(5, togglePwr);
welcome_line42.attach_function(6, togglePwr2);
// This is the method used to add a screen object to the menu.
menu.add_screen(welcome_screen);
menu.add_screen(secondary_screen);
welcome_screen.add_line(welcome_line43);
welcome_screen.add_line(welcome_line3);
menu.update();
}
void loop() {
// long press button functionality
longpressState = 0;
// read the state of the switch/button:
currentState = digitalRead(BUTTON_PIN);
if(lastState == HIGH && currentState == LOW) // button is pressed
pressedTime = millis();
else if(lastState == LOW && currentState == HIGH) { // button is released
releasedTime = millis();
long pressDuration = releasedTime - pressedTime;
if( pressDuration > LONG_PRESS_TIME ){
Serial.println("A long press is detected");
longpressState = 1;
}
else{
longpressState = 0;
}
}
// save the the last state
lastState = currentState;
// menu.call_function & menu.update conditions
if (enter.released() || longpressState == 1) {
Serial.println(F("Enter"));
// Calls the function identified with one
// for the focused line.
menu.call_function(2);
menu.call_function(3);
menu.call_function(4);
menu.call_function(5);
menu.call_function(6);
flip = !flip;
Serial.println(flip);
}
/*
* Check if the revcount has changed
* and update the display if it has.
*/
static unsigned short lastrevCount = 0;
if (revCount != lastrevCount) {
lastrevCount = revCount;
menu.update();}
/*
* Check if the secs has changed
* and update the display if it has.
*/
static unsigned short lasttimeRemaining = 0;
if (timeRemaining != lasttimeRemaining) {
lasttimeRemaining = timeRemaining;
menu.update();
}
//Rotary button commands
byte bp;
byte i;
// 0 = not turning, 1 = CW, 2 = CCW
i = rotary.rotate();
bp = rotary.push();
//CW
if ( i == 1 ) {
Serial.print("CW ");
Serial.println(++pos);
menu.switch_focus();}
//CCW
if ( i == 2 ) {
Serial.print("CCW ");
Serial.println(--pos);}
if (CD.isRunning() == true){
timeRemaining = CD.remaining();
}
// Turn off system at end of timer
if (CD.remaining() == 0 && onoroff == true){
onoroff = false;
timeRemaining = 0;
}
// Blink if timer is done
unsigned long currentMillis = millis();
if (CD.remaining()== 1){
trigger = true;
}
if (trigger == true && onoroff == false && CD.remaining() == 0){
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
}
else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(statusLed, ledState);
}
}
}