Hi,
The rotary encoder only works for fix pin:
const int RotaryCLK = 2; //CLK pin on the rotary encoder
const int RotaryDT = 3; //DT pin on the rotary encoder WAS 4
const int RotarySW = 4; //
why?
Thanks
Adam
/* https://curiousscientist.tech/blog/arduino-menu-navigation-rotary-encoder
REF: http://educ8s.tv/arduino-rotary-encoder-menu/#google_vignette
https://www.youtube.com/watch?v=ak5TsUFhyf8&t=4s
Nokia5110MenuRotary
https://curiousscientist.tech/blog/arduino-menu-navigation-rotary-encoder
A_EN_OLED_MENU_O
20210807 TESTED GOOD for pick letter by Rotary Encoder reading.
Vm2 tested good at menu selecte and Vm2.1 will mdf the menu navigation and let it to do actions.
the Sub void [ButtonChecker()] made sketch modular is better. but here will merge the many actions into [void rotate()]
added Tabs of [PWM] & [POT] to test for MEGA.
20210808: functionly tested good, but the OLED cursor not stable
https://www.jianshu.com/p/29b24e443b88
const uint8_t pinA;
const uint8_t pinB;
const uint8_t pinBTN;
const bool pinsActive;
volatile int16_t delta;
volatile int16_t last;
20210808: USE 5 letter add click here
20210810 tested that as long as [COMPONENTS] added, the ERROR : Error compiling for board Arduino Mega or Mega 2560. OUT !!!!!!!!!!!!!
20210811: COMPILLING PASSED AND UPLODED BUT THE [components] select not good.
this code only work when:
const int RotaryCLK = 2; //CLK pin on the rotary encoder
const int RotaryDT = 3; //DT pin on the rotary encoder WAS 4
const int RotarySW = 4; // WAS 3 SW pin on the rotary encoder (Button function)
why????
*/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <ClickEncoder.h>
///// #include <TimerOne.h>
#include "config.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO: A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
///// Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#include <ClickEncoder.h>
//Defining pins for rotary encoder
const int RotaryCLK = 2; //CLK pin on the rotary encoder
const int RotaryDT = 3; //DT pin on the rotary encoder WAS 4
const int RotarySW = 4; // WAS 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;
//------------------------------
int x0 = 4; //// the menu items location Line-1
int y0 = 0;
int x1 = 4; //// the menu items location Line-2
int y1 = 10;
int x2 = 4; //// the menu items location Line-3
int y2 = 20;
int h0 = 0; //// the Cursor location Line-1
int v0 = 0;
int h1 = 12; //// the Cursor location Line-2 and Line-3
int v1 = 8;
#define maxItemSize 24
char menuT[][maxItemSize] = {"V", "I", "T", "W", "B", "Q", "N", "X", "P", "O", "S", "U", "C", "L", "M" , "H", "D", "J", "K", "U", "R", "F", "G" , "A"};
// Only 2 sub-menus are shown. You can add as many as you wish.
///// char subMenu0[][maxItemSize] = {"AC", "DC"};
char subMenu1[][maxItemSize] = {"AC-DC-ma-la"};
char subMenu2[][maxItemSize] = {"CURRENT-DC-AC", "other"};
char subMenu3[][maxItemSize] = {"transist-MOSFET-IGBT", "other"};
char subMenu4[][maxItemSize] = {"TEMP-HUMI"};
char subMenu5[][maxItemSize] = {"body temperature ", "other"};
char subMenu6[][maxItemSize] = {"BATTERY", "other"};
char subMenu7[][maxItemSize] = {"QQQQ"};
char subMenu8[][maxItemSize] = {"NNNN", "other"};
char subMenu9[][maxItemSize] = {"XXXX", "other"};
char subMenu10[][maxItemSize] = {"PPPP"};
char subMenu11[][maxItemSize] = {"transist-MOSFET-IGBT", "other"};
char subMenu12[][maxItemSize] = {"diode-capa-R", "other"};
char subMenu13[][maxItemSize] = {"AC-DC-ma-la"};
char subMenu14[][maxItemSize] = {"transist-MOSFET-IGBT", "other"};
char subMenu15[][maxItemSize] = {"diode-capa-R", "other"};
char subMenu16[][maxItemSize] = {"AC-DC-ma-la"};
char subMenu17[][maxItemSize] = {"transist-MOSFET-IGBT", "other"};
char subMenu18[][maxItemSize] = {"diode-capa-R", "other"};
char subMenu19[][maxItemSize] = {"AC-DC-ma-la"};
char subMenu20[][maxItemSize] = {"transist-MOSFET-IGBT", "other"};
char subMenu21[][maxItemSize] = {"diode-capa-R", "other"};
char subMenu22[][maxItemSize] = {"AC-DC-ma-la"};
char subMenu23[][maxItemSize] = {"diode-capa-R", "other"};
char subMenu24[][maxItemSize] = {"AC-DC-ma-la"};
///// char subMenu3[][maxItemSize] = {"Temp", "Humi"};
int cnt = 0;
int itemSelected, subMenuSelected;
int itemsToDisplay = 0;
unsigned long startmillis, milliSecs, mins, secs, hour;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile uint16_t encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile uint16_t
oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent
const int itemsPerScreen = 7;
const int fontSize = 8;
boolean up = false;
boolean down = false;
boolean middle = false;
ClickEncoder *encoder;
int16_t last, value;
int buttonPin = 4;
boolean lastButton = HIGH;
boolean currentButton = HIGH;
byte enc_clk, enc_clk_old;
byte enc_switch, enc_switch_old;
int rotary_value;
boolean current = digitalRead(RotarySW); //// WAS: buttonPin
int show = 0;
void setup()
{
Serial.begin(9600); //we don't use the serial in this example
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
///// display.clearDisplay();
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println("ADAM-DIY!");
display.display();
menu();
delay(200); //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); ////// merge: enc_clk_old = digitalRead(ENC_CLK_PIN);
DTPrevious = digitalRead(RotaryDT);
enc_switch_old = digitalRead(RotarySW);
enc_switch = digitalRead(RotarySW);
attachInterrupt(digitalPinToInterrupt(RotaryCLK), rotate, CHANGE);
attachInterrupt(digitalPinToInterrupt(RotarySW), buttonPressed, FALLING); //either falling or rising but never "change".
Serial.print("RotaryCLK0=");
Serial.println(RotaryCLK);
TimeNow1 = millis(); //Start timer 1
POT_setup();
PWM_setup();
///// GAME_setup();
pinMode(buttonPin, INPUT_PULLUP);
componentsS_setup();
}
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++;
Serial.print("RotaryCLK1=");
Serial.println(RotateCounter);
if (RotateCounter > 24)
{
RotateCounter = 0;
}
}
else
{
RotateCounter--;
Serial.print("RotaryCLK2=");
Serial.println(RotateCounter);
if (RotateCounter < 0)
{
RotateCounter = 24;
}
}
}
CLKPrevious = CLKNow; // Store last CLK state
rotated = true;
Serial.print("RotaryCLK3=");
Serial.println(RotateCounter);
}
void printLCD() ///// for display only the menu and flashing the selected item, move all action to: void ButtonChecker() by action after button pressed
{
if (rotated == true) //refresh the CLK
{
display.clearDisplay();
if (RotateCounter == 1)
{
menu();
int var = 0;
while (RotateCounter == 1) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu1);
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
ACDC_loop();
}
}
}
if (RotateCounter == 2)
{
menu();
int var = 0;
while (RotateCounter == 2) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu2); ///// this shown the content in the [subMenu2], but not the all, why? ///// display.println("subMenu2"); //// works but just shown 'subMenu2', not the content in the [subMenu2]
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
///// CURRENT_loop();
}
}
}
if (RotateCounter == 3)
{
menu();
int var = 0;
while (RotateCounter == 3) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu3);
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
componentsV_loop();
}
}
}
if (RotateCounter == 4)
{
menu();
int var = 0;
while (RotateCounter == 4) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu4);
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
///// TandH_loop();
}
}
}
if (RotateCounter == 5)
{
menu();
int var = 0;
while (RotateCounter == 5) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu5);
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
///// componentsV_loop();
}
}
}
if (RotateCounter == 6)
{
menu();
int var = 0;
while (RotateCounter == 6) {
// do something repetitive 200 times
flashing8();
var++;
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(4, 33);
display.print(*subMenu6);
display.display();
enc_switch = digitalRead(RotarySW);
if ((enc_switch_old == 1) && (enc_switch == 0)) //// this works well!!!!!!!!!!!!
{
///// componentsV_loop();
}
}
}
if (RotateCounter == 7)
{
menu();
int var = 0;
while (RotateCounter == 7) {
// do something repetitive 200 times
flashing8();
var++;
}
}
if (RotateCounter == 8)
{
menu();
int var = 0;
while (RotateCounter == 8) {
// do something repetitive 200 times
flashing8();
var++;
}
}
if (RotateCounter == 9)
{
menu();
int var = 0;
while (RotateCounter == 9) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 10)
{
menu();
int var = 0;
while (RotateCounter == 10) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 11)
{
menu();
int var = 0;
while (RotateCounter == 11) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 12)
{
menu();
int var = 0;
while (RotateCounter == 12) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 13)
{
menu();
int var = 0;
while (RotateCounter == 13) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 14)
{
menu();
int var = 0;
while (RotateCounter == 14) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 15)
{
menu();
int var = 0;
while (RotateCounter == 15) {
// do something repetitive 200 times
flashing16();
var++;
}
}
if (RotateCounter == 16)
{
menu();
int var = 0;
while (RotateCounter == 16) {
// do something repetitive 200 times
flashing16();
var++;
}
}
///////////////////////////////////////////////////////////////////////
if (RotateCounter == 17)
{
menu();
int var = 0;
while (RotateCounter == 17) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 18)
{
menu();
int var = 0;
while (RotateCounter == 18) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 19)
{
menu();
int var = 0;
while (RotateCounter == 19) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 20)
{
menu();
int var = 0;
while (RotateCounter == 20) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 21)
{
menu();
int var = 0;
while (RotateCounter == 21) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 22)
{
menu();
int var = 0;
while (RotateCounter == 22) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 23)
{
menu();
int var = 0;
while (RotateCounter == 23) {
// do something repetitive 200 times
flashing24();
var++;
}
}
if (RotateCounter == 24)
{
menu();
int var = 0;
while (RotateCounter == 24) {
// do something repetitive 200 times
flashing24();
var++;
}
}
}
rotated = false;
}
void menu()
{
display.clearDisplay();
display.setCursor(4, 0); //Defining position to write from first row, first column .
display.print("V I T W B T N X");
display.setCursor(4, 10); //Defining position to write from first row, first column .
display.print("P O S U C L M N ");
display.setCursor(4, 20); //second line, 1st block
display.print("D S L Q R F G K"); //You can write 16 Characters per line .
///// display menuitem's expaintion.
///// display.setCursor(4, 30); //second line, 1st block
///// display.print("menuitem ex...."); //You can write 16 Characters per line .
display.setCursor(4, 56); //second line, 1st block
display.print("ENCODER: "); //You can write 16 Characters per line .
display.setCursor(56, 56); //second line, 1st block
display.print(RotateCounter); //You can write 16 Characters per line .
display.display();
}
void flashing8()
{
if (RotateCounter <= 8)
{
display.setCursor(x0, y0);
display.drawRect((RotateCounter - 1)*h1, y0, h1, v1, BLACK);
display.display();
display.setCursor(x0, y0);
display.drawRect((RotateCounter - 1)*h1, y0, h1, v1, WHITE);
display.display();
display.setCursor(x0, y0);
display.drawRect((RotateCounter - 1)*h1, y0, h1, v1, BLACK);
display.display();
}
}
void flashingTESTKEY() ///// TESTKEY Flashing
{
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(x0, 0);
display.println("ADAM-DIY");
display.setTextSize(2);
display.setCursor(x0, 15);
display.println("TESTER");
display.setTextColor(WHITE);
display.setCursor(4, 35 );
display.println("waite for");
display.setTextColor(WHITE);
display.setCursor(65, 35 );
display.println("TESTKEY");
display.display();
for (int i = 0; i <= 50; i++)
{
display.setTextColor(BLACK);
display.setCursor(65, 35 );
display.println("TESTKEY");
display.display();
display.setTextColor(WHITE);
display.setCursor(65, 35 );
display.println("TESTKEY");
display.display();
display.setTextColor(BLACK);
display.setCursor(65, 35 );
display.println("TESTKEY");
display.display();
}
}
void flashing16()
{
if (RotateCounter > 8 && RotateCounter <= 16)
{
display.setCursor(x1, y1);
display.drawRect((RotateCounter - 9)*h1, y1, h1, v1, BLACK);
display.display();
display.setCursor(x1, y1);
display.drawRect((RotateCounter - 9)*h1, y1, h1, v1, WHITE);
display.display();
display.setCursor(x1, y1);
display.drawRect((RotateCounter - 9)*h1, y1, h1, v1, BLACK);
display.display();
}
}
void flashing24()
{
if (RotateCounter > 16 && RotateCounter <= 24)
{
display.setCursor(x2, y2);
display.drawRect((RotateCounter - 17)*h1, y2, h1, v1, BLACK);
display.display();
display.setCursor(x2, y2);
display.drawRect((RotateCounter - 17)*h1, y2, h1, v1, WHITE);
display.display();
display.setCursor(x2, y2);
display.drawRect((RotateCounter - 17)*h1, y2, h1, v1, BLACK);
display.display();
}
}
boolean debounce(boolean last)
{
boolean current = digitalRead(RotarySW); //// WAS: buttonPin
if (last != current)
{
delay(5);
current = digitalRead(RotarySW);
}
return current;
}
/*
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
}
display.setCursor(0, 1); // Defining positon to write from second row, first column .
display.print(whiteLEDStatus);
break;
case 1:
if (blueLEDStatus == false)
{
blueLEDStatus = true;
digitalWrite(blueLED, HIGH);
GAME_loop();
}
else
{
blueLEDStatus = false;
digitalWrite(blueLED, LOW);
GAME_loop();
}
display.setCursor(2, 1); // Defining positon to write from second row, first column .
display.print(blueLEDStatus);
break;
case 2:
if (greenLEDStatus == false)
{
greenLEDStatus = true;
digitalWrite(greenLED, HIGH);
}
else
{
greenLEDStatus = false;
digitalWrite(greenLED, LOW);
}
display.setCursor(4, 1); // Defining positon to write from second row, first column .
display.print(greenLEDStatus);
break;
case 3:
if (yellowLEDStatus == false)
{
yellowLEDStatus = true;
digitalWrite(yellowLED, HIGH);
///// GAME_loop();
}
else
{
yellowLEDStatus = false;
digitalWrite(yellowLED, LOW);
}
display.setCursor(6, 1); // Defining positon to write from second row, first column .
display.print(yellowLEDStatus);
break;
case 4:
if (redLEDStatus == false)
{
redLEDStatus = true;
digitalWrite(redLED, HIGH);
}
else
{
redLEDStatus = false;
digitalWrite(redLED, LOW);
}
display.setCursor(8, 1); // Defining positon to write from second row, first column .
display.print(redLEDStatus);
break;
display.setCursor(8, 1); // Defining positon to write from second row, first column .
display.print(redLEDStatus);
break;
}
}
ButtonPressed = false; //reset this variable
}
*/
void displayMenuItem(String item, int position, boolean selected)
{
if (selected)
{
display.setTextColor(WHITE, BLACK);
} else
{
display.setTextColor(BLACK, WHITE);
}
display.setCursor(0, position);
display.print(">" + item);
}
int displayMenu(char menuInput[][maxItemSize], int menuLength) {
int curPos, startPos, endPos;
do {
startPos = encoderPos % menuLength;
Serial.println("startPos:");
Serial.println(startPos);
display.clearDisplay();
endPos = itemsPerScreen;
if (menuLength < itemsPerScreen)
{
endPos = menuLength - startPos;
}
if ((menuLength - startPos) < itemsPerScreen)
{
endPos = menuLength - startPos;
}
Serial.print("endPos:");
Serial.println(endPos);
for (cnt = 0; cnt <= (endPos - 1); cnt++) {
if (cnt == 0)
{
display.setCursor(0, 0);
display.print("->");
}
display.setCursor(16, cnt * fontSize);
display.println(menuInput[cnt + startPos]);
Serial.println(menuInput[cnt + startPos]);
}
display.display();
cnt = 0;
if (oldEncPos != encoderPos) {
oldEncPos = encoderPos;
}
} while (digitalRead(RotarySW));
while (digitalRead(RotarySW) == 0); //wait till switch is reseleased
return startPos;
}
void readRotaryEncoder()
{
value += encoder->getValue();
if (value / 2 > last) {
last = value / 2;
down = true;
delay(150);
} else if (value / 2 < last) {
last = value / 2;
up = true;
delay(150);
}
}
void timerIsr() {
encoder->service();
}