#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
#define CLK_PIN 32
#define DT_PIN 33
#define SW_PIN 34
#define DAC_PIN 25 // Virtual DAC output pin
#define ENCODER_STEPS 4
#define MAX_VALUE 127
#define MIN_VALUE 0
#define MIDDLE_VALUE 64
#define DEBOUNCE_TIME 20 // Reduced debounce time to 20ms
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
volatile int32_t encoderPosition = MIDDLE_VALUE * ENCODER_STEPS;
volatile uint8_t encoderState = 0;
volatile bool updateDisplay = false;
int32_t getEncoderValue() {
return constrain(encoderPosition / ENCODER_STEPS, MIN_VALUE, MAX_VALUE);
}
void IRAM_ATTR handleEncoder() {
static const int8_t encoderStates[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
encoderState = ((encoderState << 2) | (digitalRead(CLK_PIN) << 1) | digitalRead(DT_PIN)) & 0x0F;
int8_t change = encoderStates[encoderState];
if (change != 0) {
encoderPosition += change;
encoderPosition = constrain(encoderPosition, MIN_VALUE * ENCODER_STEPS, MAX_VALUE * ENCODER_STEPS);
updateDisplay = true;
}
}
void setup() {
Serial.begin(115200);
Wire.begin();
pinMode(CLK_PIN, INPUT_PULLUP);
pinMode(DT_PIN, INPUT_PULLUP);
pinMode(SW_PIN, INPUT_PULLUP);
pinMode(DAC_PIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(CLK_PIN), handleEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(DT_PIN), handleEncoder, CHANGE);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("KY-040 Test");
display.display();
delay(2000);
}
void loop() {
static uint32_t lastDebounceTime = 0;
static int lastButtonState = HIGH;
int buttonState = digitalRead(SW_PIN);
if (buttonState != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > DEBOUNCE_TIME) {
if (buttonState == LOW) {
encoderPosition = MIDDLE_VALUE * ENCODER_STEPS;
updateDisplay = true;
Serial.println("Button pressed, reset to middle position");
}
}
lastButtonState = buttonState;
if (updateDisplay) {
int encoderValue = getEncoderValue();
float voltage = map(encoderValue, MIN_VALUE, MAX_VALUE, 0, 1000) / 100.0; // 0-10V range
// Set virtual DAC output
int dacValue = map(encoderValue, MIN_VALUE, MAX_VALUE, 0, 255);
analogWrite(DAC_PIN, dacValue);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print("Value: ");
display.println(encoderValue);
display.setTextSize(3);
display.setCursor(0, 30);
display.print(voltage, 2);
display.println("V");
display.display();
Serial.printf("Encoder: %d, Voltage: %.2fV, DAC: %d\n", encoderValue, voltage, dacValue);
updateDisplay = false;
}
}