Skip to content

Instantly share code, notes, and snippets.

@crow

crow/LCD.java Secret

Last active Mar 28, 2017
Embed
What would you like to do?
Android Things HD44780 LCD driver class
/*
* Copyright 2017 Nish Tahir, modified by David Crow
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.urbanairship.pushtothing;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.util.Log;
import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.PeripheralManagerService;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static android.text.TextUtils.substring;
public class LCD implements Runnable, AutoCloseable {
private static final String TAG = "LCD";
/**
* LCD shared instance
*/
public static LCD shared;
/**
* Clears display and returns cursor to the home position (address 0).
*/
private static final byte LCD_CLEAR_DISPLAY = 0x01; //00000001
/**
* Set DDRAM address
*/
private static final int LCD_SET_DDRAM_ADDR = 0x80; //0010000000
/**
* Set CGRAM address
*/
private static final byte LCD_SET_CGRAM_ADDR = 0x40; //0001000000
/**
* 00001DCB
* D - Sets on/off of all display.
* C - cursor on/off.
* B - and blink of cursor position character.
*/
private static final byte LCD_DISPLAY_ON = 0x0F; //00001111
/**
* Used for initialization
*/
private static final byte LCD_4_BIT_OPERATING_MODE = 0x02;
private static final byte LCD_8_BIT_FUNCTION = 0x28;
/**
* 00000DS
* D - Sets cursor move direction D.
* S - Display shift
*/
private static final byte LCD_SET_ENTRY_MODE_NO_SHIFT_DISPLAY = 0x06; // 00000110
@NonNull
private Gpio resetPin;
@NonNull
private Gpio enablePin;
private @IntRange(from = 1, to = 2) int cursorPosition;
@NonNull
private List<Gpio> dataBus;
public LCD() throws IOException, InterruptedException {
PeripheralManagerService service = new PeripheralManagerService();
Gpio rs = service.openGpio("BCM6");
Gpio e = service.openGpio("BCM19");
Gpio d4 = service.openGpio("BCM26");
Gpio d5 = service.openGpio("BCM16");
Gpio d6 = service.openGpio("BCM20");
Gpio d7 = service.openGpio("BCM21");
this.resetPin = rs;
this.enablePin = e;
rs.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
e.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
dataBus = Arrays.asList(d4, d5, d6, d7);
for (Gpio pin : dataBus) {
pin.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
}
initializeLCD();
}
public void writeString(String string, @IntRange(from = 1, to = 2) int row) {
try {
if (string.length() > 16) {
Log.e(TAG, "Attempted to write string that was greater than maximum length," +
"truncating it...");
string = string.substring(0, 16);
}
// Only move cursor if it's out of position
if (cursorPosition != row) {
cursorPosition = row;
LCD.shared.setCursor(row, 1);
}
resetPin.setValue(true);
LCD.shared.write(string + spacePad(16 - string.length()));
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
// Helper to add spaces to each screen write to prevent aliasing
private String spacePad(int n) {
return (n == 0 ? "" : String.format("%"+n+"s", " "));
}
private void initializeLCD () throws IOException {
sendCommand(LCD_4_BIT_OPERATING_MODE, true);
sendCommand(LCD_8_BIT_FUNCTION);
sendCommand(LCD_DISPLAY_ON);
sendCommand(LCD_SET_ENTRY_MODE_NO_SHIFT_DISPLAY);
clearDisplay();
this.setCursor(1, 1);
cursorPosition = 1;
}
private void write(@NonNull String val) throws IOException {
resetPin.setValue(true);
for (char b : val.toCharArray()) {
write(b);
}
}
public void clearDisplay () throws IOException {
sendCommand(LCD_CLEAR_DISPLAY);
}
private void write(char c) throws IOException {
resetPin.setValue(true);
write8((byte) c);
}
private void setCursor(@IntRange(from = 1, to = 2) int row,
@IntRange(from = 1, to = 16) int column) throws IOException {
sendCommand((byte) (LCD_SET_DDRAM_ADDR | ((LCD_SET_CGRAM_ADDR * (row - 1)) + (column - 1))));
}
private void sendCommand(byte command, boolean fourBitMode) throws IOException {
resetPin.setValue(false);
if (fourBitMode) {
write4(command);
} else {
write8(command);
}
}
private void sendCommand(byte command) throws IOException {
sendCommand(command, false);
}
private void write4(byte value) throws IOException {
for (int i = 0; i < dataBus.size(); i++) {
Gpio pin = dataBus.get(i);
pin.setValue(((value >> i & 0x01) != 0));
}
pulseEnable();
delay(1);
}
private void write8(byte value) throws IOException {
write4((byte) (value >> 4));
write4(value);
}
private void pulseEnable() throws IOException {
enablePin.setValue(false);
delay(1);
enablePin.setValue(true);
delay(1);
enablePin.setValue(false);
delay(1);
}
private void delay(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
Log.e(TAG, e.getMessage());
}
}
@Override
public void close() throws IOException {
resetPin.close();
enablePin.close();
for (Gpio pin : dataBus) {
pin.close();
}
}
@Override
public void run() {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment