/*
Rotary Encoder volume control example
Usage: rotate the knob to control the value,
click the knob to change between volume/bass/treble.
https://wokwi.com/arduino/projects/304919215794553409
Released under the MIT license.
Copyright (C) 2021, Uri Shaked.
*/
#include <LiquidCrystal_I2C.h>
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
uint8_t volume = 50;
uint8_t bass = 25;
uint8_t treble = 66;
uint8_t repeat = 5;
typedef enum {
SET_VOLUME,
SET_BASS,
SET_TREBLE,
SET_REPEATE,
} Mode;
Mode mode = SET_VOLUME;
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display
void nextMode() {
switch (mode) {
case SET_VOLUME:
mode = SET_BASS;
break;
case SET_BASS:
mode = SET_TREBLE;
break;
case SET_TREBLE:
mode = SET_REPEATE;
break;
case SET_REPEATE:
mode = SET_VOLUME;
break;
}
}
void updateValue(int delta) {
switch (mode) {
case SET_VOLUME:
volume = constrain(volume + delta, 0, 100);
break;
case SET_BASS:
bass = constrain(bass + delta, 0, 100);
break;
case SET_TREBLE:
treble = constrain(treble + delta, 0, 100);
break;
case SET_REPEATE:
repeat = constrain(repeat + delta, 0, 100);
break;
}
}
void updateDisplay() {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Move : ");
lcd.setCursor(7, 0);
lcd.print(volume);
if (mode == SET_VOLUME) {
lcd.setCursor(0, 0);
lcd.print(">");
}
lcd.setCursor(1, 1);
lcd.print("Down : ");
lcd.setCursor(7, 1);
lcd.print(bass);
if (mode == SET_BASS) {
lcd.setCursor(0, 1);
lcd.print(">");
}
lcd.setCursor(1, 2);
lcd.print("Speed: ");
lcd.setCursor(7, 2);
lcd.print(treble);
if (mode == SET_TREBLE) {
lcd.setCursor(0, 2);
lcd.print(">");
}
lcd.setCursor(1, 3);
lcd.print("Count: ");
lcd.setCursor(7, 3);
lcd.print(repeat);
if (mode == SET_REPEATE) {
lcd.setCursor(0, 3);
lcd.print(">");
}
}
void setup() {
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_SW, INPUT_PULLUP);
updateDisplay();
lcd.init(); // initialize the lcd
// Print a message to the LCD.
lcd.backlight();
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Move : ");
lcd.setCursor(7, 0);
lcd.print(volume);
if (mode == SET_VOLUME) {
lcd.setCursor(0, 0);
lcd.print(">");
}
lcd.setCursor(1, 1);
lcd.print("Down : ");
lcd.setCursor(7, 1);
lcd.print(bass);
if (mode == SET_BASS) {
lcd.setCursor(0, 1);
lcd.print(">");
}
lcd.setCursor(1, 2);
lcd.print("Speed: ");
lcd.setCursor(7, 2);
lcd.print(treble);
if (mode == SET_TREBLE) {
lcd.setCursor(0, 2);
lcd.print(">");
}
lcd.setCursor(1, 3);
lcd.print("Count: ");
lcd.setCursor(7, 3);
lcd.print(repeat);
if (mode == SET_REPEATE) {
lcd.setCursor(0, 3);
lcd.print(">");
}
}
long int modeLastChanged = 0;
int prevClk = HIGH;
void loop() {
if (digitalRead(ENCODER_SW) == LOW && millis() - modeLastChanged > 300) {
modeLastChanged = millis();
nextMode();
updateDisplay();
}
int clk = digitalRead(ENCODER_CLK);
if (clk != prevClk && clk == LOW) {
int dt = digitalRead(ENCODER_DT);
int delta = dt == HIGH ? 1 : -1; // increment count by 1 or decrement by -1
updateValue(delta);
updateDisplay();
}
prevClk = clk;
}