---
title: "7 Arduino LCD display tips and tricks"
description: "7 tips and tricks for driving a Arduino LCD Display like the common 2x20 and 4x20 screens. Learn how to use a buffer, sprintf(), and printing floats!"
canonical: "https://www.baldengineer.com/arduino-lcd-display-tips.html"
author: "James Lewis"
date: "2017-12-21T17:30:03Z"
lastmod: "2019-11-28T06:57:52Z"
image: "https://www.baldengineer.com/wp-content/uploads/2017/12/Arduino-LCD-display.png"
categories: ["arduino","blog","displays","programming","tutorials"]
tags: ["lcd","open-vapors","sprintf"]
---

# 7 Arduino LCD display tips and tricks


When I started working on [Open Vapors](/reflow-oven.html), I thought the stumbling point would be the PID algorithm or safe AC line control. However, it turned out; I spent a significant amount of time understanding how to print to the Arduino LCD display correctly.

> **Note:** [![Grove RGB character LCD display](/wp-content/uploads/2017/12/httpsstatics3.seeedstudio.comimages104030001201-300x225.jpg)](/wp-content/uploads/2017/12/httpsstatics3.seeedstudio.comimages104030001201-300x225.jpg)
> 
> 
> If you need an easy to use RGB LCD, check out the [Grove LCD from SeeedStudio](https://www.seeedstudio.com/Grove-LCD-RGB-Backlight.html). They sent me one to check out. The LCD comes with Seeed's "[grove connector system](http://wiki.seeedstudio.com/Grove_System/)" which can connect to a variety of their Arduino-compatible boards. You can also pick up the [Grove Base Shield](https://www.seeedstudio.com/Base-Shield-V2.html) which adds a variety of Grove connectors to an Arduino Uno. The Grove LCD makes it super easy to connect up a character LCD. It is very plug-and-play.


As I dig into my latest project, the lessons I learned back then are coming back to me. Here are 7 tips for driving an Arduino LCD display, like one with 2x20 or 4x20 characters.

## 1\. Buffer the Arduino LCD Display

One approach I see many people try with a character LCD is letting their code directly print to the display. Using a simple buffer might look like it adds unnecessary complexity. One positive point is that you get a more predictable behavior. A trade-off is that you do need to use up a few more bytes of RAM. So, how do you implement a buffer?

First, declare some character arrays. Depending on your application, it might make sense to use a multi-dimensional array. If not, I find it more straightforward to have individual arrays for each line. For example, I might declare "line0" and "line1" each with 21 characters. (Remember, you should always have an extra character for the null terminator.)

```c

char line0[21];
char line1[21];

```

Modify the buffer when your code needs to make a change on the Arduino LCD display. Modify the character array, aka string, variable.

```c

line0[4] = 8;
line0[5] = 5;
line0[6] = 'C'

```

Lastly, use a separate function to lcd.print() each line. Then in your loop() call the subroutine to update the screen. If you have some code, like a large for-loop or a lot of floating point math, you can also call the update display function there. That way the screen stays responsive.

## 2\. Refresh the entire screen every time you change something

The display flickers if it is cleared then re-printed. An I2C serial backpack makes the flicker worse. SPI and UART fare a little better, but there is still some latency.

An alternative is never clear the screen. Just keep re-writing regardless if anything changes. So instead of trying to change one character at a time, print an entire line. The line printing approach works great if you are using a buffer and the print code from above.

```c

void updateDisplay() {
   lcd.setCursor(0,0);
   lcd.print(line0);
   lcd.print(line1);
}

void loop() {
   updateDisplay();
   // whatever else
}

```

This approach does have a minor issue though. Some people misinterpret a bug as something wrong with the display. Let's look at an example that shows this problem, and another way to modify the buffers.

## 3\. Using sprintf() to clear a character lcd

Pretend we built a temperature logger that prints the current temperature to the character display. While debugging, we keep seeing characters getting left behind or the temperature is displayed wrong.

### The code prints "Temperature: 5".

 [![LCD-TEMP-5](/wp-content/uploads/2017/12/LCD-TEMP-5.png)](/wp-content/uploads/2017/12/LCD-TEMP-5.png)

Then at some point, it gets slightly warmer, so the LCD now shows

### "Temperature: 15."

 [![LCD-TEMP-15](/wp-content/uploads/2017/12/LCD-TEMP-15.png)](/wp-content/uploads/2017/12/LCD-TEMP-15.png)

Later in the day, it cools off, and now your display is showing

### "Temperature: 85".

 [![LCD-TEMP-85](/wp-content/uploads/2017/12/LCD-TEMP-85.png)](/wp-content/uploads/2017/12/LCD-TEMP-85.png)

Wait a minute. 85 isn't colder than 15! And in this case, it did not matter if we displayed in Celsius, Fahrenheit, or Kelvin.

So, what happened? Only the characters that get updated are being, well, updated. The extra "5" is from printing "15." Nothing is clearing that block on the LCD.

So there are two options here. Clear the display EVERY TIME you go to print to the screen or print blank characters any place that should be blank. The second method is called "padding."

I would recommend the padding approach for two reasons:

1. **Deterministic Behavior**. I prefer operations like screen drawing to always take the same amount of time. Otherwise, you could run into hard to track down timing bugs. So on a 20 character wide display, I always print 20 characters. (Although, I may not print all of the lines at the same time.)
1. **Flickering**. The act of clearing the display and then re-printing it could lead to flickering characters. This action is similar to pulse width modulating a LED. And the same limitation applies there. If the flashing is slow enough, human eyes will see it as flashing.

Using sprintf() isn't difficult, but it does require the use of a buffer. (Sound familiar?) Here I will show you how to use sprintf(). As the name suggests, sprintf() is similar to printf(). If you have never used C's printf(), check out this explanation for all of its parameters.

Here's how to [left-pad using sprintf()](https://stackoverflow.com/questions/276827/string-padding-in-c).

```c

char msg[21];
int temperature = 8;
sprintf(msg, "Temp: %-7d", temperature);

```

In this case, I picked the value 7, since "Temperature: " takes up 14 spaces of the 20 space display. Adjust that amount as necessary in your code.

## 4\. How to print floats on an LCD

You might have noticed in my example above; I used integers for temperature. There is a reason: sprintf() does not support floats. Well, more correctly, avr-libc's implementation does not support floats without a compiler flag. An easy workaround is a [function called dtostrf()](http://www.atmel.com/webdoc/avrlibcreferencemanual/group__avr__stdlib_1ga060c998e77fb5fc0d3168b3ce8771d42.html). (This function appears to be unique to avr-libc.)

```c

// Buffer for float
char float_str[8];
char line0[21];
float temperature = 15.12;
dtostrf(temperature,4,2,float_str);

// Now you can sprintf
sprintf(line0, "Temp: %-7sC", float_str); // %6s right pads the string

```

It takes a double, or float, and converts it into an ASCII string. We can then include this string in the sprintf() call.

## 5\. I2C, use Fast LiquidCrystal

It has been a long time since I wrote the [code for Open Vapors](https://github.com/baldengineer/Open-Vapors). However, I do remember at the time there was a "Fast LiquidCrystal" library. It optimized driving character displays over I2C. The before and after with the library was unbelievable. While still not as fast as directly driving the parallel interface, it was pretty close.

I only mention the age because lots can happen with libraries. If the update rate for your display seems slow, check to see if there is a more optimized library available to drive it.

## 6\. Reversed Row and Column

Maybe this issue is just me, but it seems like row and column are reversed for the LCD commands. To select a cursor location set the column, then the row. Like: lcd.setCursor(2,1). That is the third column on the second row AND NOT the second column on the third row. (Rows and columns are 0-based, fyi).

[![LCD-Rows and Columns Reversed](/wp-content/uploads/2017/12/LCD-Rows-and-Columns-Reversed.jpg)](/wp-content/uploads/2017/12/LCD-Rows-and-Columns-Reversed.jpg)

I have no amazing wisdom bits. It is just a matter of RTFM.

## 7\. Don't forget the f() macro

Just like debugging with Serial.print(), using lcd.print() can waste RAM. Wrap all strings inside of the famous F() macro. If you have not used it before, you can see my [F() macro explanation here](/arduino-f-macro.html). In short, make sure statements that look like this:

```c

LCD.print("Hello World");

```

Are changed to look like this:

```c

LCD.print(F("Hello, World!"));

```

## Conclusion

These are my tips, so now it is your turn. What tips have you used when driving an Arduino LCD display?

