U8g2 infinite side move

Hello !
I faced a small problem, and if anyone knows the solution or made something similar! In short, a movement from left to right, which displays a vertical line (random length, max 64 pixels)!
What I would like help with is how to solve it, if you reach the 128th part, then the movement should continue by shifting the image displayed so far to the left! Because now when it reaches the end, the system stops!
How can it be solved so that an endless tape goes round and round and does not only work up to 128 lines?
Thank you in advance for your help!

unsigned long startTime = millis();
u8g2_uint_t offset;
u8g2_uint_t width;
u8g2_uint_t x ;

void strip(){
  
    int ran =random(0,64);
    x =offset; 
    do {
		x+=-1; 
    if (millis() - startTime >= 500){ 
		for(int Pix=0;Pix<ran;Pix++)
		{
		u8g2.drawLine(x, Pix, x, Pix);
    Serial.print("Movement value: ");
    Serial.println(x);
    Serial.print("Line length: ");
    Serial.println(Pix);
   // u8g2.sendBuffer();
    }
    
    startTime = millis();
    }
    } while( x < u8g2.getDisplayWidth() );
    
    offset+=1;					// scroll by one pixel
  if ( (u8g2_uint_t)offset < (u8g2_uint_t)-width )	
    offset = 0;  

}
void loop() {
  if (millis() - startTime >= 500){
  strip();
  u8g2.updateDisplay();
  startTime = millis();
  }
  
}

Your code does not compile without a library file or creating an instance...

It looks like you are trying to use an OLED (126x64).

There is no "129, 130...et c." for this screen or the memory location for the buffer. To "wrap around" (from 128 to 0), try something like this...

  if (x == 128) x = 0; // if "x" is maximum-right, "x" becomes maximum-left

Here is a simple sketch to show "endless round and round"

Hi xfpd!
Yes, I wrote the code on wokwi.com, but there is only an OLED display!
But what it will be run on is U8G2_ST7920_128X64_1_HW_SPI u8g2 ! I tried it today and it works well on ST7920 (if it reaches 128, the obtained value is displayed as a vertical line)!
This is a distance meter (sonar) that shows the surface of the bottom of the lake bed while moving! The problem is that I put a drawBox behind the lines that shows the water in side view, and as the lines appear, I want to hide them using u8g2.setDrawColor(2)! For some reason, it doesn't disappear if it doesn't blend into the box! If I can somehow remove the background, the next problem is that the background must move together with the lines!

There are 128 pixels... but you count the pixels 0 through 127. 128 is not on the screen "to the right" rather 128 is 0 (at the left).

I get a random flashing of the trace, like this...
graph

Try this in the simulator, it uses a different idea of shifting the data in the display buffer and then adding the newest line on the left. More of a typical scrolling display.

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long startTime = millis();
uint8_t* ptr;

void setup(void) {
  u8g2.begin();
  ptr = u8g2.getBufferPtr(); //get the address of the display buffer
  u8g2.drawBox(0, 20, u8g2.getDisplayWidth() - 1, u8g2.getDisplayHeight() - 1); //initial water background
}

void strip() {
  u8g2_uint_t width = u8g2.getDisplayWidth();
  u8g2_uint_t height = u8g2.getDisplayHeight();

  //this shifts the image in the display buffer 1 pixel to the right
  for (u8g2_uint_t row = 0; row < height / 8; row++) {
    for (u8g2_uint_t col = width - 1; col > 0; col--) {
      uint8_t* p = ptr + row * width + col;
      *p = *(p - 1);
    }
  }

  int ran = random(0, 42);
  //draw white line from water surface to bottom of display
  u8g2.setDrawColor(1);
  u8g2.drawVLine(0, 20, height - 20);
  //overwrite the previous line with the random depth reading
  u8g2.setDrawColor(0);
  u8g2.drawVLine(0, 21, ran);
  //set display color back to normal
  //not needed but useful if there are other display functions
  u8g2.setDrawColor(1);
}

void loop() {
  if (millis() - startTime >= 500) {
    strip();
    u8g2.updateDisplay();
    startTime = millis();
  }
}
1 Like

Nice.

Only other way I can think to do this would be to save the value for each data point and redraw the entire display. That would have the advantage that the display could use the paged buffer instead of the full buffer.

Hi David !
Thanks for the code, I tried it on the wokwi page and it works great!
In the evening, I will try it on my own display, which is not OLED, but U8G2_ST7920_128X64_1_HW_SPI, and I will see if it works as well on it too!
I have a question, what needs to be rewritten to start from the right side and move to the left?

The code should work on an ST7920, unless U8g2 organizes the buffer differently. I think I have one of those displays, but do not have time to test it before going to work.

This code scrolls from right to left. The only change needed was in the buffer shifting code.
I would probably not do it this way, instead use a circular buffer to store the most recent 128 values that you want to display, and then redraw the entire display each time. That allows you to use a page buffer instead of the full buffer, saving a considerable amount of memory.

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long startTime = millis();
uint8_t* ptr;

void setup(void) {
  u8g2.begin();
  ptr = u8g2.getBufferPtr(); //get the address of the display buffer
  u8g2.drawBox(0, 20, u8g2.getDisplayWidth(), u8g2.getDisplayHeight() - 20); //initial water background
}

void strip() {
  u8g2_uint_t width = u8g2.getDisplayWidth();
  u8g2_uint_t height = u8g2.getDisplayHeight();

  //this shifts the image in the display buffer 1 pixel to the left
  for (u8g2_uint_t row = 0; row < height / 8; row++) {
    for (u8g2_uint_t col = 0; col < width - 1; col++) {
      uint8_t* p = ptr + row * width + col;
      *p = *(p + 1);
    }
  }

  int ran = random(0, 42);
  //draw white line from water surface to bottom of display
  u8g2.setDrawColor(1);
  u8g2.drawVLine(width - 1, 20, height - 20);
  //overwrite the previous line with the random depth reading
  u8g2.setDrawColor(0);
  u8g2.drawVLine(width - 1, 21, ran);
  //set display color back to normal
  //not needed but useful if there are other display functions
  u8g2.setDrawColor(1);
}

void loop() {
  if (millis() - startTime >= 500) {
    strip();
    u8g2.updateDisplay();
    startTime = millis();
  }
}

The upper part also runs with it :slight_smile:
I'll try it tonight on my own display!

I tried it on my own display! It does not display the data, but if I eliminate the for loop, u8g2.print("Depth: "); appears !
It freezes for some reason because of the for loop, you may be right and it is straining the memory!

I tried the code on an ST7920 display. Got it working after modifying the buffer shifting code, but LCD displays update slowly, resulting in massively bad blinking. Same blinking results with redrawing the display instead of shifting the buffer, the screen update is just too slow.

Here is my final test code, if you want to see the blinking effect yourself:

#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
//
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long startTime = millis();
uint8_t* ptr;
uint8_t buff[128] = {0};

void setup(void) {
  u8g2.begin();
  ptr = u8g2.getBufferPtr(); //get the address of the display buffer
  u8g2.drawBox(0, 20, u8g2.getDisplayWidth(), u8g2.getDisplayHeight() - 20); //initial water background
}

void strip() {
  static size_t offset = 127;
  int ran = random(9, 42);
  offset = (offset + 1) % 128;
  buff[offset] = ran;
  u8g2.clearBuffer();
  u8g2.setDrawColor(1);
  u8g2.drawBox(0, 20, u8g2.getDisplayWidth(), u8g2.getDisplayHeight() - 20); //initial water background
  u8g2.setDrawColor(0);
  for (size_t i = 0; i < 128; i++){
    //u8g2.drawVLine(i, 21, buff[i]);
    u8g2.drawVLine(i, 21, buff[(offset + i + 1) % 128]);
  }
  u8g2.setDrawColor(1);
}

void loop() {
  if (millis() - startTime >= 500) {
    strip();
    u8g2.updateDisplay();
    startTime = millis();
  }
}

Thank you very much for your help !
Now I had time to try it!
I read what you wrote about changing buffers, yes, it looks like it, but there is not that much movement in the lake! In the lake bed, there is not such a big difference "per pixel", for example: pixel 127 is 11, pixel 126 is 42! Since the bottom of the lake bed is a long surface, the rise and fall is gradual! I tried setting the random value to 38-42! Thus, the buffer effect is not very noticeable! It might not be so noticeable on another display (now my display has a blue background)! Since blue and white colors are very different, you can see such an orange line! On a green background and black display, it may not be so visible! I found a not so sensitive display (I just need to make a connector for it, and I hope u8g2 runs on it)!

Thanks again for the code, it works for me!

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