ST7920 Arduino Projects: Build Real-Time Graphs, Menus, and a Complete UI Dashboard
This is the fourth tutorial in our ST7920 Arduino series.
In the first three tutorials, we covered the ST7920 wiring, text mode, graphics mode, and animations using the U8g2 library. Now, in this final part, we bring everything together and build real projects.
In this guide, you will learn how to create a real-time graph, a clean menu system, and a complete dashboard UI. All examples use simple code, clear steps, and short explanations to keep the readability high.
By the end, you will be able to design full UI systems for sensors, dashboards, meters, small devices, and embedded projects using the ST7920 graphical LCD.
Prerequisites:
You must go through the previous 2 parts of this mini series:

Real-Time Graph on ST7920 Display (Live Sensor Plotting)
In this section, we build a clean real-time sensor graph on the ST7920 128×64 display using the U8g2 library. We will read values from a potentiometer or temperature sensor, plot them on the screen, and create a smooth scrolling graph.
You will also see how to draw optional gridlines, making the graph easy to read. This part sets the foundation for the final dashboard UI.
Wiring and Setup for Sensor Input
We only need a simple analog sensor for this demo.
You can use:
- A potentiometer (easy for testing), or
- A temperature sensor like LM35 or NTC
The image below shows the Wiring Example (with Potentiometer)
The connections are explained in the table below:
| Component | Arduino Pin |
|---|---|
| Potentiometer VCC | 5V |
| Potentiometer GND | GND |
| Potentiometer Output | A0 |
| ST7920 VCC | 5V |
| ST7920 GND | GND |
| ST7920 E | D13 |
| ST7920 R/W | D11 |
| ST7920 RS | D10 |
| ST7920 PSB | GND (for SPI mode) |
| ST7920 RST | D8 |
This follows the same wiring style used in your previous tutorials for U8g2 + ST7920 SPI mode.
Code to Read Sensor and Update Graph (Scrolling Plot)
Below is the complete working code for a real-time scrolling graph. The graph scrolls from right to left while plotting live analog values.
#include <U8g2lib.h>
#include <Arduino.h>
// ST7920 SPI Constructor (same as in previous tutorials)
U8G2_ST7920_128X64_F_SW_SPI u8g2(
U8G2_R0,
/* clock=*/ 13,
/* data=*/ 11,
/* cs=*/ 10,
/* reset=*/ 8
);
// Graph settings
const int SENSOR_PIN = A0;
int graphData[128]; // Buffer for 128 graph points
int indexPos = 0;
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tr);
// Initialize graph buffer
for (int i = 0; i < 128; i++) {
graphData[i] = 32;
}
}
void loop() {
// Read analog sensor (0–1023)
int raw = analogRead(SENSOR_PIN);
// Map to ST7920 graph height (0–63)
int y = map(raw, 0, 1023, 63, 0);
// Add new value into buffer
for (int i = 0; i < 127; i++) {
graphData[i] = graphData[i + 1];
}
graphData[127] = y;
// Draw Graph
u8g2.firstPage();
do {
// Optional gridlines
for (int i = 0; i < 128; i += 16) {
u8g2.drawLine(i, 0, i, 63);
}
for (int j = 0; j < 64; j += 16) {
u8g2.drawLine(0, j, 127, j);
}
// Plot graph
for (int x = 0; x < 127; x++) {
u8g2.drawLine(x, graphData[x], x + 1, graphData[x + 1]);
}
// Print current sensor value
u8g2.setCursor(2, 10);
u8g2.print("Value: ");
u8g2.print(raw);
} while (u8g2.nextPage());
delay(40); // controls graph scrolling speed
}
Explanation
- We use a 128-element array to store graph points.
- Each loop:
- We read the analog sensor.
- Convert it to a height between 0 and 63 pixels.
- Shift the array left to create the scrolling effect.
- Add the new value at the end.
- U8g2 draws:
- Optional gridlines
- The smooth line graph
- A small text label shows the live sensor value.
Output: Real-Time Moving Graph on ST7920
The video below shows how the real-time graph appears on the ST7920 display.
You can see a smooth line graph scrolling from right to left, with gridlines in the background and the current sensor value printed at the top. The graphs updates as per the potentiometer’s movement.
Simple Menu System using ST7920 and Arduino
Now we move to a basic UI menu system on the ST7920 display. This part helps you create a clean multi-screen interface with Home, Settings, and Info pages. You can navigate the menu using push buttons or a rotary encoder. The selected item highlights automatically, and we also add a simple transition animation when switching screens.
This menu structure is important because we will use similar logic in the final dashboard project.
Button / Encoder Wiring for Menu Navigation
You can use either:
- Two push buttons: UP and DOWN
- Or a rotary encoder: Rotate to scroll, button to select
For simplicity, this example uses two buttons + one select button.
The image below shows the Button Wiring with Arduino.
The connections are explained in the table below:
| Button | Arduino Pin | Notes |
|---|---|---|
| UP | 2 | Pull-down or INPUT_PULLUP |
| DOWN | 3 | Pull-down or INPUT_PULLUP |
| SELECT | 4 | Opens the selected screen |
If using INPUT_PULLUP, connect the other pin of the button to GND. The ST7920 wiring remains identical to previous tutorials.
Code for Multi-Screen Menu with Highlighted Selection
Below is the complete menu system. It shows three items and highlights the currently selected one.
#include <U8g2lib.h>
#include <Arduino.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(
U8G2_R0,
/* clock=*/ 13,
/* data=*/ 11,
/* cs=*/ 10,
/* reset=*/ 8
);
// Button pins
const int UP_BTN = 2;
const int DOWN_BTN = 3;
const int SELECT_BTN = 4;
// Menu Settings
int menuIndex = 0;
const int MENU_ITEMS = 3;
String menuList[MENU_ITEMS] = {"Home", "Settings", "Info"};
bool inSubMenu = false;
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tr);
pinMode(UP_BTN, INPUT_PULLUP);
pinMode(DOWN_BTN, INPUT_PULLUP);
pinMode(SELECT_BTN, INPUT_PULLUP);
}
void drawMenu() {
for (int i = 0; i < MENU_ITEMS; i++) {
int y = 16 + i * 14;
if (i == menuIndex) {
u8g2.drawBox(0, y - 10, 128, 12);
u8g2.setDrawColor(0);
u8g2.setCursor(4, y);
u8g2.print(menuList[i]);
u8g2.setDrawColor(1);
} else {
u8g2.setCursor(4, y);
u8g2.print(menuList[i]);
}
}
}
void drawSubPage(int page) {
u8g2.setCursor(10, 32);
if (page == 0) u8g2.print("Home Screen");
if (page == 1) u8g2.print("Settings Page");
if (page == 2) u8g2.print("Info Page");
u8g2.setCursor(10, 50);
u8g2.print("Press SELECT to go back");
}
void loop() {
if (!inSubMenu) {
// Handling button presses
if (!digitalRead(UP_BTN)) {
menuIndex--;
if (menuIndex < 0) menuIndex = MENU_ITEMS - 1;
delay(150);
}
if (!digitalRead(DOWN_BTN)) {
menuIndex++;
if (menuIndex >= MENU_ITEMS) menuIndex = 0;
delay(150);
}
if (!digitalRead(SELECT_BTN)) {
inSubMenu = true;
delay(200);
}
// Draw menu
u8g2.firstPage();
do {
drawMenu();
} while (u8g2.nextPage());
}
else {
// Draw selected page
u8g2.firstPage();
do {
drawSubPage(menuIndex);
} while (u8g2.nextPage());
// Exit submenu
if (!digitalRead(SELECT_BTN)) {
inSubMenu = false;
delay(200);
}
}
}Explanation
- Three menu items: Home, Settings, Info
- We highlight the active menu using a dark bar
- Button presses change the
menuIndex - SELECT opens a new page
- Inside a submenu, pressing SELECT again returns to the main menu
- The code keeps navigation simple and smooth
This minimal menu system can be expanded easily for complex UI projects.
Simple Page Transition Animation
Here is a small animation added between menu -> page transitions.
Replace inside the if (!digitalRead(SELECT_BTN)) block:
for (int i = 0; i < 128; i += 8) {
u8g2.firstPage();
do {
u8g2.drawBox(0, 0, i, 64);
} while (u8g2.nextPage());
delay(10);
}
inSubMenu = true;This creates a clean left-to-right slide animation.
Output: Working Menu System on ST7920
The video below shows how the menu system appears on the ST7920.
You can see three menu items with a highlighted selection bar. Pressing UP or DOWN changes the active item, and pressing SELECT opens the chosen page with a smooth animation.
Build a Final Dashboard UI with Icons, Data and Animations
In this section, we combine everything you learned in the previous three ST7920 tutorials. We now create a clean dashboard screen that includes text, icons, sensor values, a small graph, and light animations.
This is the same style used in compact embedded devices such as meters, controllers and small handheld gadgets. The goal is to build a polished UI that feels complete and responsive.
Preparing Icons and Fonts for the Dashboard
We will use small bitmap icons for the battery, WiFi, and a generic temperature symbol. The ST7920 works perfectly with 1-bit monochrome bitmaps, and U8g2 can draw them using drawXBMP().
Below are three example icons you can directly use.
Battery Icon (16×8)
const unsigned char icon_battery[] U8X8_PROGMEM = {
0x00, 0xc0, 0xfe, 0xbf, 0x0a, 0xbd, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0xbd, 0xfe, 0xbf, 0x00, 0xc0
};WiFi Icon (16×12)
const unsigned char icon_wifi[] U8X8_PROGMEM = {
0xff, 0xff, 0x7f, 0xfe, 0x8f, 0xf1, 0xf7, 0xef, 0x1b, 0xd8, 0xed, 0xb7, 0xf6, 0x6f, 0x1b, 0xd8,
0xeb, 0xd3, 0xf7, 0xef, 0x1f, 0xf8, 0xdf, 0xfb
};Temperature Icon (8×8)
const unsigned char icon_temp[] U8X8_PROGMEM = {
0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x3C, 0x18
};Fonts
We continue using clear, readable fonts:
u8g2.setFont(u8g2_font_6x10_tr); // Labels and data
u8g2.setFont(u8g2_font_5x8_tr); // Small textUse larger fonts sparingly because the ST7920 resolution is limited.
Drawing the Dashboard Layout (Text + Icons)
Below is the full dashboard layout code.
The screen includes:
- Icons (Battery + WiFi)
- Temperature reading
- Humidity reading
- A small live graph at the bottom
- A header bar for style
#include <U8g2lib.h>
#include <Arduino.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(
U8G2_R2,
/* clock=*/13,
/* data=*/11,
/* cs=*/10,
/* reset=*/8
);
const unsigned char icon_battery[] U8X8_PROGMEM = {
0x00, 0xc0, 0xfe, 0xbf, 0x0a, 0xbd, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0xbd, 0xfe, 0xbf, 0x00, 0xc0
};
const unsigned char icon_wifi[] U8X8_PROGMEM = {
0xff, 0xff, 0x7f, 0xfe, 0x8f, 0xf1, 0xf7, 0xef, 0x1b, 0xd8, 0xed, 0xb7, 0xf6, 0x6f, 0x1b, 0xd8,
0xeb, 0xd3, 0xf7, 0xef, 0x1f, 0xf8, 0xdf, 0xfb
};
const unsigned char icon_temp[] U8X8_PROGMEM = {
0x18,
0x18,
0x18,
0x18,
0x7E,
0x7E,
0x3C,
0x18
};
// Graph Data
int graphData[50];
void setup() {
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tr);
for (int i = 0; i < 50; i++) graphData[i] = 32;
}
void updateGraph(int value) {
for (int i = 0; i < 49; i++) {
graphData[i] = graphData[i + 1];
}
graphData[49] = value;
}
void drawDashboard(int temp, int hum, int wifi, int batt) {
u8g2.firstPage();
do {
// Header Bar
u8g2.drawBox(0, 0, 128, 12);
u8g2.setDrawColor(0); // Invert text on header
u8g2.setCursor(4, 10);
u8g2.print("DASHBOARD");
u8g2.setDrawColor(1);
// Icons
u8g2.drawXBMP(110, 2, 16, 8, icon_battery);
u8g2.drawXBMP(90, 0, 16, 12, icon_wifi);
// Temperature
u8g2.drawXBMP(4, 20, 8, 8, icon_temp);
u8g2.setCursor(16, 27);
u8g2.print("Temp: ");
u8g2.print(temp);
u8g2.print(" C");
// Humidity
u8g2.setCursor(16, 40);
u8g2.print("Hum : ");
u8g2.print(hum);
u8g2.print(" %");
// Graph Label
u8g2.setCursor(4, 53);
u8g2.print("History:");
// Draw Live Graph
for (int x = 0; x < 49; x++) {
u8g2.drawLine(65 + x, graphData[x], 65 + x + 1, graphData[x + 1]);
}
} while (u8g2.nextPage());
}
void loop() {
int temp = random(20, 35);
int hum = random(40, 75);
// Map temperature to graph height
int g = map(temp, 20, 35, 60, 45);
updateGraph(g);
drawDashboard(temp, hum, 1, 1);
delay(300);
}Explanation
- A header bar gives the UI a clean look.
- Battery and WiFi icons appear at the top right.
- Temperature and humidity values show on the left side.
- A small live graph is drawn on the right side.
- Values are updated every 300 ms for a dynamic feel.
- The graph slowly scrolls, just like in the previous section.
This creates a compact but visually appealing dashboard UI.
Adding Graph + Status Indicators (Battery, WiFi, Sensors)
Battery
Instead of static icon display, you can animate battery fill:
int level = map(batt, 0, 100, 2, 12);
u8g2.drawBox(112, 3, level, 4);WiFi Indicator
You can animate WiFi bars:
if (wifi > 0) u8g2.drawLine(95, 12, 95, 8);
if (wifi > 30) u8g2.drawLine(98, 12, 98, 6);
if (wifi > 70) u8g2.drawLine(101, 12, 101, 4);Sensor Data
Real sensors such as DHT11 / DHT22 / LM35 / MPU6050 can easily replace the random() values.
Output : Final Dashboard Screen
The video below shows the final dashboard running on the ST7920 display.
You can see:
- A bold header
- Clean icons
- Live temperature and humidity readings
- A moving graph on the right side
- Smooth updates for battery and WiFi status
This UI looks professional and can be used in weather stations, power monitors, IoT devices, or any compact embedded project.
Complete Project – Full ST7920 UI System (Menu + Dashboard + Graph)
Now it’s time to bring everything together. In this part, we build the complete ST7920 UI system using the U8g2 library. This final project includes the main menu, dashboard screen, live graph screen, and system info page. All screens switch smoothly, and the UI shows real-time sensor values.
Project Wiring Diagram and Flow
We use the same ST7920 wiring as in earlier tutorials, along with:
- Three push buttons : Up, Down, Select
- Potentiometer : sensor input
- Optional DHT11/DHT22 : for temperature and humidity
- Arduino UNO / Nano : controller
The image below shows the complete wiring diagram for this project.
UI Flow:
Home Menu
├── Dashboard Screen
├── Live Graph Screen
└── System Info Screen- Buttons move between menu items.
- Select button opens the highlighted screen.
- Each screen updates in real time.
Full Code for the Complete UI System
Below is the full working code for all screens and navigation:
#include <U8g2lib.h>
#include <Wire.h>
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, 13, 11, 10, 8);
int btnUp = 2;
int btnDown = 3;
int btnSelect = 4;
int potPin = A0;
int menuIndex = 0;
int currentScreen = 0;
// 0 = Menu, 1 = Dashboard, 2 = Graph, 3 = Info
// ----- Graph Data -----
const int graphWidth = 100;
int graphData[100];
int graphPos = 0;
// ----- Debounce -----
bool readButton(int pin) {
if (!digitalRead(pin)) {
delay(80);
if (!digitalRead(pin)) return true;
}
return false;
}
void setup() {
u8g2.begin();
pinMode(btnUp, INPUT_PULLUP);
pinMode(btnDown, INPUT_PULLUP);
pinMode(btnSelect, INPUT_PULLUP);
for (int i = 0; i < graphWidth; i++) graphData[i] = 32;
}
// ----- Draw Menu -----
void drawMenu() {
const char* items[3] = {"Dashboard", "Live Graph", "System Info"};
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.setCursor(10, 12);
u8g2.print("MAIN MENU");
for (int i = 0; i < 3; i++) {
if (i == menuIndex) {
u8g2.drawBox(0, 20 + i*15, 128, 14);
u8g2.setDrawColor(0);
u8g2.setCursor(5, 31 + i*15);
u8g2.print(items[i]);
u8g2.setDrawColor(1);
} else {
u8g2.setCursor(5, 31 + i*15);
u8g2.print(items[i]);
}
}
u8g2.sendBuffer();
}
// ----- Dashboard Screen -----
void drawDashboard() {
int sensor = analogRead(potPin);
float value = map(sensor, 0, 1023, 0, 100);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.setCursor(5, 12);
u8g2.print("DASHBOARD");
u8g2.setCursor(5, 30);
u8g2.print("Sensor: ");
u8g2.print(value);
u8g2.drawFrame(80, 40, 40, 20);
int bar = map(value, 0, 100, 0, 38);
u8g2.drawBox(81, 41, bar, 18);
u8g2.sendBuffer();
}
// ----- Graph Screen -----
void updateGraph() {
int sensor = analogRead(potPin);
int y = map(sensor, 0, 1023, 60, 5);
graphData[graphPos] = y;
graphPos = (graphPos + 1) % graphWidth;
}
void drawGraph() {
updateGraph();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.setCursor(5, 12);
u8g2.print("LIVE GRAPH");
for (int i = 0; i < graphWidth - 1; i++) {
int x1 = i + 14;
int y1 = graphData[(graphPos + i) % graphWidth];
int x2 = x1 + 1;
int y2 = graphData[(graphPos + i + 1) % graphWidth];
u8g2.drawLine(x1, y1, x2, y2);
}
u8g2.sendBuffer();
}
// ----- Info Screen -----
void drawInfo() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_6x13_tf);
u8g2.setCursor(5, 12);
u8g2.print("SYSTEM INFO");
u8g2.setCursor(5, 30);
u8g2.print("ST7920 GLCD");
u8g2.setCursor(5, 45);
u8g2.print("Demo UI Project");
u8g2.sendBuffer();
}
void loop() {
// MENU NAVIGATION
if (currentScreen == 0) {
if (readButton(btnUp)) menuIndex = (menuIndex + 2) % 3;
if (readButton(btnDown)) menuIndex = (menuIndex + 1) % 3;
if (readButton(btnSelect)) currentScreen = menuIndex + 1;
drawMenu();
}
// DASHBOARD
else if (currentScreen == 1) {
drawDashboard();
if (readButton(btnSelect)) currentScreen = 0;
}
// LIVE GRAPH
else if (currentScreen == 2) {
drawGraph();
if (readButton(btnSelect)) currentScreen = 0;
}
// SYSTEM INFO
else if (currentScreen == 3) {
drawInfo();
if (readButton(btnSelect)) currentScreen = 0;
}
}
Output : Final Multi-Screen UI Project on ST7920
The video below shows the complete UI system running on the ST7920 display.
You can see:
- The main menu with a highlighted selection
- A clean dashboard with live sensor data fetched from the potentiometer
- A moving graph that updates in real time
- A simple system info screen
This final setup gives you a full mini UI framework for the ST7920.
Conclusion: What You Can Build Next
You have now reached the end of this fourth ST7920 tutorial.
Throughout this series, you learned how to work with the display, draw graphics, create animations, build a menu system, plot a real-time graph, and design a full dashboard UI.
These skills give you everything you need to build polished and functional interfaces on the ST7920.
Now that you understand the full workflow, here are some ideas you can explore next:
- Create a mini control panel for your DIY projects
- Build a weather dashboard with temperature, humidity, and trend graphs
- Design a smart home status screen with multiple pages
- Make a portable sensor monitor with battery and WiFi indicators
- Develop a game-style interface with icons and small animations
With the U8g2 library and the techniques you learned, the ST7920 can be used for many creative and useful projects. This tutorial completes the UI foundation — from here, you can start designing your own custom screens and full user interfaces.
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
Arduino ST7920 Graphics Guide: How to Create Scrolling Text, Animations and Page Transitions (U8g2)
Arduino ST7920 UI Project Download
Info
You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.
Arduino ST7920 UI Project FAQs
Yes. Any analog sensor like LDR, soil moisture, or gas sensors will work. Just adjust the mapping range if needed.
You can add many screens. The limit is mostly code size and how you manage navigation logic.
Yes, but you must save the values in an array or external memory. The display only shows what you draw, so history must be stored manually.
Yes, heavy animations can reduce frame rate. Keep animations simple, like sliding or fading with small steps.
Yes, HW SPI works and is faster. You only need to change the constructor and match the hardware SPI pins for your board.



