Arduino Scrolling Display. Generic code you can use for scrolling any graphics display. Here the example code shows scrolling of a simulated temperature graph on an SSD1306


This is a Beginner's Guide to Arduino Scrolling Display: It provides you with template code that shows you:

  • How to scroll data on a graphics display,
  • How to map the input values to a part of the screen,
  • Exactly how circular buffers are used to achieve scrolling,
  • How to blank the left of the graph, that doesn't have valid data yet.

Arduino scrolling display in caseThe specific device used here is the SSD1306, but you can use different displays by changing parameters at the start of the program e.g. screen width and height, output width and height etc.

Introduction

Welcome to this beginner's guide on creating an Arduino scrolling display using the SSD1306 OLED display. The SSD1306 is a popular choice for small, high-contrast displays, and it's perfect for projects that require a clear and readable output, even if it is a little on the small side (it's just under an inch wide)!

In this tutorial, we'll walk you through the process of setting up and programming an Arduino to create a scrolling display, making use of the SSD1306 graphics capabilities for the scrolling graph.

We'll cover everything you need to know to get started, including the required components, circuit connections, and the code needed to create the scrolling display to show parameter variation over time.

A useful feature of the code is that the graph occupies part of the screen allowing you to place text above the graph - so you can display the current temperature for instance.

Let's dive in and bring your Arduino project to life with the SSD1306 OLED display!

What is an SSD1306?

arduino scrolling display - how to do it easily with code examples

The SSD1306 is a monochrome OLED display driver that is widely used in small display modules. It supports both I2C and SPI communication protocols, making it versatile and easy to integrate with microcontrollers like the Arduino. Here we are using the display set up in I2C mode (that means a four pin connection). The display is known for its high contrast and low power consumption, making it ideal for battery-powered projects.

The Adafruit_SSD1306 library simplifies the process of controlling the display, allowing you to create text, graphics, and animations with ease. Whether you're displaying sensor data, creating a user interface, or just experimenting with graphics, the SSD1306 is a great choice for your Arduino projects.

Getting started with an Arduino Scrolling display

Required Components

  • Arduino Uno or compatible board
  • SSD1306 OLED display (I2C mode)
  • Solderless Breadboard
  • Jumper wires
  • USB cable for programming the Arduino

Circuit Diagram

The layout diagram shows how to place components on the breadboard.

- Connect the VCC pin of the SSD1306 display to the 5V pin on the Arduino.
- Connect the GND pin of the display to the GND pin on the Arduino.
- Connect the SCL pin of the display to the A5 pin on the Arduino (SCL).
- Connect the SDA pin of the display to the A4 pin on the Arduino (SDA).

uno and SSD1306 connections for arduino scrolling display demo
Diagram using fritzing

Schematic Diagram

uno and SSD1306 schematic diagram for arduino scrolling display demo

Diagram using fritzing

Libraries Needed

The library you need to install is "Adafruit_SSD1306".

Installing an Arduino Library with IDE

Install the library as follows:

1st method:

    Click the menu bar and follow the menu items:

Sketch-->Include Library-->Manage Libraries...

2nd method:

    Click the ICON on the left that looks like a set of books.
The library manager appears on the left of the screen.

In the search box type "Adafruit_SSD1306". Now click the install button.

This library does depend on others, so answer yes to installing dependent libraries.

Arduino Scrolling Display Example Sketch

This code displays a simulated temperature reading and shows a scrolling graph with new values appearing on the right side.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

const int GRAPH_HEIGHT = 40;
const int GRAPH_TOP = 20;
int tempValues[SCREEN_WIDTH];
int currentIndex = 0;
int lastTemp = 250; // Starting temperature (25.0°C * 10)

void setup() {
  Serial.begin(115200);
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 FAILED startup");
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("Temperature Monitor");
  display.display();
  delay(1000);

   // Initialize tempValues with an invalid temperature
  for (int i = 0; i < SCREEN_WIDTH; i++) {
    tempValues[i] = -1000;  // Use -1000 to indicate no valid reading yet
  }
}

void loop() {
  int temperature = simulateTemperature();
  updateGraph(temperature);
  displayTemperature(temperature);
  display.display();
  delay(300);
}

int simulateTemperature() {
  // Generate a small random change
  int change = random(-10, 10); //  (-1, 2)// -0.1 to 0.1 degree change
  lastTemp += change;
 
  // Keep temperature within a realistic range
  if (lastTemp < 200) lastTemp = 200;
  if (lastTemp > 300) lastTemp = 300;
 
  return lastTemp;
}

void updateGraph(int temperature) {
  int y1,y2;
  tempValues[currentIndex] = temperature;
  currentIndex = (currentIndex + 1) % SCREEN_WIDTH;
 
  display.fillRect(0, GRAPH_TOP, SCREEN_WIDTH, GRAPH_HEIGHT, SSD1306_BLACK);
 
  for (int i = 0; i < SCREEN_WIDTH - 1; i++) {
    int index = (currentIndex + i) % SCREEN_WIDTH;
    int nextIndex = (index + 1) % SCREEN_WIDTH;

    // Only draw if both points have valid temperatures
    if (tempValues[index] != -1000 && tempValues[nextIndex] != -1000) { // Keep blank until temps recorded
      y1 = map(tempValues[index], 200, 300, GRAPH_TOP + GRAPH_HEIGHT - 1, GRAPH_TOP);
      y2 = map(tempValues[nextIndex], 200, 300, GRAPH_TOP + GRAPH_HEIGHT - 1, GRAPH_TOP);
      display.drawLine(i, y1, i+1, y2, SSD1306_WHITE);     
    }
  }  // for scr width
}

void displayTemperature(int temperature) {
  display.fillRect(0, 0, SCREEN_WIDTH, 16, SSD1306_BLACK);
  display.setCursor(0, 0);
  display.print("Temp: ");
  display.print(temperature / 10);
  display.print(".");
  display.print(temperature % 10);
  display.print(" C");
}

Sketch: rolling-temp-simlation.ino

Short Code Explanation

  • Include Libraries: Includes the libraries for the SSD1306 display and I2C.
  • Define Constants: Sets the screen width, height, and reset pin. Here the reset pin is set to -1 (as the display I have does not have a reset pin).
  • Initialize Display: Sets up the display with screen dimensions and I2C address.
  • Setup Function: Initializes Serial, display and sets up the initial display text.
  • Loop Function: Simulates temperature changes, updates the graph and displays the temperature.
  • Simulate Temperature: Generates random temperatures within a specified range.
  • Update Graph: Updates the graph with the new temperature values.
  • Display Temperature: Displays the current temperature on the screen.

Detailed Code Explanation

The code begins by including the necessary libraries: `Wire.h` for I2C communication, `Adafruit_GFX.h` for graphics functions, and `Adafruit_SSD1306.h` for controlling the SSD1306 display. The display is initialized with a width of 128 pixels and a height of 64 pixels, and the reset pin is set to -1, indicating that no reset pin is used.

In the `setup` function, the serial communication is initialized at a baud rate of 115200. The display is then initialized with the `display.begin` function, which sets the display to use the I2C address 0x3C. The display is cleared, and the initial text "Temperature Monitor" is displayed.

The `loop` function simulates temperature changes using the `simulateTemperature` function, which generates random changes within a specified range. It is arranged so that the new temperature is not too different the old temperature - otherwise the display just looks random.

The `updateGraph` function updates the graph with the new temperature values, and the `displayTemperature` function displays the current temperature on the screen. The display is updated every 300 milliseconds.

The `simulateTemperature` function generates a small random change in temperature keeping the graph looking real. The `updateGraph` function updates the graph by filling a rectangle with a black background and drawing lines to represent the temperature values and the `displayTemperature` function displays the current temperature on the screen.

Arduino scrolling display: Uploading the Code

There are a few steps to uploading the code using the Arduino IDE:

  • Connect the Arduino Uno to the PC with a USB cable.
  • Select the Arduino Uno hardware.
  • Open a new sketch.
  • Paste the code above into the new page (overwrite everything).
  • Press the upload button (right arrow at top).

You can find a more detailed tutorial on the Arduino IDE page.

Testing the Circuit

To test the circuit, connect the Arduino to your computer and upload the code. Once the code is uploaded, the display should show the initial text "Temperature Monitor" and start displaying the simulated temperature values and graph. If everything is working correctly, you should see the temperature values updating and the graph scrolling across the screen. If not check your I2C connections - right way round?

Conclusions

In this beginner's guide, we've covered how to set up and program an Arduino scrolling display using the SSD1306 OLED display - but remember - you can apply this code to any graphics display.

By following the steps outlined in this tutorial, you can create a dynamic and visually appealing display for your projects. The SSD1306 graphics capabilities, combined with the Adafruit_SSD1306 library, make it easy to create text, graphics, and animations on your Arduino.

Whether you're a hobbyist looking to add a new feature to your project or a beginner just starting with Arduino, this guide provides a solid foundation for working with the SSD1306 display. Experiment with different graphics and text to see what you can create, and don't hesitate to explore more advanced features as you become more comfortable with the basics.

Happy tinkering, and enjoy bringing your Arduino projects to life with the SSD1306 OLED display!

Arduino scrolling display zoom out

More Advanced Details

Blanking the left of the graph

When you first use code like this, the graph values are initialised to zero, which results in a line at the bottom of the graph. This happens because the initial values in the tempValues array are set to zero, and the map function translates these zero values to the bottom of the display. As a result, the graph starts with a horizontal line at the bottom.

To avoid this, the code includes a mechanism to "blank" or clear the left side of the graph until valid temperature readings are recorded. This is achieved by initializing the tempValues array with an invalid value (e.g., -1000) and checking for these invalid values before drawing the graph. This is a so called magic number - it is pulled out of a hat and could be anything (as long as it is not a valid temperature). It will only work if the iniaitlisation and loop code use the same number.

Here's how it works:

// Initialize tempValues with an invalid temperature
for (int i = 0; i < SCREEN_WIDTH; i++) {
  tempValues[i] = -1000;  // Use -1000 to indicate no valid reading yet
}

The tempValues array is initialized with -1000, an invalid temperature value, to indicate that no valid readings have been recorded yet.

The associated code that updates the graph is:

for (int i = 0; i < SCREEN_WIDTH - 1; i++) {
  int index = (currentIndex + i) % SCREEN_WIDTH;
  int nextIndex = (index + 1) % SCREEN_WIDTH;

  // Only draw if both points have valid temperatures
  if (tempValues[index] != -1000 && tempValues[nextIndex] != -1000) { // Keep blank until temps recorded
    y1 = map(tempValues[index], 200, 300, GRAPH_TOP + GRAPH_HEIGHT - 1, GRAPH_TOP);
    y2 = map(tempValues[nextIndex], 200, 300, GRAPH_TOP + GRAPH_HEIGHT - 1, GRAPH_TOP);
    display.drawLine(i, y1, i+1, y2, SSD1306_WHITE);   
  }
}  // for scr width
  • Before drawing each line segment of the graph, the code checks if both the current and next temperature values are valid (i.e., not equal to -1000).

  • If either value is invalid, the line segment is not drawn, effectively "blanking" that part of the graph.

This ensures that the graph only shows valid temperature readings, preventing the initial horizontal line at the bottom, and providing a cleaner, more accurate visual representation of the data.

How the scrolling code works

The first idea you will probably have when thinking about scrolling a display horizontally is a stack. You would represent each position on the x axis of the display as an element of the stack. Adding a value to the stack (rightmost position) would represent the right of the screen. You then shift all the data down by one position loosing the last value. Then you print out the stack to the screen from last value to first value.

The problem with this is that moving all that data around takes time - so is there a better way?

The answer is yes: pointers (although in the code above index values are used - you could use pointers as an alternative). The idea is that instead of moving data around you only move a pointer to the data (or index value).

The problem now is how do you know where your start and end value, begin and end. Also where do you start printing out data so that the left of the screen has the oldest data - and how do you keep it all under control?

Circular buffers

The key idea is to use a circular buffer

A circular buffer, or ring buffer, is a fixed-size buffer that wraps around when it reaches the end. This means that new data overwrites the oldest data in a continuous loop.

How to wrap a value

So how do you do the wrap around without a lot of fuss?

You use the modulo operator '%' which gives the remainder of one integer divided by another.

In the code below the variable currentIndex stores the location that will be udpated with the newest temperature value (into the array tempValues)

the next line:

currentIndex = (currentIndex + 1) % SCREEN_WIDTH;

moves the current index forwards but uses the modulo operator to create the circular operation. For example

if currentIndex has a value of 100 and we have SCREEN_WIDTH = 128 then:

100 % 128 is 100 as the quotient is 0 (128/100) and the remainder is 100

...but when currentIndex has a value of 128:

128 % 128 is zero, since the quotient is 1 (128/128) and the remainder is 0.

This is ideal for arrays, since arrays start from zero and have n-1 elements. In this case tempValues has index values from 0 to 127. In this way the index is kept cycling within the confines of the array.

How to output the graph

In the code below the following lines output the oldest value 1st, by again employing the modulo operator.

Earlier code:

tempValues[currentIndex] = temperature;
currentIndex = (currentIndex + 1) % SCREEN_WIDTH;

So, the currentIndex indexes into the tempValues array to insert the newest temperature value at the currentIndex position. Then currentIndex is increased with modulo wrap.

At this point currentIndex has moved one to the right, and so, points to the oldest value in the array. This is the value to start printing from(at the left most position of the display - when i is zero - below). By progressing through the array and wrapping the index using the modulo operator all the values are output to the screen with oldest at the left hand side and the newest to the right.

for (int i = 0; i < SCREEN_WIDTH - 1; i++) {
    int index = (currentIndex + i) % SCREEN_WIDTH;

By using a circular buffer, the code efficiently manages the temperature data and updates the graph without the need for costly data shifting operations. This results in smooth and responsive performance, even with limited computational resources.



Written by John Main who has a degree in Electronic Engineering.

Note: Parts of this page were written using AI as a research assistant.




Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.



Privacy Policy | Contact | About Me

Site Map | Terms of Use