Zonnestroompanelen in Nederland

duurzaamheid achter de meter

(38) Arduino 128*64 Liquid Crystal Display ST7920 test bench

Floris Wouterlood – May 8, 2020

Displays that use liquid crystal technology (LCDs) were introduced in the 1970’s. LCD technology can therefore be considered ‘mature’, that is: cheap, universally available, and being applied in all kind of electronic gear. In the Arduino realm most widespread are 16×2 and 20×4 character LCDs based on the Hitachi HD44780U controller. These LCD’s have very primitive graphics, that is one may program with a 20×4 LCD up to four horizontal, 20-character wide ‘bars’ or 20 vertical, 4-character high ‘bars’.

Figure 1: Design of the 128*64 LCD test bench. The board is a 80×120 mm double-sided universal PCB. Two parallel 15-pin female pin headers accommodate an Arduino Nano. A female 20-pin header accommodates a 128*64 LCD breakout unit. Two additional, female 8-pin headers are added to make some of the Nano’s free pins available for input or output. Serial communication is supported by a ‘TX-RX’ female pin header. Correct functioning of the Nano is reported by the red led (wired to Nano pin D2). Two male 4-pin headers (indicated in red and black) supply 5V and GND to projects. The potentiometer controls contrast of the LCD character pixels via pin V0 of the LCD.

Creative programmers exploit their ingenuity with 16×2 or 20×4 LCDs to make their own graphic expressions exploiting the 8×5 pixel space that is available for each individual character. Much, much more than rows of filled character spaces is offered by the 128*64 pixel LCD. In fact this display is the predecessor of the popular 128*64 OLED display. Most widely used are 128*64 LCDs driven by ST7920 controller chips. LCDs based on this chip can in Arduino be programmed, just like OLEDs, using the versatile <u8glib.h> library created by Olikraus. U8glib offers graphical functions like bars, rectangles, triangles, circles and so forth. Because it is possible to program individual pixels (monochrome) via the ST7920, images can be displayed on 128*64 LCDs.

Figure 2: The PCB with its main pin headers, potentiometer, led and resistors. The ‘support’ is just what it is: it adds mechanical stability to the LCD breakout board while it has no electronic function.

To circumvent the usual preparations one has to make when ideas pop up to experiment with an 128*64 breakout LCD: dig up a breadboard, do proper wiring, add resistors, check pin selection and so forth, I kept for several years a ready-to-go configuration in stand-by: a contraption of two breadboards strung with jumper wires, resistors, leds, and with the LCD breakout board. However, usually this contraption would not work immediately because of loose or defect wiring, malfunctioning contacts and so forth. A more permanent, ‘hard’ workbench for the 128*64 LCD was a desirable device. This ‘hard’ bench should be multi-purpose: a stable platform for my 128*64 LCD and simultaneously suitable to test sensors, devices and communication. This would offer the stable environment wherein it is possible to concentrate on developing Arduino sketches. A similar bench has been designed and constructed recently* to test 16×2 and 20×4 LCDs; this prompted me to construct also a permanent bench for the 128*64 LCD.
All the parts of the 128*64 Arduino test bench are positioned on a 80×120 universal prototyping board (PCB).

Required electronic parts

  • 1x 80×120 mm double-sided universal Printed Circuit Board (PCB)
  • 2x 15 pin female pin header: ‘Nano support pin headers’
  • 1x 20 pin female pin header: ‘128*64 LCD pin header’
  • 2x 8 pin female pin header: ‘test bench pin header’
  • 1 x 2 pin female pin header: ‘TX-RX header’
  • 2x 4 pin male pin header: ‘power and GND pin headers’
  • 1x potentiometer 10 kΩ
  • 2x resistor 220Ω
  • 1x led
  • 4 nylon spacers with nylon bolts and screws
  • 1x Arduino Nano
  • wire

Wiring and pin connectivity
A wiring diagram is presented in figure 3. One set of wiring is between the Nano and the display pin header. Other sets of wiring exists between the Nano, the two test bench pin headers and the TX-RX pin header, and finally there is wiring to the external 5V and GND power pins and to a led connected to pin D2 of the Nano.

Nano to display pin header
LCDs for the Arduino (that is the breakout board on which the actual display is mounted) have 20 pins, usually marked 1 through 16, or GND, VCC, V0, RS, RW, E, DB0, DB1, DB2, DB3, DB4, DB5, DB6, DB7, PSB. NC, RST, Vout, BLA and BLK. Because the <u8glib.h> works via serial communication the parallel interface will not be used. Because of this the LCD requires only three pins: D10, D11 and D12. This frees a large number of Arduino pins for all kinds of useful applications.

Figure 3: Wiring diagram with the LCD wiring plus the additional wiring to the test pin headers. The LCD is made partially visible in the bottom part of the diagram.

Nano to test bench pin header
As the 20-pins LCD breakout pin header requires only three of the Arduino pins to control the display (plus GND on pins 1, 15 and 20, 5V on pin 2 and current limited 5V on pin 19), plenty of Arduino pins remain empty and therefore can be used for testing purposes. Three female pin headers were mounted for this purpose: an 8-pin ‘Analog’ header, an 8-pin ‘digital’ header and a two-pin ‘TX-RX’ header for serial communication. Care was taken to wire a led that can be programmed to flash during activity to signal an orderly working Arduino sketch.

The ‘digital’ pin header is wired to pins D3 through D10 of the Nano
The ‘analog’ pin header is connected to pins A0 through A7 of the Nano.
The ‘TX-RX’ pin header enables serial communication
Nano pin D13 is not used.

Because equipment that is being tested needs power and GND, two male pin headers supporting these functions were included. Male pin headers with functional colors (red: voltage; black, GND) were chosen to guard against erroneously connecting wires. Thus the test bench has multiple pin headers to supply power and GND to external devices, e.g., sensors.

Figure 4: Top and bottom view of the fully assembled and working 128*64 LCD test bench, with my favorite ‘Duck’ graphical test sketch.

First sketch
A most basic sketch to get an 128*64 ST78920 LCD up and running under Arduino is the following:

(if you copy-paste this, then change smart quotes around “Hello World!” into straight quotes)

// LCD_128x64_ST7920_hello_world
// controller ST7920
// <U8glib.h> authored by Olikraus

// public domain
// May 8, 2020
// Floris Wouterlood

// note that all graphic commands to redraw the complete screen
// must be placed in draw(void)
// no subroutines allowed in draw(void)!

#include <U8glib.h>
U8GLIB_ST7920_128X64 u8g (13, 11, 12, U8G_PIN_NONE);

void draw(void) {

u8g.setFont (u8g_font_unifont);
u8g.drawStr (10, 44, “Hello World!”);

void setup(void) {

pinMode (2,OUTPUT); // this is to set up the signaling led
u8g.setRot180(); // flip screen, if required

void loop(void) { // picture loop

do {
} while( u8g.nextPage() );

digitalWrite (2, HIGH);
digitalWrite (2, LOW);

This sketch will print the words “Hello World!” to screen and flash the led every two seconds.

Second Sketch
To demonstrate what is possible with graphics I have included the sketch LCD_128x64_duck here. When this sketch is executed a 60×64 pixel bitmap is loaded into RAM and displayed in the left part of the display while the right part contains a rectangle and text (‘live’ on display in Figure 4A).

The ‘duck’ image is embedded in hex code in the sketch. To display such an image it should be present as uint8_t hexadecimal format. An original, say, 24 bit color image has to be converted first into 1-bit monochrome format (also called ‘bitmap’ or ‘black-white’) and then converted into appropriate hexadecimal code. This needs to be done because pixels in an LCD are either in OFF or ON position. There are no grey levels! Conversion of color images into black/white is done in photo-editing software, e.g. Photoshop (mode – – bitmap).

Figure 5: Conversion steps from 24-bit color image to 1-bit Arduino sketch hexadecimal code.

Conversion of a 1-bit black/white image into hex code is performed with a special image converter, e.g., lcd-image-converter (Figure 5). lcd-image-convertor is a free Windows application.


// LCD_128x64_ST7920_duck
// uses u8glib by Olikraus
// bitmap loaded in progmem
// Floris Wouterlood
// May 8, 2020
// public domain

#include <avr/pgmspace.h>
#include “U8glib.h”

U8GLIB_ST7920_128X64 u8g(13, 11, 12, U8G_PIN_NONE);

// Duck 60×64 bitmap
const uint8_t duck_064_bitmap [ ] PROGMEM = {

0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xff, 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xfe, 0xff, 0x5f, 0xfb, 0xff, 0xff, 0xf0,
0xff, 0xff, 0x7f, 0xff, 0xfd, 0xff, 0xff, 0xf0,
0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0xe0,
0xff, 0xff, 0xbf, 0xff, 0xfb, 0xff, 0xff, 0xf0,
0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xd0,
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xfd, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xf0,
0xff, 0xff, 0x3f, 0xf9, 0x3c, 0x7f, 0xff, 0xf0,
0xff, 0xff, 0xff, 0xfe, 0xc7, 0xbf, 0xff, 0xf0,
0xff, 0xff, 0xff, 0xf7, 0xbc, 0xd7, 0xff, 0xf0,
0xff, 0xff, 0xff, 0xcc, 0xdf, 0xfb, 0xff, 0xf0,
0xff, 0xff, 0xfe, 0x7f, 0xcb, 0xe5, 0xff, 0xf0,
0xff, 0xff, 0xfe, 0xfd, 0xbd, 0xbe, 0xff, 0xf0,
0xff, 0xff, 0xfd, 0xff, 0x7e, 0xff, 0xff, 0xf0,
0xff, 0xff, 0xfb, 0x4f, 0xfe, 0xbf, 0x7f, 0xf0,
0xff, 0xff, 0xed, 0x6f, 0x3e, 0xdf, 0x7f, 0xf0,
0xff, 0xff, 0xef, 0xf6, 0xcf, 0x5f, 0xf7, 0xf0,
0xff, 0xff, 0xdb, 0xed, 0xf7, 0x7f, 0x37, 0xf0,
0xff, 0xff, 0xb7, 0xdb, 0xff, 0x5f, 0x9f, 0xf0,
0xff, 0xff, 0xaf, 0xfb, 0xf7, 0x7f, 0xf1, 0xf0,
0xff, 0xff, 0x6f, 0xb7, 0xff, 0xff, 0xf7, 0xf0,
0xff, 0xff, 0xdf, 0x6f, 0xfb, 0x7f, 0xf9, 0xf0,
0xff, 0xfe, 0x7f, 0x6f, 0xff, 0x7f, 0xff, 0xf0,
0xff, 0xff, 0xbe, 0xef, 0xfb, 0x7f, 0xf9, 0xf0,
0xff, 0xfe, 0xbf, 0xdf, 0xf7, 0xff, 0xfd, 0xf0,
0xff, 0xff, 0xb0, 0xff, 0xff, 0xff, 0xfb, 0xf0,
0xff, 0xfe, 0xe3, 0x87, 0xf7, 0xff, 0xfb, 0xf0,
0xff, 0xfe, 0x63, 0xc7, 0xf7, 0xff, 0xf9, 0xf0,
0xe0, 0x7f, 0x61, 0x87, 0xff, 0xff, 0xfd, 0xf0,
0xeb, 0x8f, 0x63, 0x8f, 0xef, 0xff, 0xff, 0xf0,
0xdc, 0xe3, 0x71, 0x0f, 0xef, 0xff, 0xf3, 0xf0,
0x8a, 0xb8, 0x55, 0x1f, 0xef, 0xff, 0xff, 0xf0,
0xd4, 0xce, 0x2a, 0xbf, 0xdf, 0xff, 0xf7, 0xf0,
0xea, 0x31, 0xad, 0xbf, 0xdf, 0xff, 0xff, 0xf0,
0xfa, 0x8e, 0x96, 0x9f, 0xff, 0xff, 0xef, 0xf0,
0xff, 0x62, 0xd2, 0xcf, 0xbf, 0xff, 0xdf, 0xf0,
0xff, 0x99, 0x4f, 0x67, 0x7f, 0xff, 0xdf, 0xf0,
0xff, 0xe5, 0x61, 0x59, 0x7e, 0xff, 0xbf, 0xf0,
0xff, 0xf2, 0xb6, 0xae, 0x12, 0x0f, 0x7f, 0xf0,
0xff, 0xfa, 0x5b, 0xd3, 0xcb, 0xd0, 0xff, 0xf0,
0xff, 0xfc, 0x2a, 0x5c, 0xba, 0x55, 0xff, 0xf0,
0xff, 0xfe, 0x95, 0x53, 0x49, 0x2e, 0xff, 0xf0,
0xff, 0xfe, 0x87, 0xdd, 0x46, 0x82, 0xff, 0xf0,
0xff, 0xf9, 0x50, 0x40, 0x42, 0xfa, 0xff, 0xf0,
0xff, 0xfa, 0x6d, 0x2b, 0x79, 0x2e, 0xff, 0xf0,
0xff, 0xf9, 0xf2, 0x97, 0xff, 0xc0, 0xff, 0xf0,
0xff, 0xf5, 0xda, 0x7f, 0xe7, 0xfb, 0xff, 0xf0,
0xff, 0xf2, 0x4a, 0xff, 0xdf, 0xff, 0xff, 0xf0,
0xff, 0xf5, 0x3e, 0xff, 0x8f, 0xff, 0xff, 0xf0,
0xff, 0xfa, 0x45, 0xfe, 0x47, 0xff, 0xff, 0xf0,
0xff, 0xc9, 0x73, 0xfc, 0x53, 0xff, 0xff, 0xf0,
0xff, 0xb7, 0x20, 0x1a, 0x0b, 0xff, 0xff, 0xf0,
0xfe, 0x84, 0x89, 0x40, 0x41, 0xff, 0xff, 0xf0,
0xfd, 0x35, 0x02, 0xa9, 0x15, 0xff, 0xff, 0xf0,
0xa0, 0xd4, 0x4a, 0xb4, 0x00, 0xff, 0xff, 0xf0,
0x06, 0x54, 0x8a, 0x93, 0xfe, 0xff, 0xff, 0xf0,
0x51, 0x52, 0x1a, 0xd7, 0xff, 0x3f, 0xff, 0xf0,
0x08, 0x09, 0x25, 0x27, 0xff, 0xff, 0xff, 0xf0,
0x25, 0x40, 0x3a, 0x9f, 0xff, 0xdf, 0xff, 0xf0

void draw(void) {

u8g.setFont( u8g_font_unifont);
u8g.drawFrame (65,0,63,64);
u8g.drawStr ( 73, 22, “DUCK!!”);
u8g.drawStr ( 70, 45, ” 60*64″);
u8g.drawStr ( 82, 58, “mono”);
u8g.drawBitmapP ( 0, 0, 8, 64, duck_064_bitmap); // print bitmap to screen

void setup(void) {

pinMode (2, OUTPUT);
u8g.setRot180 (); // flip screen


void loop(void) {

u8g.firstPage(); // picture loop
do {
} while( u8g.nextPage() );

digitalWrite (2, HIGH); // flash control led
delay (50);
digitalWrite (2, LOW);
delay (2000);

Results and discussion
A picture of the completed test bench with a ST7920 128*64 LCD mounted on the LCD pin header is shown in figure 4. It is running the LCD_128x64_duck.ino sketch.

With the test bench I can now concentrate on software development any time because the platform is indefinitely more stable than the old contraption of breadboards and wires. There are plenty of free Arduino pins, ready to connect sensors or to provide output. I2C devices can be tested via pins A4 (SDA) and A5 (SCL) of the analog test pin header. Serial communication is available and there are plenty power and GND pins. I believe that this test bench is a nice addition to my growing collection of Arduino gear.
About <u8glib.h>: this library has been succeeded by <u8g2.h> which can be found at Github. U8g2.h requires an overhaul of the sketches presented here; this is one of the software development projects in the planning.


Sketches are zipped: unzip and open in Arduino IDE