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();
}
}
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!
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();
}
}
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();
}
}
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:
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)!