Menu with voice & encoder code
Download the .zip file below with the full code or copy it from belwo as well. Unzip it and open it in Arduino IDE. Compile and upload.
/*
Menu with voice and rotary encoder
http://www.electronoobs.com/eng_arduino_tut22.php
http://www.youtube.com/c/ELECTRONOOBS
*/
//Inport the libraries
#include <DFMiniMp3.h>
//LCD config
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f,20,4); //sometimes the LCD adress is not 0x3f. Change to 0x27 if it dosn't work.
////////////////////Serial prints for the DFplayer/////////////////////////////
class Mp3Notify
{
public:
static void OnError(uint16_t errorCode)
{
// see DfMp3_Error for code meaning
Serial.println();
Serial.print("Com Error ");
Serial.println(errorCode);
}
static void OnPlayFinished(uint16_t globalTrack)
{
Serial.println();
Serial.print("Play finished for #");
Serial.println(globalTrack);
}
static void OnCardOnline(uint16_t code)
{
Serial.println();
Serial.print("Card online ");
Serial.println(code);
}
static void OnCardInserted(uint16_t code)
{
Serial.println();
Serial.print("Card inserted ");
Serial.println(code);
}
static void OnCardRemoved(uint16_t code)
{
Serial.println();
Serial.print("Card removed ");
Serial.println(code);
}
};
DFMiniMp3<HardwareSerial, Mp3Notify> mp3(Serial);
/////////////////////////////////////////////////////////
//Vectors for musical note and arrow
uint8_t note[8] = {0x02, 0x03, 0x02, 0x0e, 0x1e, 0x0c, 0x00, 0x00};
uint8_t arrow[8] = {0x0, 0x04 ,0x06, 0x1f, 0x06, 0x04, 0x00, 0x00};
//Variables for the menu encoder
int counter = 0;
int page=1;
int Ready=1;
int submenu=0;
int last_counter = 0;
bool clk_State;
bool Last_State;
bool dt_State;
int pushed = 0;
//The pin for the push button
#define push 10
void setup() {
pinMode (push,INPUT); //Define the pin as input
lcd.init(); //Init the LCD
lcd.backlight(); //Activate backlight
lcd.createChar(0, note); //Create the note symbol
lcd.createChar(1, arrow); //Create the arrow symbol
lcd.home(); //Home the LCD
PCICR |= (1 << PCIE0); //enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); //Set pin D8 trigger an interrupt on state change.
PCMSK0 |= (1 << PCINT1); //Set pin D9 trigger an interrupt on state change.
DDRB &= B11111100; //8, 9 as input for the encoder clock and data pins
Last_State = (PINB & B00000001); //pin 8 state (clock pin)?
//Prepare the DFplayer module comunication and settings
Serial.begin(115200);
mp3.begin();
uint16_t volume = mp3.getVolume();
mp3.setVolume(20);
uint16_t count = mp3.getTotalTrackCount();
//Print the initial text. Delete these lines if you don't want that
lcd.clear();
lcd.setCursor(0,0);
lcd.write(0);
lcd.print(" ELECTRONOOBS ");
lcd.write(0);
lcd.setCursor(0,1);
lcd.print(" Coffee machine ");
delay(3000);
//Print the first page menu.
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("Choose coffee");
lcd.setCursor(0,1);
lcd.print(" Sugar level");
}
//Void for the DFplayer to play sounds
void waitMilliseconds(uint16_t msWait)
{
uint32_t start = millis();
while ((millis() - start) < msWait)
{
mp3.loop(); // calling mp3.loop() periodically allows for notifications to be handled without interrupts
delay(1);
}
}
void loop() {
if((last_counter > counter) || (last_counter < counter) || pushed) //Only print on the LCD when a step is detected or the button is pushed.
{
Ready=1;
//First page of the menu
if(submenu == 0)
{
if(0 <= counter && counter < 5)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("Choose coffee");
lcd.setCursor(0,1);
lcd.print(" Sugar level");
page=1;
if(pushed)
{
mp3.playMp3FolderTrack(1); // play coffe select sound
pushed=0;
}
}
if(5 < counter && counter < 10)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Choose coffee");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("Sugar level");
page=2;
if(pushed)
{
mp3.playMp3FolderTrack(2);
pushed=0;
}
}
if(10 < counter && counter < 15)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("Backlight");
lcd.setCursor(0,1);
lcd.print(" Volume");
page=3;
if(pushed)
{
mp3.playMp3FolderTrack(3);
pushed=0;
}
}
if(15 < counter && counter < 20)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Backlight");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("Volume");
page=4;
if(pushed)
{
mp3.playMp3FolderTrack(4);
pushed=0;
}
}
}//submenu = 0;
//Second page of the menu
if(submenu == 1)
{
if(0 <= counter && counter < 5)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("Latte");
lcd.setCursor(0,1);
lcd.print(" Cappuccino");
page=1;
pushed=0;
}
if(5 < counter && counter < 10)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Latte");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("Cappuccino");
page=2;
pushed=0;
}
if(10 < counter && counter < 15)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("Americano");
lcd.setCursor(0,1);
lcd.print(" Back");
page=3;
pushed=0;
}
if(15 < counter && counter < 20)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Americano");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("Back");
page=4;
pushed=0;
}
}//submenu = 1;
//Third page of the menu
if(submenu == 2)
{
if(0 <= counter && counter < 5)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("25%");
lcd.setCursor(0,1);
lcd.print(" 50%");
page=1;
pushed=0;
}
if(5 < counter && counter < 10)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" 25%");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("50%");
page=2;
pushed=0;
}
if(10 < counter && counter < 15)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("75%");
lcd.setCursor(0,1);
lcd.print(" 100%");
page=3;
pushed=0;
}
if(15 < counter && counter < 20)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" 75%");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("100%");
page=4;
pushed=0;
}
}//submenu = 2;
//Forth page of the menu
if(submenu == 3)
{
if(0 <= counter && counter < 5)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("ON");
lcd.setCursor(0,1);
lcd.print(" OFF");
page=1;
pushed=0;
}
if(5 < counter && counter < 10)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" ON");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("OFF");
page=2;
pushed=0;
}
}//submenu = 3;
if(submenu == 4)
{
if(0 <= counter && counter < 5)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("25%");
lcd.setCursor(0,1);
lcd.print(" 50%");
page=1;
pushed=0;
}
if(5 < counter && counter < 10)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" 25%");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("50%");
page=2;
pushed=0;
}
if(10 < counter && counter < 15)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.write(1);
lcd.print("75%");
lcd.setCursor(0,1);
lcd.print(" 100%");
page=3;
pushed=0;
}
if(15 < counter && counter < 20)
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" 75%");
lcd.setCursor(0,1);
lcd.write(1);
lcd.print("100%");
page=4;
pushed=0;
}
}//submenu = 4;
}//end of the MENU prints on the LCD
last_counter = counter; //Save the value of the last state
//Now we detect when we push the button
if(digitalRead(push))
{
if(submenu == 1)
{
if(page==1)
{
submenu=0;
counter=1;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(5); // Play sound
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Making coffee...");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==2)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(6); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Making coffee...");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==3)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(7); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Making coffee...");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==4)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(8); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Going back... ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(2000);
}
}//end of submenu 1
if(submenu == 2)
{
if(page==1)
{
submenu=0;
counter=1;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(9); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Sugar level 25%");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==2)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(10); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Sugar level 50%");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==3)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(11); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Sugar level 75%");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==4)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(12); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Sugar level 100%");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
}//end of submenu 1
if(submenu == 3)
{
if(page==1)
{
submenu=0;
counter=1;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(13); //
lcd.backlight();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Backlight ON ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
if(page==2)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(14); //
lcd.noBacklight();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Backlight OFF");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
}
}//end of submenu 1
if(submenu == 4)
{
if(page==1)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(15); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Volume 25% ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
mp3.setVolume(5);
}
if(page==2)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(16); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Volume 50% ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
mp3.setVolume(10);
}
if(page==3)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(17); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Volume 75% ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
mp3.setVolume(20);
}
if(page==4)
{
submenu=0;
counter=0;
pushed=0;
Ready=0;
mp3.playMp3FolderTrack(18); //
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" Volume 100% ");
lcd.setCursor(0,1);
lcd.print(" Wait ");
delay(4000);
mp3.setVolume(30);
}
}//end of submenu 1
if(submenu == 0 && Ready==1)
{
if(page==1)
{
submenu=1;
counter=0;
pushed=1;
mp3.playMp3FolderTrack(1); //
delay(500);
}
if(page==2)
{
submenu=2;
counter=0;
mp3.playMp3FolderTrack(2); //
pushed=1;delay(500);
}
if(page==3)
{
submenu=3;
counter=0;
mp3.playMp3FolderTrack(3); //
pushed=1;delay(500);
}
if(page==4)
{
submenu=4;
counter=0;
mp3.playMp3FolderTrack(4); //
pushed=1;delay(500);
}
}//end of submenu 0
}
//Add limit for the counter. Each line of the menu has 5 points. Since my menu has 4 lines the maximum counter will be from 0 to 20
//If you add more lines for the menu, increase this value
if(counter > 20)
{
counter=20;
}
if(counter < 0)
{
counter=0;
}
}//end void
//Interruption vector
ISR(PCINT0_vect){
clk_State = (PINB & B00000001); //pin 8 state, clock pin?
dt_State = (PINB & B00000010);
if (clk_State != Last_State){
// If the data state is different to the clock state, that means the encoder is rotating clockwise
if (dt_State != clk_State) {
counter ++;
}
else {
counter --;
}
}
Last_State = clk_State; // Updates the previous state of the data with the current state
}