Random white dots on OLED display

My OLED screen displays random dots only in 2 submenus: time delay and time step

Here is my code:

#include <Adafruit_SSD1306.h>
#include <splash.h>

#include <Adafruit_GFX.h>
#include <Adafruit_GrayOLED.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>

#include <SPI.h>
#include <Wire.h>

#define SCREEN_WIDTH 128 // OLED display width,  in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define CLK 2
#define DT 3
#define SW 4
#define LED 13

//Adafruit_SSD1306 display(-1);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

int value = 0;
int counter = 0;
int counter1_min = 100;
int counter1_max = 1000;
int counter1 = counter1_min;
int counter2 = 0;
int time_step = 1;
int currentStateCLK;
int lastStateCLK;
String currentDir = "";


int ButtonState;
int btn;
unsigned long lastButtonPress = 0;

int x2 = 4;
int x1 = 17;
int y1 = 26;
int z1 = 34;
int t1 = 43;
int frame = 0;


String before1[4];
int after[4];
int before[] = {B1000, B0100, B0010, B0001};
uint8_t array_size = sizeof(before) / sizeof(before[0]);

void setup() {
  // Setup Serial Monitor
  Serial.begin(9600);
  while (!Serial);
  // initialize with the I2C addr 0x3C
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  // Clear the buffer.
  display.clearDisplay();

  // Set encoder pins as inputs
  pinMode(CLK, INPUT_PULLUP);
  pinMode(DT, INPUT_PULLUP);
  pinMode(SW, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
 
  randomSeed(analogRead(0));
  for (int i = 0; i < 4; i++) {

    // ---Pick a random array element.---
    uint8_t pick = random(0, array_size);

    // ---Display the value.---
    //Serial.println(before[pick]);

    // ---Assign the values to after[] array---
    after[i] = before[pick];
    //Serial.println(after[i]);

    // ---Overwrite with the last element of the array.---
    before[pick] = before[array_size - 1];

    // ---Reduce the array size to be selected.---
    array_size--;
    digitalWrite(LED, HIGH);
  }
  // Read the initial state of CLK
  lastStateCLK = digitalRead(CLK);

  // Call updateEncoder() when any high/low changed seen
  // on interrupt 0 (pin 2), or interrupt 1 (pin 3)
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);

}

void loop() {

  for (int i = 4; i >= 0; i--) {
      if(after[i]==B0001)
      before1[i]="0001";
      else if(after[i]==B0010)
      before1[i]="0010";
      else if(after[i]==B0100)
      before1[i]="0100";
      else //if(after[i]==B1000)
      before1[i]="1000";
  }
      Serial.println(before1[0]);
      Serial.println(before1[1]);
      Serial.println(before1[2]);
      Serial.println(before1[3]);

//Serial.println(after[i]);
    //switch (after[i]) {
      //case 1:
        //before1[i]="0001";
        //break;
      //case 2:
        //before1[i]="0010";
        //break;
      //case 4:
        //before1[i]="0100";
        //break;
      //case 8:
        //before1[i]="1000";
        //break;
        //}
        //Serial.println(before1[i]);
      //}
      //for (int i = 0; i < 4; i++){
        //Serial.println(before1[i]);
      //}
  //for (String element : before1)
  //Serial.println(element);
  Serial.println("-----");
  for (int element : after)
  Serial.println(element);
  Serial.println("-----");

  button();

  //Serial.println(btn);
  frame = counter;
  if (frame < 0) {
    frame = abs(frame % 4);
    if (frame == 1) frame = 4;
    else if (frame == 2) frame = 3;
    else if (frame == 3) frame = 2;
    else if (frame == 0) frame = 1;
  }
  else if (frame < 0 && frame % 4 == 0) frame = 1;
  else if (frame > 4 && frame % 4 != 0) frame = frame % 4;
  else if (frame > 4 && frame % 4 == 0) frame = 4;

  if (btn == 0) {
    switch (frame) {
      case 0:
        frame0();
        break;
      case 1:
        frame1();
        break;
      case 2:
        frame2();
        break;
      case 3:
        frame3();
        break;
      case 4:
        frame4();
        break;
    }
  }
  else if (btn == 1) {
    switch (frame) {
      case 0:
        btn = 0;
        break;
      case 1:
        subFrame1();
        break;
      case 2:
        subFrame2();
        value = counter1;
        break;
      case 3:
        subFrame3();
        break;
      case 4:
        subFrame4();
        break;
    }
  }

}

void frame0() {
  //display.clearDisplay();
  header();
  display.setCursor(0, x1);  display.print (" Generated matrix");
  display.setCursor(0, y1);  display.print (" Time delay");
  //display.setCursor(0, z1);  display.print (" Project info");
  display.setCursor(0, z1);  display.print (" Time step");
  display.setCursor(0, t1);  display.print (" Help");
  //display.display();
  refresh();
}
void frame1()
{
  //display.clearDisplay();
  header();
  display.setCursor(0, x1);  display.print (">Generated matrix");
  display.setCursor(0, y1);  display.print (" Time delay");
  //display.setCursor(0, z1);  display.print (" Project info");
  display.setCursor(0, z1);  display.print (" Time step");
  display.setCursor(0, t1);  display.print (" Help");
  //display.display();
  refresh();
}
void frame2()
{
  //display.clearDisplay();
  header();
  display.setCursor(0, x1);  display.print (" Generated matrix");
  display.setCursor(0, y1);  display.print (">Time delay");
  //display.setCursor(0, z1);  display.print (" Project info");
  display.setCursor(0, z1);  display.print (" Time step");
  display.setCursor(0, t1);  display.print (" Help");
  //display.display();
  refresh();
}
void frame3()
{
  //display.clearDisplay();
  header();
  display.setCursor(0, x1);  display.print (" Generated matrix");
  display.setCursor(0, y1);  display.print (" Time delay");
  //display.setCursor(0, z1);  display.print (">Project info");
  display.setCursor(0, z1);  display.print (">Time step");
  display.setCursor(0, t1);  display.print (" Help");
  //display.display();
  refresh();
}
void frame4()
{
  //display.clearDisplay();
  header();
  display.setCursor(0, x1);  display.print (" Generated matrix");
  display.setCursor(0, y1);  display.print (" Time delay");
  //display.setCursor(0, z1);  display.print (" Project info");
  display.setCursor(0, z1);  display.print (" Time step");
  display.setCursor(0, t1);  display.print (">Help");
  //display.display();
  refresh();
}


void subFrame1()
{
  //display.clearDisplay();
  //header();
  display.setCursor(0, 2);  display.print ("  Generated matrix");
  display.drawRoundRect(5, 0, 108, 12, 3, WHITE);
  //display.drawLine(0, y1+1, 128, y1+1, WHITE);
  display.setTextSize(1);
  for (int element : after)
  display.setCursor(0, x1 + 5);  display.print (after[0],BIN);
  display.setCursor(0, y1 + 5);  display.print (after[1],BIN);
  display.setCursor(0, z1 + 5);  display.print (after[2],BIN);
  display.setCursor(0, t1 + 5);  display.print (after[3],BIN);
  //display.display();
  refresh();
  //duzelt


}
void subFrame2()
{
  //display.clearDisplay();
  //header();
  display.setTextSize(1);
  display.setCursor(0, 2);  display.print ("     Time delay");
  display.setCursor(0, x1 + 1);  display.print (" Choose time delay:");
  display.drawRoundRect(5, 0, 108, 12, 3, WHITE);
  //display.drawRoundRect(7, x1-1, 108, 12, 3, WHITE);
  display.setTextSize(2);
  display.setCursor(0, y1 + 5);  display.print (value);
  //display.display();
  refresh();
  //duzelt

}

void subFrame3()
{
  //display.clearDisplay();
  //header();
  //display.drawRoundRect(7, x1-1, 108, 12, 3, WHITE);
  display.setTextSize(1);
  display.setCursor(2, 2);  display.print ("     Time step");
  display.drawRoundRect(5, 0, 108, 12, 3, WHITE);
  display.setCursor(0, x1 + 1);  display.print ("  Choose time step:");
  display.setTextSize(2);
  display.setCursor(0, y1 + 5);  display.print (time_step);
  //display.display();
  refresh();
}
void subFrame4()
{
  //display.clearDisplay();
  //header();
  display.setCursor(0, 2);  display.print ("        Help");
  display.drawRoundRect(5, 0, 108, 12, 3, WHITE);
  //display.drawRoundRect(7, x1-1, 108, 12, 3, WHITE);
  display.setCursor(0, y1 + 4);  display.print (" For more information please visit");
  //display.display();
  refresh();
}
void header() {
  display.setTextSize(1);          // text size
  display.setTextColor(WHITE);     // text color
  display.setCursor(0, 0);        // position to display
  display.println("Any header"); // text to display
  //display.display();               // show on OLED
}
void button() {
  ButtonState = digitalRead(SW);
  if (ButtonState == 0) { //if 80ms have passed since last LOW pulse, it means that the
    //button has been pressed, released and pressed again
    if (millis() - lastButtonPress > 80) {
      //Serial.println("Button pressed!");
      btn = (btn + 1) % 2;
      //display.clearDisplay();
    }
    lastButtonPress = millis();
  }
  delay(10);
}
void updateEncoder() {

  // 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) {
    //display.clearDisplay();
    // If the DT state is different than the CLK state then
    // the encoder is rotating CCW so decrement
    if (digitalRead(DT) != currentStateCLK && btn == 0) {
      counter --;
      currentDir = "CCW";
    } else if (digitalRead(DT) == currentStateCLK && btn == 0 ) {
      // Encoder is rotating CW so increment
      counter ++;
      currentDir = "CW";
    }
    else if (digitalRead(DT) != currentStateCLK && btn == 1 && frame == 2) {
      counter1 = counter1 + time_step;
      if (counter1 > counter1_max) counter1 = counter1_max;
    }
    else if (digitalRead(DT) == currentStateCLK && btn == 1 && frame == 2) {
      counter1 = counter1 - time_step;
      if (counter1 < counter1_min) counter1 = counter1_min;
    }
    else if (digitalRead(DT) != currentStateCLK && btn == 1 && frame == 3) {
      counter2++;
      if (counter2 < 1) counter2 = 1;
      time_stp();
    }
    else if (digitalRead(DT) == currentStateCLK && btn == 1 && frame == 3) {
      counter2--;
      if (counter2 > 5) counter2 = 5;
      time_stp();
    }

    //Serial.print("Direction: ");
    //Serial.print(currentDir);
    //Serial.print(" | Counter: ");
    //Serial.println(counter);
  }

  // Remember last CLK state
  lastStateCLK = currentStateCLK;
}
void refresh()
{
  display.display();
  delay(00);
  display.clearDisplay();
}
void time_stp() {
  switch (counter2) {
    case 1:
      time_step = 1;
      break;
    case 2:
      time_step = 5;
      break;
    case 3:
      time_step = 10;
      break;
    case 4:
      time_step = 50;
      break;
    case 5:
      time_step = 100;
      break;
  }
}

It looks like this:
oled

Why does it happen and how to get rid of this? It's same for simulation and real Arduino project.

you define

String before1[4];

so indexes go from 0 to 3 and after you try to write at index 4 which does not exist

  for (int i = 4; i >= 0; i--) {
    if (after[i] == B0001)
      before1[i] = "0001";

➜ you write beyond the bounds so your code is now in undefined behaviour territory

Side notes:

  • Why do you use a String for a byte representation? (after and before1)

  • when you want to alternate between two values, just use a boolean. instead of

int btn;
...
      btn = (btn + 1) % 2;

you could use

bool buttonReleased = true; // initial value
...
      buttonReleased = ! buttonReleased;

then instead of

  if (btn == 0) {
    ...
  }
  else if (btn == 1) {
    ...
  }

you can just do

  if (buttonReleased) {
    ...
  }
  else {
    ...
  }

2 Likes

That's actually another problem I got. Thanks for asking it. I want to display binary values on screen but instead of 0001 it displays 1. I tried several ways to solve it, but neither of them helps.

In the simulated world, there are no white dots. I made your project in Wokwi simulation:

Please only include what you need. This is all that you need:

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

You removed the check with "display.begin(SSD1306_SWITCHCAPVCC, 0x3C);". I think it is better to use the extra check. An example is here: Adafruit_SSD1306/ssd1306_128x64_i2c.ino at master · adafruit/Adafruit_SSD1306 · GitHub

1 Like

the print function does not print the leading 0 but you could write your own function

void printByte(byte aByte, byte nbBits = 8, bool addNewLine = true) { // nbBits is how many bits you want to print starting from LSb
  if (nbBits == 0) return; // nothing to print
  Serial.print(F("0b")); // 0b denotes a binary representation
  for (int i = nbBits - 1; i >= 0; i--) {
    Serial.write(bitRead(aByte, i) == 0 ? '0' : '1'); // https://www.arduino.cc/reference/en/language/functions/bits-and-bytes/bitread/
  }
  if (addNewLine) Serial.println();
}

void setup() {
  Serial.begin(115200);
  byte b = 0b1;
  printByte(b, 4);
  printByte(0b11001100, 8);
  printByte(0, 3);
}

void loop() {}

(typed here)

if I did not mess up, you should see in the Serial monitor (at 115200 bauds)

0b0001
0b11001100
0b000
1 Like

The random dots at the corner of the display are an indication that something is overwriting the display buffer. The display needs 1024 bytes of dynamic memory in addition to the amount the compiler shows for global variable use.

Avoid all use of String if possible.

Use the F() macro for text literals with print() or println(), that will tell the compiler to use program memory for the text instead of ram (dynamic memory). Should work with display.print() as well as Serial.

  Serial.println(F("-----"));
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.