Merge pull request #3 from KevinMidboe/feat/rotary-encoder

Feat/rotary encoder
This commit is contained in:
2020-08-13 22:30:34 +02:00
committed by GitHub
5 changed files with 149 additions and 63 deletions

View File

@@ -14,8 +14,7 @@ From here search for `Adafruit SSD1306`, this should prompt to also download `Ad
## Hardware ## Hardware
- OLED screen: Displays the current number of repetitions. - OLED screen: Displays the current number of repetitions.
- Potentiometer: Setting value to display. - Rotary encoder: Count steps in both directions and has a button used to change modes.
- Button: Change from repetition view mode to a menu view using `digitalPinToInterrupt`.
## Software ## Software
- Timeout: Any pot input has 1 second of timeout since last value change. After timeout runs out the value locks and a value of ± 2 must be read to enable inputs and reset the cooldown. - Timeout: Any pot input has 1 second of timeout since last value change. After timeout runs out the value locks and a value of ± 2 must be read to enable inputs and reset the cooldown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1,72 @@
// Rotary Encoder Inputs
#define CLK 2
#define DT 3
#define SW 4
int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;
void setup() {
// Set encoder pins as inputs
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
// Setup Serial Monitor
Serial.begin(9600);
// Read the initial state of CLK
lastStateCLK = digitalRead(CLK);
}
void loop() {
// Read the current state of CLK
currentStateCLK = digitalRead(CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir ="CCW";
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir ="CW";
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
// Remember last CLK state
lastStateCLK = currentStateCLK;
// Read the button state
int btnState = digitalRead(SW);
//If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
Serial.println("Button pressed!");
}
// Remember last button press event
lastButtonPress = millis();
}
// Put in a slight delay to help debounce the reading
delay(1);
}

View File

@@ -30,19 +30,25 @@
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example #define CLK 2
#define DT 3
#define SW 4
// input pin definition int counter = 0;
int buttonModePin = 2; int currentStateCLK;
int potPin = 2; int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;
bool mode = false;
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
// Setup button interrupt for changing modes // Set encoder pins as inputs
pinMode(buttonModePin, INPUT_PULLUP); pinMode(CLK,INPUT);
attachInterrupt(digitalPinToInterrupt(2), changeMode, FALLING); pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
@@ -50,6 +56,9 @@ void setup() {
for(;;); // Don't proceed, loop forever for(;;); // Don't proceed, loop forever
} }
// Read the initial state of CLK
lastStateCLK = digitalRead(CLK);
// Clear the buffer // Clear the buffer
display.clearDisplay(); display.clearDisplay();
display.setTextColor(SSD1306_WHITE); display.setTextColor(SSD1306_WHITE);
@@ -70,6 +79,34 @@ void displayFromSerialInput() {
} }
} }
boolean readEncoderAndUpdateCounter() {
currentStateCLK = digitalRead(CLK);
// If last and current state of CLK are different, then pulse occurred
// React to only 1 state change to avoid double count
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// If the DT state is different than the CLK state then
// the encoder is rotating CCW so decrement
if (digitalRead(DT) != currentStateCLK) {
counter --;
currentDir ="CCW";
} else {
// Encoder is rotating CW so increment
counter ++;
currentDir ="CW";
}
lastStateCLK = currentStateCLK;
return true;
}
lastStateCLK = currentStateCLK;
return false;
}
void drawHeader(String textToDisplay) { void drawHeader(String textToDisplay) {
display.setTextSize(1); display.setTextSize(1);
display.setCursor(2,0); display.setCursor(2,0);
@@ -83,68 +120,44 @@ void drawText(String textToDisplay) {
} }
void drawPushups(int count) { void drawPushups(int count) {
Serial.print("refreshing display w/ value: ");
Serial.println(count);
display.clearDisplay(); display.clearDisplay();
drawHeader("Daily push-ups:"); drawHeader("Daily push-ups:");
drawText(String(count)); drawText(String(count));
display.display(); display.display();
} }
int positionBuffer = 10;
int getPotValue() {
return analogRead(potPin) / positionBuffer;
}
void checkButtonState() {
int btnState = digitalRead(SW);
bool mode = false; //If we detect LOW signal, button is pressed
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
Serial.println("Button pressed!");
mode = !mode;
int pos = 0; if (mode == false) {
int currentPos; drawPushups(counter);
bool active; } else {
displayMenu();
unsigned long lastEvent = 0; }
unsigned long currentTime;
const long timeout = 1000;
void displayNumberWithPotValue() {
currentPos = getPotValue();
if (currentPos < pos - 2 || currentPos > pos + 2) {
active = true;
} }
while (active && mode == false) { // Remember last button press event
currentTime = millis(); lastButtonPress = millis();
if (currentTime - lastEvent > timeout) {
active = false;
}
currentPos = getPotValue();
if (currentPos != pos) {
lastEvent = currentTime;
pos = currentPos;
drawPushups(pos);
}
delay(10);
} }
} }
String menuLookup[4] = { "daily", "weekly", "goal" }; String menuLookup[4] = { "daily", "weekly", "goal" };
void displayMenu() {
void displayMenuSelect() {
currentPos = analogRead(potPin) / 257; // split in four (1028/4)
if (pos == currentPos) {
return;
}
pos = currentPos;
display.clearDisplay(); display.clearDisplay();
display.setTextSize(1); display.setTextSize(1);
display.setCursor(0,0); display.setCursor(0,0);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (pos == i) { if (counter == i) {
display.print("- "); display.print("- ");
} else { } else {
display.print(" "); display.print(" ");
@@ -154,26 +167,28 @@ void displayMenuSelect() {
display.display(); display.display();
} }
bool beingPressed = false; void displayCounterValue() {
void changeMode() { if (readEncoderAndUpdateCounter()) {
if (beingPressed == true) { drawPushups(counter);
return;
} }
Serial.println("CHANGING MODE"); delay(1);
}
beingPressed = true; int menuPos = 0;
mode = !mode; void displayMenuSelect() {
delay(800); if (readEncoderAndUpdateCounter()) {
beingPressed = false; displayMenu();
}
delay(1);
} }
void loop() { void loop() {
// displayFromSerialInput(); // displayFromSerialInput();
if (mode == false) { if (mode == false) {
displayNumberWithPotValue(); displayCounterValue();
} else { } else {
displayMenuSelect(); displayMenuSelect();
} }
delay(10); checkButtonState();
} }