Oled flickering when turning potmeter

Hello,

I am making a volume controller with an LCD and I only want to show the volume of the potmeter i am turning.

I finally got it too work but now when i turn the potmeter the lcd starts flickering.. I have been banging my head against the wall on how to fix it. if you review my code and point out mistakes I made would very much appreciate it.

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int numPotentiometers = 2;  // Define the number of potentiometers
const int potPins[numPotentiometers] = {A0, A1}; // Define an array to store the analog input pins connected to the potentiometers
const int numReadings = 10; // Number of readings to average for the moving average
int currentIndex = 0;             // Index to track the current position in the array

// Array to store the recent readings for each potentiometer
int readings[numPotentiometers][numReadings];

void setup() {
  // Initialize serial communication for debugging
  Serial.begin(9600);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  // Initialize the array of readings to zero
  for (int i = 0; i < numPotentiometers; i++) {
    for (int j = 0; j < numReadings; j++) {
      readings[i][j] = 0;
    }
  }
}

void loop() {
  // Read analog voltage from the pin corresponding to the current index
  int rawValue = analogRead(potPins[currentIndex]);
  // Perform any necessary processing on the raw value
  int stableValue = rawValue >> 2;

  display.clearDisplay();

  // Update the array of readings for the current potentiometer
  updateReadings(stableValue, currentIndex);

  // Calculate the moving average for the current potentiometer
  int movingAverage = calculateMovingAverage(currentIndex);

   // Compare the current value with the moving average
  int difference = stableValue - movingAverage;
  if (abs(difference) >= 10) {  // Adjust the threshold as needed
    Serial.print("Potentiometer on pin ");
    Serial.print(currentIndex);
    Serial.print(" changed. New value: ");
    Serial.println(stableValue);
    drawVerticalProgressBar(stableValue, 255, SCREEN_HEIGHT);
  }

  // Move to the next potentiometer
  currentIndex = (currentIndex + 1) % numPotentiometers;

  display.display();
}

// Function to update the array of readings for the current potentiometer
void updateReadings(int value, int index) {
  for (int i = 0; i < numReadings - 1; i++) {
    readings[index][i] = readings[index][i + 1];
  }
  readings[index][numReadings - 1] = value;
}

// Function to calculate the moving average for the current potentiometer
int calculateMovingAverage(int index) {
  int total = 0;
  for (int i = 0; i < numReadings; i++) {
    total += readings[index][i];
  }
  return total / numReadings;
}

void drawVerticalProgressBar(int progress, int total, int height) {
  // Calculate the height of the filled portion of the progress bar
  int filledHeight = map(progress, 0, total, 0, height);

  // Draw the filled portion
  display.fillRect(0, height - filledHeight, 10, filledHeight, WHITE);

  // Draw the empty portion
  display.fillRect(0, 0, 10, height - filledHeight, BLACK);

  // Draw an outline around the progress bar
  display.drawRect(0, 0, 10, height, WHITE);
}

You may be updating the display too fast. Slow it down a little. I guess 5-10 times per second is more than enough.

Just adding a delay() to the loop?

Also, do not redraw the full screen. First, draw your template. Next, draw "progress" then only redraw the part that changes.

Start re-drawing at "progress" rather than from 0. When your progress is negative, you will need to fill that as BLACK.

void drawVerticalProgressBar(int progress, int total, int height) {
  // Calculate the height of the filled portion of the progress bar
  int filledHeight = map(progress, 0, total, 0, height);

  // Draw the filled portion
  display.fillRect(0, height - filledHeight, 10, filledHeight, WHITE);

  // Draw the empty portion
  display.fillRect(0, 0, 10, height - filledHeight, BLACK);

  // Draw an outline around the progress bar
  display.drawRect(0, 0, 10, height, WHITE);
}

That should work, but remember delay() is blocking, and it will interfere with other functionality you may want to add later.

Try something like this to make it non-blocking:

void loop() {
  static unsigned long lastUpdate;
  const unsigned long updateInterval = 100;
  unsigned long currentTime = millis();
  if (currentTime - lastUpdate >= updateInterval)   {

      // everything else in here

    lastUpdate = currentTime;
  }
}

The funny thing is i just found it, because you made me think in a different way. Got the same code now. Haha thank you!!

I reworked my code looks smoother, thanks for the suggestion!

An update to redrawing...

If progress is positive, only redraw the WHITE part (this will begin to cover the BLACK portion).
If progress is negative, only redraw the BLACK part (this will begin to cover the WHITE portion).