Android Things is a great solution if you want to get an IoT project up and running quickly. With all of the power of Android and Android Studio at your disposal you can leverage the extensive body of existing work, and experts, to help get you started.
With Android Things you don't need to have a display, it works well 'headless.' If, however, you do want a display, then you can consider a character LCD display. You could use a full blown graphical display (and should if you need a 'proper' UI). But if you don't want the added cost of a graphical display then a simple, cheap character LCD display might be ideal.
In this tutorial we will learn about the character LCD based on the HD44780, how to connect it to an Android Things board, and how to control it. We will be using two methods of connecting the display, serial and parallel, and we will drive the display to make a simple interface.
Character LCD DisplaysCharacter displays, also known as alpha-numeric displays, are cheap and readily available. You can get them for a few dollars, or even scavenge them from old projects or recycled electronics. They come in many shapes, sizes and colours. Some have backlights, some do not.
The display 'size' usually refers to the number of characters as rows and columns, so a 16x2 has 16 columns and two rows. Size can also mean the physical size of the individual characters, but most often it refers to the columns and rows.
Some displays have a backlight, usually an LED. Having a backight means you don't need ambient light to see the display, it makes its own. If this is important for your project make sure you check the specifications of the display before buying it.
A common colour combination for character LCD displays is green with dark characters, but you can get many different colour displays. Some displays are 'inverted' meaning that the display is dark and the characters are coloured, white or blue or whatever the display colour is.
The LCD controller chip that resides in the display is usually an HD44780 (or clone). This controller has been around for ages. I haven't seen a character LCD display that wasn't based on the HD44780, or one that didn't use the HD44780 command set and initialisation sequence.
There are a few things to learn about the HD44780. The key facts to know are that the controller has some registers that control its function, some DDRAM (Display Data RAM) where you write data to display, and some CGRAM (Character Generator RAM) where you can write bitpatterns to make a few custom characters. The controller also has an initialisation sequence that it requires at the start to get the display running. You don't need to know the fine details at this stage, these few facts are enough to get started, you'll learn the rest along the way.
Display PinoutThe display pinout is reasonably standardised. There are a couple of variations though so be careful with the initial hookup.
Displays can require 5V or 3.3V for power, plus 0V (or GND).
Contrast AdjustThe contrast of a display can change with temperature and age. Contrast adjust pin (VEE) should connected to a trimpot to vary the voltage on this pin to somewhere between VCC and GND. Changing the voltage on this pin adjusts the contrast.
The RS pin lets you write either commands to the display registers, or data to the display. When RS is 0 data present on the data lines is transferred to the registers, when RS is 1 data is transferred to the display.
E - EnableE is the enable signal, this is used to clock in the data present on the data lines.
The E pin is really a kind of clock signal, meaning that when the signal switches from high to low, data is clocked into the display.
E2 - Enable 2Most displays don't have an E2. It is only required if the display is larger than 80 characters. This is because the size of DDRAM (Display Data RAM) is 80 bytes. To get around this limit and enable bigger displays, manufacturers make displays with 2 HD44780s. The 2 controllers share RS, R/W and data lines. E is connected to one controller's E and E2 is connected to the other. A common display with an E2 is the 40x4 display. E2 has the same function as E but is for the second 'half' of the display.
DataThe HD44780 has 8 data lines. Displays can operate in 8 bit or 4 bit mode. In 8 bit mode data from all data lines is clocked in to the device when E is toggled. In 4 bit more data from D3 to D7 is clocked in when E is toggled. A second pulse on E is required to clock in the second nibble of a byte. Most implementations I've seen recently use 4 bit mode. it's easier to wire up than 8 bit mode at the cost of slightly complicating the required software.
R/W - Read not-writeIn most cases you only need to write to the display so you don't really need the R/W signal, it can be tied to GND.
Connection methodsThere are typically two ways to connect the display to an Android Things development board; parallel or serial. There's a tradeoff to consider when deciding which method to use. Parallel uses more GPIOs but requires little extra hardware. Serial is simpler (in my opinion), using fewer GPIOs but requires extra hardware to 'convert' serial data into the parallel signals required to drive the display. Serial display adaptors are readily available, and cheap, and usually come with a transistor to drive a display backlight.
Parallel connectionThe issues I see with parallel connection to an LCD are; I/O voltage levels of the Raspberry Pi being 3.3V means you need to find a display that works at this level, or add hardware to do level shifting. You still need to add a potentiometer to set the contrast, and you use a lot of I/O pins on the Raspberry Pi, limiting what you have available for other functions. Another issue is that you can only add one display. Although this is the typical case, you might want more than one display. With a serial connection connecting to multiple displays is easier.
For the above reasons my recommendation is to use a serial adaptor board, but for completeness this is how you do connect a display to the board in parallel.
Here's what it would look like to connect an LCD directly to the Raspberry Pi. This is assuming that you have a 3.3V compatible display. If you had a 5V display you should use level shifters to ensure that you don't damage the Raspberry Pi IO pins. Even with the mess of wires shown below there is still no method to control the display backlight, for that you need a couple more components; a transistor and a resistor or two.
Serial connection means you need to use extra hardware to connect the display, but you reduce the number of GPIOs you need, and converter boards usually include the potentiometer needed to set the display contrast. I've seen a couple of types of serial adaptor, UART, USB and I2C adaptors exist. My favourite is the I2C type of adaptor based on the PCF8574 8-bit IO port expander. This is the type of adaptor that I'll describe here.
You can make your own adaptor using a PCF8574. I used to do this years ago but nowadays cheap adaptors are readily available that include all the components you need on a single board. I use a board called the LCM1602, which is an unfortunate name in my opinion because it implies that it just supports the 16x2 displays when, in reality, it supports all HD44780 based displays. I've even used a modified one with a 40x4 display that requires an E and an E2 signal.
The LCM1602, sometimes referred to as the YwRobot LCM1602, is a simple board that contains a PCF8574, trimpot and a transistor to switch a backlight. There are a few versions of this board around, and the schematics are available with a little searching. These are also known as piggyback boards because the piggyback on the LCD display.
The main IC (usually the only IC) on the adaptor board is a PCF8574. This is an I2C, 8-bit, I/O expander. That's a mouthful, lets unwrap what that means.
I2C (pronounced 'eye-squared-cee' or 'eye-two-cee' depending on where you were raised) is a serial communications standard created by Philips. It's used extensively in electronics. It's typically used to connect components to microprocessors on circuit boards. I2C is master-slave, multi-drop, meaning that there's a controller (the master) that can communicate to multiple devices (the slaves) on a single bus (or pair of wires). The advantage of I2C is that you can communicate with multiple devices with a single pair of wires, reducing the required pin count for the controlling microprocessor, and simplifying your schematic.
The PCF8574 is 8 bit, meaning that the number of output pins it has is 8. This also means it's word size is 8. It can take a single byte of serial data and set 8 output pins.
The PCF8574 is a port expander, this is its primary function. It lets you have 8 I/O (input/output) pins for the cost of the two serial pins, expanding the number of pins that your microprocessor has available.
The PCF8574 is also addressable, meaning that you can communicate to multiple PCF8574s on the same bus by setting different addresses for each one. This is achieved by setting pins A0, A1 and A2 either high or low. With 3 pins the PCF8574 has 8 addresses so you can add up to 8 port expanders to a single project. This gives you up to 64 output pins for the cost of two pins on your microprocessor. Setting the pin state on display adaptors usually involves bridging solder jumpers on the board.
The trimpot is used to adjust the contrast on the display. Turn the trimpot until the display looks 'about right.' If you're having trouble getting a display working this is the first thing to check.
The display adaptor board I bought has a transistor to drive the LCD backlight. This is required because the required backlight current is usually higher than a IO pin can provide. The transistor is switched by one of the PCF8574 pins.
The LCD display and LCM1602 operate at 5V. I2C pins on the Raspberry Pi are not 5V tolerant. The safest way to connect the two is to use a bus level translator. This ensures that you won't damage the I2C pins on the Raspberry Pi. I have seen people not use this. It's probably OK not to. The board I have ties the I2C lines to VCC (5V) with 4K7 resistors. This would pull the Raspberry Pi I2C lines up to 5V too. I think it's better to be safe than risk frying the Raspberry Pi's I2C lines. There is some debate about whether this is a problem or not. I'll leave it up to you to do the research and make the call.
Driving the LCD with Android Things is easy, you just need to use the right library. To add the library to your Android Studio project add the driver dependency to your module dependencies.
dependencies {
implementation 'nz.geek.android.things:things-driver-char-display:0.6'
}
ArchitectureI want to be able to use serial or parallel connections for displays, and I don't want to change the software much between each method. I do this by creating an interface for the display that models the display functions I need. Then I can implement a serial or parallel version of the interface. I also want to use the same interface for LED Matrix character displays. My LED character display uses SPI and a simple protocol, but that's another story.
The important bit in the preceding diagram is the CharacterDisplay interface at the top. This contains the methods we will need to call to control the display.
Using the CharacterDisplay interfaceTo use a CharacterDisplay we first need to create an object of the implementing class. The GpioLcdCharacterDisplay and I2cLcdCharacterDisplay classes define a builder that can be used to create a display. The builders for each implementation have similar methods which take different arguments. Here's a closer look at the builder for a serial display.
Most of the builder methods take an int, which is the pin number of the PCF8574 IO pin that the LCD pin is connected to. This sets up the pin mapping between the PCF8574 and the LCD. The mapping will depend on your adaptor board. To find this out you will need the schematic for your board or you will have to work out the mapping by using a multimeter and buzz out the pins. I created a schematic from the adaptor board that I purchased which will probably be representative of the boards you can get on Aliexpress.
One important thing to note about the schematic of board I have is that the address lines are tied high via pull up resistors. This means that without any of the solder jumpers shorted the address will be 7. I have seen boards that are the opposite, with the address lines tied low with pull down resistors that need to be 'jumped' high. It's important to measure the jumper pads resistance to ground and VCC to see what type of board you have.
Here's the mapping for the adaptor I am using. Note that the port number is not the pin number of the PCF8574 but the P0, P1 etc output.
There are two other important builder methods: address() and isPcf8574(). Use the address method to set the address, give it the value of A0-A2 for your adaptor. The value you pass to address should be from 0 to 7, anything outside that range is an error. There are two types of PCF8574; the PCF8574 and the PCF8574A. The two are identical except for a different base address. We don't need to worry about what the base address is, we only need to tell the driver which one we are using. If we don't specify it the driver assumes that we are using a PCF8574A. If the adaptor has a PCF8574 (no A at the end) then use the isPcf8574() method of the builder.
Using the builder we can string together the methods to define the pin mapping like this:
// set port pin to LCD pin mapping, and PCF8574(A) address
builder.rs(0).rw(1).e(2).bl(3).data(4, 5, 6, 7).address(6);
Here we are saying RS is P0, R/W is P1, E is P2, the backlight is controlled by P3 and the data pins are P4, P5, P6 and P7. We are also saying that the address is 6, meaning that A2 and A1 are high and A0 is low. We have also implied that we are using a PCF8574A by omitting the isPcf8574() method.
With the builder initialised we can now use it to build a display and start using it.
// build and use the display
CharacterDisplay lcd = builder.build();
lcd.connect();
Use the display
// create a display builder with the LCD module width and height
I2cLcdCharacterDisplay.Builder builder = I2cLcdCharacterDisplay.builder(20, 4);
// set port pin to LCD pin mapping, and PCF8574(A) address
builder.rs(0).rw(1).e(2).bl(3).data(4, 5, 6, 7).address(6);
// build and use the display
CharacterDisplay lcd = builder.build();
lcd.connect();
// write message to the display, the first argument
// is the LCD line (row) number
lcd.print(1, "Hello World!");
ConclusionIn this tutorial we have learned about character LCD displays based on the HD44780 driver IC. We have learned about the types of connection you can make between a display and its controller, in this case a Raspberry Pi running Android Things. We have learned about I2C adaptors that simplify the connection, and what the components on an adaptor board do. Finally we have learned how to control the LCD and write messages to the display from an Android Things app.
The complete source code for the display driver and a sample app for Android Things is linked in the attachments. Have fun and enjoy!
Comments