ST7920 Arduino Tutorial (Part 3): Scrolling, Animations & Smooth Screen Transitions with U8g2
Welcome to the third part of the ST7920 Arduino Tutorial series.
In the previous two guides, you learned how to connect the ST7920 128×64 display, print text, and draw graphics using the U8g2 library. Now it is time to take your UI to the next level.
In this tutorial, you will learn how to create scrolling text, smooth animations, and professional screen transitions on the ST7920 display. These effects help your project look modern, alive, and more interactive.
By the end of this guide, you will be able to create animated menus, moving icons, loading screens, progress bars, sliding pages, and much more using Arduino and U8g2.
Prerequisites:
You must go through the previous 2 parts of this mini series:

Scrolling Text on ST7920 using Arduino and U8g2
The Scrolling text is one of the most common effects used in modern displays. It helps when the message is longer than the screen width, or when you want to create attention-grabbing UI elements like headlines, tickers, and alerts. In this part, you will learn how to create smooth horizontal scrolling, vertical scrolling, and a marquee banner using the ST7920 display with the U8g2 library. These effects make even a simple monochrome screen look dynamic and professional.
Horizontal Scrolling Text (Left to Right / Right to Left)
Below is a fully working version with the correct scrolling behavior. This code uses a fixed frame rate and calculates the text width properly. It scrolls from right to left, which is the most common style.
Below is the Code for Horizontal Scrolling Text
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
// ST7920 128x64 using Software SPI
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* CS=*/ 10, /* reset=*/ 8);
const char msg[] = "Controllerstech Tutorials";
int displayWidth = 128; // ST7920 width in pixels
int textWidth; // Pixel width of the message
int xPos; // Current X position of the text
unsigned long lastMillis = 0;
const unsigned long frameDelay = 40;
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_6x12_tf);
// Measure text width after setting the font
textWidth = u8g2.getStrWidth(msg);
// Start the text just outside the right edge
xPos = displayWidth;
}
void loop() {
// Maintain stable frame timing
if (millis() - lastMillis < frameDelay) return;
lastMillis = millis();
u8g2.firstPage();
do {
u8g2.drawStr(xPos, 32, msg); // Draw text horizontally centered
} while (u8g2.nextPage());
// Move text left
xPos--;
// When text moves fully off the left side, reset it to the right side
if (xPos < -textWidth) {
xPos = displayWidth;
}
}Explanation
This example creates a smooth right-to-left scrolling effect. The text begins from the right edge of the screen and moves left one pixel at a time.
- The
getStrWidth()function is used to calculate the exact pixel width of the string. This is very important, because different fonts have different character widths. If the text width is not calculated properly, the scroll will stop early or will not reset correctly. - Once the text has moved completely off the screen (i.e., its rightmost pixel is past the left edge), we reset the
xPosback to the full display width. This makes the scrolling continuous. The controlled frame delay ensures smooth animation without flicker.
Output
The gif below shows the text smoothly sliding from right to left across the display.

Vertical Scrolling Text (Up and Down)
Scrolling Vertical is useful for showing notifications, credits, or long descriptions in a limited vertical space. In this example, the text moves from the bottom of the screen toward the top.
Below is the Code to scroll text Vertically
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int yPos = 64; // Start from bottom edge
const char* vText = "Scrolling Vertically";
const unsigned long frameDelay = 40;
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_6x12_tf);
}
void loop() {
u8g2.firstPage();
do {
u8g2.drawStr(10, yPos, vText);
} while (u8g2.nextPage());
yPos--;
// Reset once the text scrolls out of view
if (yPos < -10) {
yPos = 64;
}
delay(frameDelay);
}Explanation
The vertical scrolling effect works by gradually decreasing the y-coordinate of the text. The text starts at the bottom of the screen (y = 64) and moves upward one pixel at a time.
Once the text moves completely out of the top boundary, we reset the position back to the bottom. Vertical scroll effects are commonly used in menus, messages, and scrolling credits. This type of motion also gives a “smooth lift” feel, which is very helpful in UI navigation.
Output
The gif below shows the text moving upward smoothly, creating a clean vertical scrolling effect.
Marquee Banner Effect for Headlines
A marquee banner is commonly used for alerts, news tickers, and headline strips. In this effect, the top area of the display is turned into a moving banner with bold text. This enhances readability and draws user attention.
Below is the Code for Marquee Banner Text (with seamless scroll)
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
const char* banner = " Welcome to Controllerstech ";
int textWidth;
int xPos = 0;
const int displayWidth = 128;
unsigned long lastMillis = 0;
const unsigned long frameDelay = 35;
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_7x14B_tf); // Bold font for banner
textWidth = u8g2.getStrWidth(banner);
}
void loop() {
if (millis() - lastMillis < frameDelay) return;
lastMillis = millis();
u8g2.firstPage();
do {
// Draw banner background
u8g2.drawBox(0, 0, 128, 16);
// Draw two copies of the text for seamless scrolling
u8g2.setDrawColor(0); // White text on black
u8g2.drawStr(xPos, 14, banner);
u8g2.drawStr(xPos + textWidth, 14, banner);
u8g2.setDrawColor(1);
} while (u8g2.nextPage());
xPos--;
// Seamless reset
if (xPos <= -textWidth) {
xPos += textWidth;
}
}Explanation
This code creates a professional-looking marquee banner, just like the scrolling headlines on news channels. The banner area is drawn using a solid black rectangle, and bold white text scrolls through it.
To achieve a seamless effect without any blank gaps, two copies of the string are drawn:
- one at
xPos - another at
xPos + textWidth
As the first text scrolls off the screen, the second one takes its place. This gives the illusion of a continuous loop, making the banner look smooth and polished.
The bold font enhances visibility, and the dark background makes the banner stand out from the rest of the screen.
Output
The gif below shows the marquee banner on the display.
Creating Animations on ST7920 with Arduino
Animations make the UI feel alive, modern and professional. Even on a small monochrome display like the ST7920, you can create smooth motion effects using simple logic and the U8g2 library.
In this section, we will explore different animation styles, from frame-by-frame animation to sliding banners and progress bars.
Frame-by-Frame Animation Example
Frame-by-frame animation is the simplest form of animation. You draw individual frames and show them one after another with a delay. This technique works well for icons, emoji-style graphics, or simple motion.
Below is the Code to draw Frame-by-Frame Animation
#include <U8g2lib.h>
#include <Wire.h>
// Using 128x64 ST7920 SPI
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
const unsigned char frame1[] PROGMEM = {
0x00,0x18,0x3C,0x7E,0x3C,0x18,0x00
};
const unsigned char frame2[] PROGMEM = {
0x00,0x0C,0x1E,0x3F,0x1E,0x0C,0x00
};
void setup() {
u8g2.begin();
}
void loop() {
u8g2.firstPage();
do {
u8g2.drawXBMP(60, 24, 7, 7, frame1);
} while (u8g2.nextPage());
delay(150);
u8g2.firstPage();
do {
u8g2.drawXBMP(60, 24, 7, 7, frame2);
} while (u8g2.nextPage());
delay(150);
}Explanation
This example stores two small bitmap frames in PROGMEM. The display shows frame1, waits a moment, then shows frame2, creating a blinking or beating effect.
By adding more frames, you can create smoother animations.
Output
The gif below shows the frame-by-frame animation on the display.
Moving Object Animation (Ball / Icon Movement)
This effect moves an object smoothly across the screen. It is great for indicators, UI elements, bouncing objects, or simple games.
Below is the Code for Moving Ball Animation
#include <U8g2lib.h>
#include <Wire.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int x = 0;
int y = 30;
int speedX = 2;
void setup() {
u8g2.begin();
}
void loop() {
x += speedX;
if (x > 120 || x < 0) {
speedX = -speedX; // bounce
}
u8g2.firstPage();
do {
u8g2.drawDisc(x, y, 5, U8G2_DRAW_ALL);
} while (u8g2.nextPage());
delay(50);
}Explanation
A simple physics loop updates the x-position of the ball. When the ball reaches a screen edge, the direction reverses, creating a bouncing animation.
This is one of the smoothest animation styles on ST7920 because drawing a circle is fast.
Output
The gif below shows the output of the moving ball animation.
Loading Spinner Animation
The Loading spinners give a modern look and are useful for processes like reading sensors or loading menus.
Below is the Code fo Loading Spinner
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int angle = 0;
void setup() {
u8g2.begin();
}
void loop() {
u8g2.firstPage();
do {
int x = 64 + 20 * cos(angle * 0.1);
int y = 32 + 20 * sin(angle * 0.1);
u8g2.drawCircle(64, 32, 22);
u8g2.drawDisc(x, y, 3);
} while (u8g2.nextPage());
angle++;
if (angle > 360) angle = 0;
delay(30);
}Explanation
This spinner uses trigonometric functions to move a small dot around a circular path. The outer circle stays fixed, while the dot rotates smoothly like a loading icon found in modern apps.
Output
The image below shows a spinning loader animation with a dot rotating around a circle.
Progress Bar Animation
The Progress bars are useful for showing loading tasks, sensor calibration, or startup screens.
Below is the Code for Progress Bar Animation.
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int progress = 0;
void setup() {
u8g2.begin();
}
void loop() {
progress++;
if (progress > 100) progress = 0;
u8g2.firstPage();
do {
u8g2.drawFrame(20, 30, 88, 12); // outline
u8g2.drawBox(22, 32, progress * 0.84, 8);
} while (u8g2.nextPage());
delay(60);
}Explanation
The bar grows gradually from 0% to 100%. To convert percentage into pixel width, the code multiplies by 0.84 because the bar width is 84 pixels.
This makes a smooth and clean loading bar animation.
Output
The gif below shows the progress bar animation.
Screen Transitions for ST7920 UI Navigation
Modern user interfaces feel smooth because screens do not change suddenly. Instead, they use transitions — sliding, fading, or soft switching. Even with a monochrome display like the ST7920, you can create clean and attractive page transitions using the U8g2 library.
In this section, we will create three useful transitions that you can use for menus, dashboards, or multi-page UI.
Slide Left and Slide Right Transition
A sliding transition makes the next page appear as if it is moving from one side of the screen. This is one of the most common UI effects seen in mobile apps and smart displays.
Below is the Code for Slide Left / Slide Right Page Transition
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int offset = 0;
bool nextPage = false;
void drawPage1(int x) {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(x + 10, 20, "PAGE 1");
u8g2.drawStr(x + 10, 40, "This is the first screen");
}
void drawPage2(int x) {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(x + 10, 20, "PAGE 2");
u8g2.drawStr(x + 10, 40, "Welcome to the next page");
}
void setup() {
u8g2.begin();
}
void loop() {
if (!nextPage) {
// ---- Slide Left (Page 1 → Page 2) ----
for (offset = 0; offset >= -128; offset -= 8) {
u8g2.firstPage();
do {
drawPage1(offset);
drawPage2(offset + 128);
} while (u8g2.nextPage());
delay(40);
}
nextPage = true;
delay(1000);
}
else {
// ---- Slide Right (Page 2 → Page 1) ----
for (offset = -128; offset <= 0; offset += 8) {
u8g2.firstPage();
do {
drawPage1(offset);
drawPage2(offset + 128);
} while (u8g2.nextPage());
delay(40);
}
nextPage = false;
delay(1000);
}
}Explanation
This effect creates two virtual pages.
- By shifting both pages horizontally at the same speed, one page slides out while the other slides in.
- Sliding left shows the next page. Sliding right returns to the previous page.
- The animation is smooth because each step moves only a few pixels.
Output
The gif below shows the Slide Left / Slide Right Page Transition.
Fade Effect using Gradual Clear
A fade-out effect is easy to simulate on monochrome displays. The trick is to slowly clear different parts of the screen, giving a smooth visual transition.
Below is the Code for Fade-Out Transition
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
void drawPage() {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(20, 30, "Fading Page...");
}
void setup() {
u8g2.begin();
}
void loop() {
// Draw the full page
u8g2.firstPage();
do {
drawPage();
} while (u8g2.nextPage());
delay(1000);
// ---- Gradual Fade ----
for (int i = 0; i < 64; i += 4) {
u8g2.firstPage();
do {
drawPage(); // redraw page
u8g2.setDrawColor(0); // set color to erase
u8g2.drawBox(0, i, 128, 4); // clear strip
u8g2.setDrawColor(1);
} while (u8g2.nextPage());
delay(40);
}
delay(800);
}Explanation
The page is displayed normally. Then, each loop clears a horizontal strip of the display. Because the stripping happens slowly, the page appears to fade away, line by line.
You can reverse the logic to create a fade-in effect as well.
Output
The gif below shows the Fade-Out Transition.
Smooth Page Switching Technique
If you do not want sliding or fading, you can use a gentle soft switch. This draws a small fade at the top or bottom, creating a subtle transition.
Below is the Code for Smooth Page Switch
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
void drawPageA() {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(10, 25, "This is PAGE A");
}
void drawPageB() {
u8g2.setFont(u8g2_font_6x10_tf);
u8g2.drawStr(10, 25, "This is PAGE B");
}
void setup() {
u8g2.begin();
}
void softSwitch(void (*pageA)(), void (*pageB)()) {
// Fade bottom up
for (int h = 0; h <= 64; h += 6) {
u8g2.firstPage();
do {
pageA();
u8g2.setDrawColor(0);
u8g2.drawBox(0, 64 - h, 128, h);
u8g2.setDrawColor(1);
} while (u8g2.nextPage());
delay(40);
}
// Fade-in next page
for (int h = 64; h >= 0; h -= 6) {
u8g2.firstPage();
do {
pageB();
u8g2.setDrawColor(0);
u8g2.drawBox(0, 0, 128, h);
u8g2.setDrawColor(1);
} while (u8g2.nextPage());
delay(40);
}
}
void loop() {
softSwitch(drawPageA, drawPageB);
delay(1000);
softSwitch(drawPageB, drawPageA);
delay(1000);
}Explanation
- This function clears the previous page from bottom to top.
- Then it shows the next page gradually from top to bottom.
- The effect is very smooth and soft, giving a premium UI feeling.
The transition does not move fast and does not feel abrupt, making it perfect for menu screens.
Output
The image below shows a gentle fade transition between Page A and Page B.
Practical Animation Examples for ST7920
This section brings everything together. Here, we turn animation concepts into real UI designs for the ST7920 display. You will learn how to animate a logo, make a simple clock animation, and generate a smooth waveform using the sin() function.
These examples will help you build professional-looking interfaces for your Arduino projects.
Logo Animation (Move, Scale or Reveal)
Logo animations make your project feel branded and polished. In this example, we reveal the logo by sliding it from left to right.
Below is the Code for Logo Reveal Animation
#include <U8g2lib.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
// Simple 32x16 logo bitmap (replace with your actual logo)
const unsigned char logoBitMap[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xe0, 0xff, 0x01,
0x00, 0xf8, 0xff, 0x07, 0x00, 0xee, 0xff, 0x0f, 0x00, 0xbb, 0xfd, 0x3f, 0x80, 0xed, 0x77, 0x38,
0xc0, 0xb6, 0x1d, 0x60, 0x60, 0xdb, 0x06, 0xc0, 0xb0, 0x6d, 0x03, 0x80, 0xdc, 0xb6, 0x01, 0x00,
0x74, 0xdf, 0x60, 0x40, 0xbc, 0x6f, 0x50, 0xa4, 0xd8, 0x3e, 0x70, 0xea, 0x68, 0x18, 0x10, 0x2e,
0x7e, 0x18, 0x08, 0x12, 0x77, 0x0e, 0x34, 0x09, 0x35, 0x0f, 0x92, 0x1c, 0x02, 0x06, 0xfb, 0x2e,
0x00, 0x80, 0x6d, 0x3b, 0x00, 0xc0, 0xb6, 0x0d, 0x02, 0x60, 0xdb, 0x06, 0x06, 0x90, 0x6d, 0x03,
0x1c, 0x6c, 0xb2, 0x01, 0xf8, 0xbb, 0xc9, 0x00, 0xf0, 0x7f, 0x36, 0x00, 0xe0, 0xff, 0x1d, 0x00,
0x80, 0xff, 0x07, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
int xPos = -40; // start outside screen
void setup() {
u8g2.begin();
}
void loop() {
xPos += 4;
if (xPos > 48) xPos = -40; // reset and repeat
u8g2.firstPage();
do {
u8g2.drawXBMP(xPos, 24, 32, 32, logoBitMap);
} while (u8g2.nextPage());
delay(60);
}Explanation
The logo begins off-screen at x = -40.
- It moves smoothly until it reaches the center area of the display.
- When it goes too far, the position resets and the animation repeats.
- You can replace the bitmap with your real logo and adjust movement or scaling.
Output
The gif below shows the Logo reveal effect on the display.
Simple Clock Animation
A clock animation shows how useful dynamic UI elements can be. Here, we animate the second hand of a minimal analog clock.
Below is the Code for animated Clock Example
#include <U8g2lib.h>
#include <math.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int secAngle = 0; // angle for second hand
void setup() {
u8g2.begin();
}
void loop() {
int centerX = 64;
int centerY = 32;
int radius = 20;
// second hand end point
int x = centerX + radius * cos(secAngle * 0.10472); // convert secAngle to radians
int y = centerY + radius * sin(secAngle * 0.10472);
secAngle++;
if (secAngle >= 60) secAngle = 0;
u8g2.firstPage();
do {
u8g2.drawCircle(centerX, centerY, radius);
u8g2.drawLine(centerX, centerY, x, y);
} while (u8g2.nextPage());
delay(200);
}Explanation
This code draws a static circle representing the clock face.
- Only the second hand changes — its angle updates every loop.
- To convert 60 seconds into 360 degrees, we multiply by 0.10472 radians per second.
- The result is a clean, smooth second-hand animation.
Output
The gif below shows the clock animation on the display.
Waveform Animation using sin() Function
Waveforms are perfect for audio-style displays, sensor visualization, and oscilloscopes. Using the sin() function gives you a smooth, professional curve.
Below is the Code for Live Waveform Animation
#include <U8g2lib.h>
#include <math.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
float phase = 0;
void setup() {
u8g2.begin();
}
void loop() {
u8g2.firstPage();
do {
for (int x = 0; x < 128; x++) {
float yVal = 32 + 20 * sin((x * 0.15) + phase);
u8g2.drawPixel(x, (int)yVal);
}
} while (u8g2.nextPage());
phase += 0.2; // shift waveform horizontally
if (phase > 1000) phase = 0;
delay(40);
}Explanation
- Each
xpixel is used as an input to the sine function. - The sine result determines the
ypixel position, forming a smooth wave. - By increasing phase, the wave moves left or right, creating a real-time waveform animation.
You can adjust:
- amplitude (wave height)
- frequency (wave tightness)
- speed (phase jump)
Output
The gif below shows the waveform animation on the display.
Conclusion
In this tutorial, you learned how to take the ST7920 display far beyond static images and simple text. By using the power of the U8g2 library, you created smooth scrolling text, clean animations, and modern screen transitions that bring your UI to life. These techniques give your projects a polished, professional feel, something normally seen in advanced embedded systems.
You explored horizontal and vertical scrolling, marquee banners, logo reveal effects, waveform animations, loading spinners, progress bars, and multiple styles of page transitions.
Each example helps you understand how movement works on a monochrome display and how small changes in position, timing, and redrawing can create powerful effects.
With these skills, you can now build:
- Multi-page menus
- Animated dashboards
- Branded boot screens
- Real-time data visualizers
- Interactive embedded UIs
The ST7920 may look simple, but with the right animations, it becomes a flexible display capable of delivering a rich user experience. Feel free to combine and customize these techniques to create your own style of interface.
Browse More Arduino Display Tutorials
Arduino SSD1306 OLED 0.96″ Display Guide – Show Text, Numbers & Custom Animations
Interfacing ST7735 TFT Display with Arduino – Display Text, Graphics, and Images from SD Card
Interface SH1106 I2C 1.3” OLED Display with Arduino – Full Guide with Bitmaps and Animations
How to Interface MAX7219 7 Segment Display with Arduino | Display Text, Scrolling Message, and Time
Arduino ST7920 Tutorial (128×64 LCD): Wiring, Setup, U8g2, and Text Display Guide
Arduino ST7920 Display Graphics Guide: Shapes, Icons, Bitmaps, and UI Design
ST7920 Arduino Projects Tutorial: Real-Time Graphs, Menu System, and Full Dashboard UI using U8g2
Arduino ST7920 Project Download
Info
You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.
Arduino ST7920 Animations FAQs
Yes. Hardware SPI is noticeably faster on ST7920 and improves animation smoothness. Just replace your constructor with the hardware SPI version in U8g2.
Flicker usually comes from too many draw calls. Use smaller fonts, avoid redraw-heavy graphics, or reduce frame rate slightly for stability.
Update each object’s position in the loop before drawing. Then draw everything inside a single firstPage()…nextPage() cycle.
Yes. Create the scrolling animation first, then apply transitions like slide or fade during page changes for a more polished UI.
Yes. Large or high-detail bitmaps take longer to render. Use small icons or compressed XBM graphics for smoother movement.












