/*
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 <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//#include <Fonts/FreeSansBold9pt7b.h>
//#include <Fonts/Picopixel.h>
struct EncoderData {
int8_t E;
byte S;
byte So;
byte X;
};
EncoderData encoderData;
int8_t getEncoderTick(struct EncoderData &ed) {
return ed.E;
}
void encoder(struct EncoderData &ed) {
// PD 76543210
// S=3- PIND&B00000011 ; // Uso PD1 e PD0, perciò non devo scorrere a destra.
// S=3-( PIND>>3)&B00000011 ; // Uso PD4 e PD3, quindi scorro a destra di 3 bit per farli diventare 1 e 0.
// S=3-((PIND>>2)&B00000011); // Uso PD3 e PD2, quindi scorro a destra di 2 bit per farli diventare 1 e 0.
// S=3-((PINC>>1)&B00000011); // Uso PC2 e PC1 (A2 e A1), quindi scorro a destra di 1 bit per farli diventare 1 e 0.
ed.S = 3 - ((PIND >> 4)&B00000011); // Uso PD5 e PD4, quindi scorro a destra di 4 bit per farli diventare 1 e 0.
// Il valore binario di S rappresenta A e B. Il centrale dell'encoder è a massa, quindi faccio complemento a 3 (11).
ed.S ^= ed.S >> 1; // Faccio XOR (^) fra S (gray) e il suo bit 1, facendolo scorrere a Dx: AB XOR A,
// ottenendo un binario che per ogni scatto fa 0-1-2-3-0 oppure 0-3-2-1-0.
ed.E = 0;
if (ed.S != ed.So && ed.S == 0)
ed.X = 0;
if (ed.X == 0) {
if (ed.So == 1 && ed.S == 2) {
ed.E = 1;
ed.X = 1;
// Bip();
}
if (ed.So == 3 && ed.S == 2) {
ed.E = -1;
ed.X = 1;
// Bip();
}
if (ed.S == 0) {
ed.E = 0;
ed.X = 0;
}
ed.So = ed.S;
} // end if (X == 0)
}
//#define ENCODER_CLK 2
//#define ENCODER_DT 3
#define ENCODER_SW 6
uint8_t volume = 15;
uint8_t bass = 12;
uint8_t treble = 12;
uint32_t ms;
typedef enum {
SET_VOLUME,
SET_BASS,
SET_TREBLE
} Mode;
Mode mode = SET_VOLUME;
enum class MenuEQItem {
VOLUME,
BASS,
TREBLE
};
MenuEQItem menuEQItem = MenuEQItem::VOLUME;
int8_t ctrDelta;
Adafruit_SSD1306 display(128, 64, &Wire, -1, 400000, 40000);
#include "gfxwidget.h"
GfxBar volBar(10, 10, 50, 4);
//GfxBar volBar(GfxPoint(10, 12), 50, 4);
GfxBar bassBar(10, 30, 50, 4);
GfxBar trebleBar(10, 50, 50, 4);
void setup() {
Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
//pinMode(ENCODER_CLK, INPUT);
//pinMode(ENCODER_DT, INPUT);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
//pinMode(6, INPUT_PULLUP);
pinMode(ENCODER_SW, INPUT_PULLUP);
display.clearDisplay();
volBar.setMap(0, 32);
volBar.draw();
volBar.setVal(volume);
bassBar.setMap(0, 24);
bassBar.draw();
bassBar.setVal(bass);
trebleBar.setMap(0, 24);
trebleBar.draw();
trebleBar.setVal(treble);
display.setFont();
display.setTextColor(WHITE);
display.setCursor(11, 2);
display.print("*");
display.setCursor(24, 2);
display.print("Vol");
display.setCursor(22, 22);
display.print("Bass");
display.setCursor(19, 42);
display.print("Treble");
display.display();
}
uint32_t modeLastChanged = 0;
void clearPrint(const char *s, int16_t cx, int16_t cy, int16_t wx, int16_t wy) {
display.setTextColor(BLACK);
display.setCursor(cx, cy);
display.print(s);
display.setTextColor(WHITE);
display.setCursor(wx, wy);
display.print(s);
}
void nextMode() {
switch (mode) {
case SET_VOLUME:
mode = SET_BASS;
clearPrint("*", 11, 2, 11, 22);
break;
case SET_BASS:
mode = SET_TREBLE;
clearPrint("*", 11, 22, 11, 42);
break;
case SET_TREBLE:
mode = SET_VOLUME;
clearPrint("*", 11, 42, 11, 2);
break;
}
}
void updateSettings(int8_t delta) {
switch (mode) {
case SET_VOLUME:
volBar.setBar(volBar.getCount() + delta);
volume = volBar.getVal();
Serial.println(volume);
break;
case SET_BASS:
bassBar.setBar(bassBar.getCount() + delta);
bass = bassBar.getVal();
Serial.println(bass);
break;
case SET_TREBLE:
trebleBar.setBar(trebleBar.getCount() + delta);
treble = trebleBar.getVal();
Serial.println(treble);
break;
}
//ms = millis();
display.display();
//Serial.println(millis() - ms);
}
void loop() {
if (digitalRead(ENCODER_SW) == LOW && millis() - modeLastChanged > 100) {
modeLastChanged = millis();
nextMode();
display.display();
}
encoder(encoderData);
int8_t e = getEncoderTick(encoderData);
if (e != 0) {
int8_t delta = e == HIGH ? 5 : -5;
updateSettings(delta);
}
}
ERC Warnings
flop3:CLK: Clock driven by combinatorial logic
flop1:CLK: Clock driven by combinatorial logic