I've been searching for a way to build arduino menus
They are a common feature in many synths.
A huge thank you to Curious Scientist for this navigation menu post
Hopefully, I'll be able to incorporate some of these ideas into future projects.
I didn't have a KY-040 rotary encoder on hand so had to make do with a "naked one"
The KY-040 has a breakout board which adds a Vcc pin
The virgin encoder doesn't have this.
It has 5 pins:
1. CLK - Clock (Out B)
2. DT - data (Out A)
3. SW - switch (when we press the shaft, the switch connects to GND. Otherwise it is floating.)
4. GND
5. GND
They still have 5 pins.
Here there are two GNDs
There is no Vcc
// o CLK (out B) --> Pin 2
// o DT (Out A) --> Pin 4
// o SW --> Pin 3
// o GND both --> GND on arduino/breadboard
I used tinkercad to make the wiring diagram
LEDs
short legs - cathode to gnd (connects to 220 ohm resistors )
Anode - to digital pins
Normally, I connect the anode to the digital pins via resistors, and
the cathode goes in straight to gnd, however this other way seems to work fine too.
ground it well.
// *********************************************
//16x2 LCD
#include <LiquidCrystal_I2C.h> //SDA = A4, SCL = A5
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//Defining pins for rotary encoder
const int RotaryCLK = 2; //CLK pin on the rotary encoder
const int RotaryDT = 4; //DT pin on the rotary encoder
const int RotarySW = 3; //SW pin on the rotary encoder (Button function)
//Defining variables for rotary encoder and button
int ButtonCounter = 0; //counts the button clicks
int RotateCounter = 0; //counts the rotation clicks
bool rotated = true; //info of the rotation
bool ButtonPressed = false; //info of the button
//Statuses
int CLKNow;
int CLKPrevious;
int DTNow;
int DTPrevious;
// Timers
float TimeNow1;
float TimeNow2;
//LED things
//digital pins
const int whiteLED = 8;
const int blueLED = 9;
const int greenLED = 10;
const int yellowLED = 11;
const int redLED = 12;
//statuses (1/true: ON, 0/false: OFF)
bool whiteLEDStatus = false;
bool blueLEDStatus = false;
bool greenLEDStatus = false;
bool yellowLEDStatus = false;
bool redLEDStatus = false;
//------------------------------
//Drawing of the LCD layout
//W B G Y R CLK
//0 0 0 0 0 1
void setup()
{
//Serial.begin(9600); //we don't use the serial in this example
//------------------------------------------------------
lcd.begin(16,2); // initialize the lcd
lcd.backlight();
//------------------------------------------------------
lcd.setCursor(0,0); //Defining position to write from first row, first column .
lcd.print("W B G Y R CLK");
lcd.setCursor(0,1); //second line, 1st block
lcd.print("0 0 0 0 0 0"); //You can write 16 Characters per line .
delay(3000); //wait 3 sec
//------------------------------------------------------
//setting up pins
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(whiteLED, OUTPUT); //white LED
pinMode(blueLED, OUTPUT); //blue LED
pinMode(greenLED, OUTPUT); //green LED
pinMode(yellowLED, OUTPUT); //yellow LED
pinMode(redLED, OUTPUT); //red LED
//LOW pins = LEDs are off. (LED + is connected to the digital pin)
digitalWrite(whiteLED, LOW);
digitalWrite(blueLED, LOW);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
//Store states
CLKPrevious = digitalRead(RotaryCLK);
DTPrevious = digitalRead(RotaryDT);
attachInterrupt(digitalPinToInterrupt(RotaryCLK), rotate, CHANGE);
attachInterrupt(digitalPinToInterrupt(RotarySW), buttonPressed, FALLING); //either falling or rising but never "change".
TimeNow1 = millis(); //Start timer 1
}
void loop()
{
printLCD();
ButtonChecker();
}
void buttonPressed()
{
//This timer is a "software debounce". It is not the most effective solution, but it works
TimeNow2 = millis();
if(TimeNow2 - TimeNow1 > 500)
{
ButtonPressed = true;
}
TimeNow1 = millis(); //"reset" timer; the next 500 ms is counted from this moment
}
void rotate()
{
CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
// If last and current state of CLK are different, then a pulse occurred
if (CLKNow != CLKPrevious && CLKNow == 1)
{
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so increase
if (digitalRead(RotaryDT) != CLKNow)
{
RotateCounter++;
if(RotateCounter > 4)
{
RotateCounter = 0;
}
}
else
{
RotateCounter--;
if(RotateCounter < 0)
{
RotateCounter = 4;
}
}
}
CLKPrevious = CLKNow; // Store last CLK state
rotated = true;
}
void printLCD()
{
if(rotated == true) //refresh the CLK
{
lcd.setCursor(12,1);
lcd.print(RotateCounter);
rotated = false;
}
}
void ButtonChecker() //this is basically the menu part. keep track of the buttonpressed and rotatecounter for navigation
{
if(ButtonPressed == true)
{
switch(RotateCounter)
{
case 0:
if(whiteLEDStatus == false)
{
whiteLEDStatus = true;
digitalWrite(whiteLED, HIGH); //white LED is turned ON
}
else
{
whiteLEDStatus = false;
digitalWrite(whiteLED, LOW); //white LED is turned OFF
}
lcd.setCursor(0,1); // Defining positon to write from second row, first column .
lcd.print(whiteLEDStatus);
break;
case 1:
if(blueLEDStatus == false)
{
blueLEDStatus = true;
digitalWrite(blueLED, HIGH);
}
else
{
blueLEDStatus = false;
digitalWrite(blueLED, LOW);
}
lcd.setCursor(2,1); // Defining positon to write from second row, first column .
lcd.print(blueLEDStatus);
break;
case 2:
if(greenLEDStatus == false)
{
greenLEDStatus = true;
digitalWrite(greenLED, HIGH);
}
else
{
greenLEDStatus = false;
digitalWrite(greenLED, LOW);
}
lcd.setCursor(4,1); // Defining positon to write from second row, first column .
lcd.print(greenLEDStatus);
break;
case 3:
if(yellowLEDStatus == false)
{
yellowLEDStatus = true;
digitalWrite(yellowLED, HIGH);
}
else
{
yellowLEDStatus = false;
digitalWrite(yellowLED, LOW);
}
lcd.setCursor(6,1); // Defining positon to write from second row, first column .
lcd.print(yellowLEDStatus);
break;
case 4:
if(redLEDStatus == false)
{
redLEDStatus = true;
digitalWrite(redLED, HIGH);
}
else
{
redLEDStatus = false;
digitalWrite(redLED, LOW);
}
lcd.setCursor(8,1); // Defining positon to write from second row, first column .
lcd.print(redLEDStatus);
break;
}
}
ButtonPressed = false; //reset this variable
}
#include <LiquidCrystal_I2C.h> //SDA = A4, SCL = A5
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
//Defining pins for rotary encoder
const int RotaryCLK = 2; //CLK pin on the rotary encoder
const int RotaryDT = 4; //DT pin on the rotary encoder
const int RotarySW = 3; //SW pin on the rotary encoder (Button function)
//Defining variables for rotary encoder and button
int ButtonCounter = 0; //counts the button clicks
int RotateCounter = 0; //counts the rotation clicks
bool rotated = true; //info of the rotation
bool ButtonPressed = false; //info of the button
//Statuses
int CLKNow;
int CLKPrevious;
int DTNow;
int DTPrevious;
// Timers
float TimeNow1;
float TimeNow2;
//LED things
//digital pins
const int whiteLED = 8;
const int blueLED = 9;
const int greenLED = 10;
const int yellowLED = 11;
const int redLED = 12;
//statuses (1/true: ON, 0/false: OFF)
bool whiteLEDStatus = false;
bool blueLEDStatus = false;
bool greenLEDStatus = false;
bool yellowLEDStatus = false;
bool redLEDStatus = false;
//------------------------------
//Drawing of the LCD layout
//W B G Y R CLK
//0 0 0 0 0 1
void setup()
{
//Serial.begin(9600); //we don't use the serial in this example
//------------------------------------------------------
lcd.begin(16,2); // initialize the lcd
lcd.backlight();
//------------------------------------------------------
lcd.setCursor(0,0); //Defining position to write from first row, first column .
lcd.print("W B G Y R CLK");
lcd.setCursor(0,1); //second line, 1st block
lcd.print("0 0 0 0 0 0"); //You can write 16 Characters per line .
delay(3000); //wait 3 sec
//------------------------------------------------------
//setting up pins
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(whiteLED, OUTPUT); //white LED
pinMode(blueLED, OUTPUT); //blue LED
pinMode(greenLED, OUTPUT); //green LED
pinMode(yellowLED, OUTPUT); //yellow LED
pinMode(redLED, OUTPUT); //red LED
//LOW pins = LEDs are off. (LED + is connected to the digital pin)
digitalWrite(whiteLED, LOW);
digitalWrite(blueLED, LOW);
digitalWrite(greenLED, LOW);
digitalWrite(yellowLED, LOW);
digitalWrite(redLED, LOW);
//Store states
CLKPrevious = digitalRead(RotaryCLK);
DTPrevious = digitalRead(RotaryDT);
attachInterrupt(digitalPinToInterrupt(RotaryCLK), rotate, CHANGE);
attachInterrupt(digitalPinToInterrupt(RotarySW), buttonPressed, FALLING); //either falling or rising but never "change".
TimeNow1 = millis(); //Start timer 1
}
void loop()
{
printLCD();
ButtonChecker();
}
void buttonPressed()
{
//This timer is a "software debounce". It is not the most effective solution, but it works
TimeNow2 = millis();
if(TimeNow2 - TimeNow1 > 500)
{
ButtonPressed = true;
}
TimeNow1 = millis(); //"reset" timer; the next 500 ms is counted from this moment
}
void rotate()
{
CLKNow = digitalRead(RotaryCLK); //Read the state of the CLK pin
// If last and current state of CLK are different, then a pulse occurred
if (CLKNow != CLKPrevious && CLKNow == 1)
{
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so increase
if (digitalRead(RotaryDT) != CLKNow)
{
RotateCounter++;
if(RotateCounter > 4)
{
RotateCounter = 0;
}
}
else
{
RotateCounter--;
if(RotateCounter < 0)
{
RotateCounter = 4;
}
}
}
CLKPrevious = CLKNow; // Store last CLK state
rotated = true;
}
void printLCD()
{
if(rotated == true) //refresh the CLK
{
lcd.setCursor(12,1);
lcd.print(RotateCounter);
rotated = false;
}
}
void ButtonChecker() //this is basically the menu part. keep track of the buttonpressed and rotatecounter for navigation
{
if(ButtonPressed == true)
{
switch(RotateCounter)
{
case 0:
if(whiteLEDStatus == false)
{
whiteLEDStatus = true;
digitalWrite(whiteLED, HIGH); //white LED is turned ON
}
else
{
whiteLEDStatus = false;
digitalWrite(whiteLED, LOW); //white LED is turned OFF
}
lcd.setCursor(0,1); // Defining positon to write from second row, first column .
lcd.print(whiteLEDStatus);
break;
case 1:
if(blueLEDStatus == false)
{
blueLEDStatus = true;
digitalWrite(blueLED, HIGH);
}
else
{
blueLEDStatus = false;
digitalWrite(blueLED, LOW);
}
lcd.setCursor(2,1); // Defining positon to write from second row, first column .
lcd.print(blueLEDStatus);
break;
case 2:
if(greenLEDStatus == false)
{
greenLEDStatus = true;
digitalWrite(greenLED, HIGH);
}
else
{
greenLEDStatus = false;
digitalWrite(greenLED, LOW);
}
lcd.setCursor(4,1); // Defining positon to write from second row, first column .
lcd.print(greenLEDStatus);
break;
case 3:
if(yellowLEDStatus == false)
{
yellowLEDStatus = true;
digitalWrite(yellowLED, HIGH);
}
else
{
yellowLEDStatus = false;
digitalWrite(yellowLED, LOW);
}
lcd.setCursor(6,1); // Defining positon to write from second row, first column .
lcd.print(yellowLEDStatus);
break;
case 4:
if(redLEDStatus == false)
{
redLEDStatus = true;
digitalWrite(redLED, HIGH);
}
else
{
redLEDStatus = false;
digitalWrite(redLED, LOW);
}
lcd.setCursor(8,1); // Defining positon to write from second row, first column .
lcd.print(redLEDStatus);
break;
}
}
ButtonPressed = false; //reset this variable
}
//******************************
Links
+https://www.youtube.com/watch?v=Q58mQFwWv7c
https://www.youtube.com/watch?v=CnS0PuDJybA
+ https://www.youtube.com/watch?v=x2J4VAYQGh0
No comments:
Post a Comment