ThingPulse / esp8266-oled-ssd1306

Driver for the SSD1306 and SH1106 based 128x64, 128x32, 64x48 pixel OLED display running on ESP8266/ESP32
https://thingpulse.com
Other
2.03k stars 643 forks source link

"Side scrolling" is mentioned in the readme but undocumented #160

Closed bmidgley closed 4 years ago

bmidgley commented 7 years ago

Are there any examples out there for using the side scrolling? I tried drawstring with my string printed twice and then moved to a negative offset, but this only works with short strings. (Long strings wrap around and print over the start of the string)

arunkbharathan commented 6 years ago

I too have the same problem. How to scroll long text sideways?

Shdwdrgn commented 6 years ago

If you are just looking at scrolling a single line of text horizontally, below is the solution I came up with. Note this still does not solve the problem of longer text strings (note the "quick brown fox" at line 55 which will show the problem if you uncomment it), but it does demonstrate an easy method of horizontal scrolling. It would be great if someone could wrap this up into a function for the ssd1306 library and make it work off of an interrupt.

This technique works by first trying to guess at the pixel length of the whole string you want to scroll. Since characters are of differing widths I have to make a rough estimate of an average character size in scroll_char_width. You will need to adjust this based on your particular text. Once we have a width, the string is drawn to the display twice -- first the main string that should always be showing some part of itself, and the a second string to fill in the gaps, either before or after the primary string base on the current scroll position. (See lines 69-73.) Every 20ms we shift the scroll position one more pixel to the left, draw a filled white rectangle to clear the current text, and redraw the two strings at their new offset. The string also includes a display of millis() so you can see constantly-changing text as it scrolls.

From my testing, it looks like the string-wrap issue happens if you try to print a string longer than 60 characters. If there were a way to find the exact pixel length that a string will require on the screen for the given font size, then I could rewrite the function to line up the two scrolling strings exactly, and I could scroll just a portion of the string so that length would no longer be a factor. Without that, I think we're stuck working with shorter strings.

The following demonstration was run on a Lolin32 which has an ESP32 and a 128x64 display onboard. Adjust the parameters to suit your own hardware. (Sorry, doesn't look like code pasting is supported here, so I also attached a file with the proper indentations.)

// OLED SCREEN PARAMETERS

define SCREEN_I2C_ADDRESS 0x3C

define SCREEN_SDA_PIN 5

define SCREEN_SCL_PIN 4

define SCREEN_HEIGHT 64

define SCREEN_WIDTH 128

define SCREEN_VERTICAL_FLIP true

include

SSD1306Wire display(SCREEN_I2C_ADDRESS, SCREEN_SDA_PIN, SCREEN_SCL_PIN);

// Parameters for the scrolling text

define scroll_delay 20 // set the scroll speed

define scroll_char_width 4.666 // approximate average character width

define scroll_y 51 // row of text line

define scroll_height 12 // character height

int scroll_pos = SCREEN_WIDTH; unsigned int next_scroll = 0; String scroll_string; const char* scroll_div = " | ";

void setup() { Serial.begin(115200);

Wire.begin(SCREEN_SDA_PIN, SCREEN_SCL_PIN); Wire.beginTransmission(SCREEN_I2C_ADDRESS); if(Wire.endTransmission() == 0) { display.init(); display.setContrast(255); if(SCREEN_VERTICAL_FLIP) display.flipScreenVertically(); display.clear(); display.setFont(ArialMT_Plain_16); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(63, 26, "Waiting for data..."); display.display(); } else { Serial.print("OLED screen not found at 0x"); Serial.println(SCREEN_I2C_ADDRESS, HEX); while (1); } }

void loop() { unsigned long NOW = millis();

if (NOW >= next_scroll) { scroll_pos--; next_scroll = NOW + scroll_delay;

scroll_string  = "1024 hPa" + String(scroll_div);
scroll_string += "30.24 Hg" + String(scroll_div);
scroll_string += "192.168.0.100" + String(scroll_div);
scroll_string += String(millis()) + String(scroll_div);
//scroll_string += "The quick brown fox jumped over the lazy dog" + String(scroll_div);
scrollText(scroll_string);

} }

void scrollText(String str) { int len = str.length() * scroll_char_width; if (scroll_pos + len <= SCREEN_WIDTH) scroll_pos += len;

display.setFont(ArialMT_Plain_10); display.setTextAlignment(TEXT_ALIGN_LEFT); display.setColor(WHITE); // blank out the scrollable area display.fillRect(0, scroll_y+1, SCREEN_WIDTH, scroll_height); display.setColor(BLACK); // draw text in opposite color display.drawString(scroll_pos, scroll_y, str); if (scroll_pos > 0) display.drawString(scroll_pos - len, scroll_y, str); else display.drawString(scroll_pos + len, scroll_y, str); display.display(); display.setColor(WHITE); // set drawing color back to default }

SSD1306HorizontalScroll.ino.txt

dpharris commented 6 years ago

Looks like you can calculate the width: *for (uint16_t i = 0; i < length; i++) { strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) JUMPTABLE_BYTES + JUMPTABLE_WIDTH); }**

From: https://github.com/squix78/esp8266-oled-ssd1306/blob/master/OLEDDisplay.cpp

Shdwdrgn commented 6 years ago

Thanks for finding this! Let me see what I can work out with it and I'll post back...

kosso commented 6 years ago

I don't know if this is any help (or if I just totally missed that this lib already has it), but I just added a basic display scroll left and right to my fork. Using the commands used in the Adafruit SSD1306 library.

See: https://github.com/kosso/esp8266-oled-ssd1306/blob/add-scrolling/OLEDDisplay.cpp#L558

This will scroll the whole screen (which might not be what you want) from left to right:

display.init();

display.clear();    
display.setColor(WHITE);
display.setFont(ArialMT_Plain_10);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(DISPLAY_WIDTH / 2, 2, "WOO! SCROLLING");
display.setFont(ArialMT_Plain_10);
display.drawString(DISPLAY_WIDTH / 2, 18, "until we stop it...");
display.display();

display.startscrollright(0x00, 0x0F);
delay(4000);
display.stopscroll();

Also, (and this might be exactly what you want) the library already has the methods:

display.getStringWidth(String text)
// Returns the width of the text with the current font settings

and

display.drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text)
// Draws a String with a maximum width at the given location.
// If the given String is wider than the specified width
// The text will be wrapped to the next line at a space or dash
androdlang commented 6 years ago

A bit late, but I just finished a library for the SSD1306 covering "scrolling text" with unlimited text length, variable font and speed. If you arre interested, have a look into the source https://github.com/androdlang/InfoTicker

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.