In many cases, a display can be necessary or a great addition to an Arduino based project, so today we are going to go through the steps of setting up a Nokia 5110 LCD for use with an Arduino. In this case the Arduino Nano, however, the process is the same for other popular boards like the Uno or Mega.
This LCD was once used in the Nokia 5110 mobile phone and so is referred to the “Nokia 5110 LCD” or just “5110 LCD”. It usually comes on a red or blue board as in the picture and they should all function the same. The display says it operates within the range of 3V to 5V which makes it perfect for use with a 5V system such as an Arduino, however, I find it better to connect it to the 3.3V supply rather than the 5V.
Connecting the Arduino and the display
There are 8 connections on the LCD module, this may vary on slightly different boards but the pins required are:
- RST – Reset Signal
- CE – Chip Enable
- DC – Data or Command
- DIN – Data in
- CLK – Clock Signal
- Vcc – 3V to 5V supply
- BL – Backlight
- GND – Ground 0V
Vcc should be connected to 3.3V, GND connected to GND and BL can also be connected to 3.3V or 5V with a suitable resistor. The rest of the pins can be connected directly to any output pins on the Arduino, though it is probably wise to connect it through suitable 1K resistors or a level shifter if the signals are 5V. Here is the configuration I used:
And here is it connected up to the Arduino without the BL connection hooked up (easier to photograph on my phone), now it is time to have a look at the data-sheet to see how to send data to the display.
Sending data to the display
The controller of the display is the PCD8544, so let’s have a look at its data-sheet.
First, let’s see how the display works, we can see from this diagram that the LCD is split into vertical cells, each containing 8 pixels. This means we can send a byte of data to the display and it will be shown within a cell allowing us to create images – every 1 is a pixel on and every 0 a pixel off.
We can see here that the MSB (left-most) is at the bottom of each cell and the LSB (right-most) is at the top. So basically we can send data to the display ram and it will display a byte across one cell then move to the next cell, this can either be done horizontally or vertically. As we are trying to display text which is read horizontally, it makes a lot of sense to use the horizontal addressing rather than vertical.
Now we can look at how we actually send data to the display from this timing diagram.
The pin names are slightly different from those written on our display but we should be able to tell which is which. We can see that (S)CE must be low to send data and that DC should be either HIGH or LOW by the end of the byte to tell the display controller to either display the data on screen or to execute the data as a command, we can see that as C had a line over it, it means active low. Therefore, DC HIGH is display data and DC LOW is command data. Finally, we see that (S)DIN send that byte as serial data, note that (S)CLK goes from LOW to HIGH for each bit, a clock is required for serial communication like this and so we will have to generate this clock signal.
We should first make sure the Arduino IDE is set to the correct setting and we should define and set-up all the pins we use.
All pins are configured as outputs at setup and then a LOW HIGH pulse is sent on the RST pin to reset the display for use. Now we need to replicate the timing diagram in code so we will make a function for sending a command and for sending display data.
These two functions are essentially the same, we just have to set DC to LOW or HIGH depending on the operation. So we set DC first as it doesn’t matter when its set, it just must be valid by the end of the byte. We set CE LOW to enable the chip and then we use the shiftOut() function which is an in-built Arduino function that will send serial data and generate our clock signal. So we call shiftOut(D_IN, CLK, MSBFIRST, data), the first parameter is the data pin to send the data along, the second is the data pin to generate the clock on, the third is the order we send the data and finally the fourth is the byte we want to send. MSBFIRST means we send the serial byte with the most-significant-bit first, this is required as it is the way the display reads data.
Initialising the display
Now that we can send data and commands to the display we need to initialise the display for use so we look back to the data-sheet for the commands/instructions.
This will help us to understand what data needs to be sent for each command. To initialise we should do a few things:
- Set Contrast (Vop)
- Set Temperature Coefficient
- Set the LCD Bias
- Set to normal and horizontal mode
Here is the code to achieve this, the temperature coefficient and bias have been set to 0x04 and 0x14 respectively, as this is what is recommended for use. The contrast, on the other hand, should be set to what you find works best, I tried a few values and found 0xB7 worked pretty well. Finally, in the end, we switch back to normal commands and horizontal mode and set the LCD to normal operation, if we wanted inverted mode we could set it to 0x0D.
Writing to the Display RAM
Now we have set up and initialised the display we can attempt to write some data to it, let’s first start by writing 0xFF, this should turn on all the pixels in the first cell forming a vertical line. However, we should first create a function to clear the screen or we will get information still in RAM displayed which we may not want, this is simple to do we just need to fill every cell with 0x00 with a loop.
We can also do the same to make a fill-screen function. Then in setup, after the initialise commands:
And result! Everything seems to have worked fine, now let’s see what else we can do…
Setting X and Y Address (Draw Coordinates)
If we look back to the datasheet information on the various commands then we can see there is a way to set the X and Y address of RAM, this will allow us to select where we draw on the screen.
The X address will allow us to choose any of the 84 positions across the display but you may notice that the Y address is only between 0 and 5 as we can not choose any pixel, but instead which cell of pixels. Think of the screen having 6 rows and we can only write to one row at a time but anywhere along that row. We must represent the coordinates in binary as seen in the table, the Y address is easy enough it will be the command 0x4? where the ? is between 0 and 5. The X address has a wider range for the commands can be anything between 0x80 and 0xD3. The easiest way to do this in our code is to OR the co-ordinate with 0x40 for Y and 0x80 for X as shown:
And there we go! We have our original line in top left and now in the 4th row about halfway across the screen we have drawn a small checker pattern from dotted lines.
Drawing Text Characters
As seen before, I made a simple checker pattern by placing dotted lines in neighbouring cells, we can use this technique to form characters to display text. For example:
By writing the correct sequences of bytes I have formed an ‘M’ on screen, however, doing this for every letter would become confusing and long. It would be much easier if we have a header file with all the byte sequences pre-written… well I guess it’s our lucky day because I have one right here. Apologies I do not know who originally made this file with the font/chars so I cannot credit them. Here is a look inside the file:
It contains a 2-dimensional array, which is an array of an array of 5 bytes. We can see that the ASCII code followed by the character has been conveniently written by each array, this is important as the first ASCII code is 0x20 for SPACE. This means if we are using ASCII characters we choose the correct sequence of bytes by subtracting 0x20 to give the array position.
Now we can include this file by adding it to the directory of the sketch and using #include, then we need to write a function to utilise it.
This function allows us to print a single character to the display, it is a for loop that prints the 5-byte sequences for each character and then adds a blank gap after so the letters do not all combine together. As previously mentioned it has to subtract 0x20 to correctly read ASCII codes. Now, let’s test the function by adding:
Nice! Everything seems to be working well still, now let’s write a function to print strings instead of just single characters. This is done by printing every character in the string until a loop reaches the null character ‘\0’ that is at the end of a string:
So let’s test it out, add:
Well there we go, we have added basic functionality to display text on our display. Let’s finish by adding some Serial code to the loop so we can display whatever we type.
And done! Well, that’s all for this post. Hopefully I will get some different displays and make more posts similar to this one and maybe next time I will detail how to display bitmap graphics! But for now, Thanks for reading :^)