OLED 128x64 Clear Display Problem

Hello everyone. I am using OLED 128x64 display with ASCII library. I'll leave the link library below.
Here you can see my coding and my display example. As you can see there are two "columns" that I separated with setcursor. P and mV as an example of my label and unit string: Power output and millivolts. Between them, I have variables that are given from sensor reading.

#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
SSD1306AsciiWire oled;
long randNumber;

void setup() 
{
  #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
  #else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  #endif // RST_PIN >= 0
  // Call oled.setI2cClock(frequency) to change from the default frequency.
  oled.setFont(Adafruit5x7);
  Serial.begin(9600);
  randomSeed(analogRead(0));

  oled.clear();
  oled.setCursor( 0, 0)      ;  oled.print(F("SD OK. Starting.."));
  oled.setCursor( 0, 1)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 1)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 2)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 2)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 3)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 3)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 4)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 4)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 5)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 5)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 6)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 6)      ;  oled.print(F("P      mV"));
  oled.setCursor( 0, 7)      ;  oled.print(F("P      mV"));
  oled.setCursor(64, 7)      ;  oled.print(F("P      mV"));
  delay(3000);
}

void loop() 
{
  randNumber = random(20000);
  oled.setCursor( 0, 0)      ;  oled.print(F("Writing Data "));  oled.print(randNumber); oled.print(F("  "));
  oled.setCursor( 6, 1)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 1)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 2)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 2)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 3)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 3)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 4)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 4)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 5)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 5)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 6)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 6)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor( 6, 7)      ;  oled.print(randNumber); oled.print(F(" "));
  oled.setCursor(70, 7)      ;  oled.print(randNumber); oled.print(F(" "));

  delay(500);

The problem is I want to refresh only all the variables from the sensor. In this coding, I attempted to use oled.print(" ") which is not effective; when the variables' digits dropped suddenly, some characters are not cleared, if too much space the unit strings will be cropped. Otherwise, if I use oled.clear command, the whole oled will refresh slowly and looks very apparent. Is there anything that I could try to fix this? Thank you

Convert the value to a string and then, with strlen, determine if you need to truncate or add spaces to keep your formatting

Do you have some easy examples of how to do it?

Nothing easy.
From your related, previous subject, I know that your project has floats galore.
dtostrf()
converts a float into a string
dtostrf() - turn your floats into strings - Programming Electronics Academy
It can truncate your decimal, too.
Then, I guess, there's a matter Left or Right Justification (Formatting);
strlen() & strcat()

dtostrf() will handle formatting too. e.g. width = 5, decimals = 0.

Can it add leading spaces, to shift everything to the right

   1.56 mW
  12.34 mW

Just a bit more work there I think.

PE - If the previous field was "12.34" and current is "1.23", he doesn't want the result to display 11.23

If I'm using dtostrf, strlen and strcat, and I have 14 variables, isn't that mean I'm going to write 14 repeated codes? So the code will be too long and eats up lots of storage space? If yes I'm worried I can't put this solution into my code, I have quite limited space for oled codings. If not, maybe I'll give it a try.

Otherwise, I have thought of other solutions. Is it possible to just delete specific rows or columns via some special codes? I found these in the library and it's quite interesting, but I don't know how to use them.

   * @brief Clear the display and set the cursor to (0, 0).
   */
  void clear();
  /**
   * @brief Clear a region of the display.
   *
   * @param[in] c0 Starting column.
   * @param[in] c1 Ending column.
   * @param[in] r0 Starting row;
   * @param[in] r1 Ending row;
   * @note The final cursor position will be (c0, r0).
   */
  void clear(uint8_t c0, uint8_t c1, uint8_t r0, uint8_t r1);
  /**
   * @brief Clear a field of n fieldWidth() characters.
   *
   * @param[in] col Field start column.
   *
   * @param[in] row Field start row.
   *
   * @param[in] n Number of characters in the field.
   *
   */
  void clearField(uint8_t col, uint8_t row, uint8_t n);
  /**
   * @brief Clear the display to the end of the current line.
   * @note The number of rows cleared will be determined by the height
   *       of the current font.
   * @note The cursor will be returned to the original position.
   */
  void clearToEOL();

Or maybe by printing black squares, or settextcolor to black and white? I've read some in the other related post, but they are using the default library. I don't know are those things can be done by using this ASCII library.

You have similar repeated sequences e.g.

So you write a helper function that takes appropriate arguments e.g.

void oled_x_y_val(int x, int y, int val)
{
    char buf[16];  //somewhere to build the formatted result
    oled.setCursor(x, y);
    dtostrf(val, 5, 0, buf);   // allow 5 character width, 0 decimals
    oled.print(buf);
    oled.print(F(" "));    // not necessary when you format properly
}

and your loop would be something like

or you could test the function with

  oled_x_y_val( 6, 1, 1);
  oled_x_y_val( 6, 2, 12);
  oled_x_y_val( 6, 3, 123);
  oled_x_y_val( 6, 4, 1234);
  oled_x_y_val( 6, 5, 12345);
  oled_x_y_val( 6, 6,  -12345);  //see what happens

If you ever see repeated sequences it is always worth thinking about a single helper function.

Note that you normally use dtostrf() with f-p values.
But there are many other ways to format numbers.

Another way to right justify integer values

void oled_x_y_val(int x, int y, int val)
{
    oled.setCursor(x, y);
    if (val < 10) oled.print("    ");
    else if (val < 100) oled.print("   ");
    else if (val < 1000) oled.print("  ");
    else if (val < 10000) oled.print(" ");
    oled.print(val);
    oled.print(F(" "));    // not necessary when you format properly
}

This approach is handy when you are printing 0-99 but it becomes convoluted when you have more than 2 digits

Wow, this is working exactly as I wanted :smiley: . But I think the code that I've written is not compact yet. This code takes 35% of storage space and 21% of dynamic memory. Is there anything that I can do to make it smaller?

#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define I2C_ADDRESS 0x3C
#define RST_PIN -1
SSD1306AsciiWire oled;
float randNumber1 = 0;
float randNumber2 = 0;
float randNumber3 = 0;
float randNumber4 = 0;

void setup() {
  #if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
  #else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
  #endif // RST_PIN >= 0
  // Call oled.setI2cClock(frequency) to change from the default frequency.
  oled.setFont(Adafruit5x7);
  Serial.begin(9600);
  randomSeed(analogRead(0));

  oled.clear();
  oled.setCursor( 0, 0)      ;  oled.print(F("SD OK. Starting.."));
  oled.setCursor( 0, 1)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 1)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 2)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 2)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 3)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 3)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 4)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 4)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 5)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 5)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 6)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 6)      ;  oled.print(F("P       mV"));
  oled.setCursor( 0, 7)      ;  oled.print(F("P       mV"));
  oled.setCursor(64, 7)      ;  oled.print(F("P       mV"));
  delay(3000);
}

void oled_x_y_val(int x, int y, float val)
{
    char buff[16];  //somewhere to build the formatted result
    oled.setCursor(x, y);
    dtostrf(val, 7, 2, buff);   // allow 7 character width, 2 decimals
    oled.print(buff);
}
void loop() {
  
  randNumber1 = random(20000)/22.00;
  randNumber2 = random(50000)/33.00;
  randNumber3 = random(10000)/44.00;
  randNumber4 = random(40000)/55.00;

  Serial.print  (randNumber1); Serial.print(F("\t"));
  Serial.print  (randNumber2); Serial.print(F("\t"));
  Serial.print  (randNumber3); Serial.print(F("\t"));
  Serial.print  (randNumber4); Serial.print(F("\t"));
  Serial.println(F("\n"));
   
  oled.setCursor( 0, 0)      ;  oled.print(F("Writing Data "));  oled.print(randNumber1); oled.print(F("   "));
  oled_x_y_val( 6, 1, randNumber1);
  oled_x_y_val(70, 1, randNumber2);
  oled_x_y_val( 6, 2, randNumber3);
  oled_x_y_val(70, 2, randNumber4);
  oled_x_y_val( 6, 3, randNumber1);
  oled_x_y_val(70, 3, randNumber2);
  oled_x_y_val( 6, 4, randNumber3);
  oled_x_y_val(70, 4, randNumber4);
  oled_x_y_val( 6, 5, randNumber1);
  oled_x_y_val(70, 5, randNumber2);
  oled_x_y_val( 6, 6, randNumber3);
  oled_x_y_val(70, 6, randNumber4);
  oled_x_y_val( 6, 7, randNumber1);
  oled_x_y_val(70, 7, randNumber2);
  
  delay(500);
}

Just a side question, is this helper function can be used too on serial prints? I wanted to align the printed variables too if it is possible.

Yes, you can make a serial_val() helper function.
If you have a VT100 Terminal you could even set the cursor correctly.

You could make an oled_x_y_msg() helper for your initial stuff in setup().

Don't worry too much about memory use. Concentrate on making your program easy to write and maintain.
Cups of tea help you think straight.

The memory size will be fairly efficient. Especially when you understand what you are designing. You can tweak if necessary.

David.

Alright then, I'll take a look at the serial_val. Yes, I was quite concerned about the size, but after putting it into my main code turns out it didn't consume as much. :slight_smile: Anyway thank you very much for your help.

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