![JAR search and dependency download from the Maven repository](/logo.png)
com.diozero.devices.LcdConnection Maven / Gradle / Ivy
package com.diozero.devices;
/*-
* #%L
* Organisation: diozero
* Project: diozero - Core
* Filename: LcdConnection.java
*
* This file is part of the diozero project. More information about this project
* can be found at https://www.diozero.com/.
* %%
* Copyright (C) 2016 - 2024 diozero
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
import java.util.Arrays;
import com.diozero.api.DeviceInterface;
import com.diozero.api.DigitalOutputDevice;
import com.diozero.api.RuntimeIOException;
import com.diozero.devices.mcp23xxx.MCP23xxx;
import com.diozero.internal.spi.GpioDeviceFactoryInterface;
import com.diozero.util.BitManipulation;
/**
* Interface for connecting to LCD displays using 4-bit data mode (D4-D7).
*
* Data is packed into single 1-byte payload - 4-bits contain data, the other 4
* bits control backlight, enable, read/write, and register select flags.
*/
public interface LcdConnection extends AutoCloseable {
void write(byte value);
/**
* Control whether the data bits are in the first or last 4-bits
*
* @return true if the data bits are in the high nibble (bits 4:7)
*/
boolean isDataInHighNibble();
/**
* Identify the bit in the byte payload that refers to the backlight control
* flag 1=on, 0=off.
*
* @return the backlight control bit number
*/
int getBacklightBit();
/**
* Identify the bit in the byte payload that refers to the enable flag to start
* read/write.
*
* Falling edge triggered
*
* @return the enable flag bit number
*/
int getEnableBit();
/**
* Identify the bit in the byte payload that refers to the read/write flag. Not
* implemented.
*
* R/W=0: Write, R/W=1: Read
*
* @return the read/write flag bit number
*/
int getDataReadWriteBit();
/**
* Identify the bit in the byte payload that refers to the register select flag.
*
* RS=0: Command, RS=1: Data
*
* @return the register select flag bit number
*/
int getRegisterSelectBit();
@Override
void close() throws RuntimeIOException;
/**
* For connections via a GPIO expansion board.
*/
public static abstract class GpioExpansionLcdConnection implements LcdConnection {
private final GpioExpander gpioExpander;
private final int port;
private final boolean dataInHighNibble;
private final int registerSelectBit;
private final int dataReadWriteBit;
private final int enableBit;
private final int backlightBit;
public GpioExpansionLcdConnection(GpioExpander gpioExpander, int port, boolean dataInHighNibble,
int registerSelectBit, int dataReadWriteBit, int enableBit, int backlightBit) {
// All must be unique, register select and enable must be set
if (registerSelectBit == dataReadWriteBit || registerSelectBit == enableBit
|| registerSelectBit == backlightBit) {
throw new IllegalArgumentException("registerSelectBit (" + registerSelectBit + ") must be unique");
}
if (dataReadWriteBit == enableBit || dataReadWriteBit == backlightBit) {
throw new IllegalArgumentException("dataReadWriteBit (" + dataReadWriteBit + ") must be unique");
}
if (enableBit == backlightBit) {
throw new IllegalArgumentException("enableBit (" + enableBit + ") must be unique");
}
// The control bits must not clash with the data bits
if (dataInHighNibble) {
if (registerSelectBit > 3 || dataReadWriteBit > 3 || enableBit > 3 || backlightBit > 3) {
throw new IllegalArgumentException("Data bits clash with control bits");
}
} else {
if (registerSelectBit < 4 || dataReadWriteBit < 4 || enableBit < 4 || backlightBit < 4) {
throw new IllegalArgumentException("Data bits clash with control bits");
}
}
this.gpioExpander = gpioExpander;
this.port = port;
this.dataInHighNibble = dataInHighNibble;
this.registerSelectBit = registerSelectBit;
this.dataReadWriteBit = dataReadWriteBit;
this.enableBit = enableBit;
this.backlightBit = backlightBit;
gpioExpander.setDirections(port, GpioExpander.ALL_OUTPUT);
}
@Override
public void write(byte values) {
gpioExpander.setValues(port, values);
}
@Override
public boolean isDataInHighNibble() {
return dataInHighNibble;
}
@Override
public int getRegisterSelectBit() {
return registerSelectBit;
}
@Override
public int getDataReadWriteBit() {
return dataReadWriteBit;
}
@Override
public int getEnableBit() {
return enableBit;
}
@Override
public int getBacklightBit() {
return backlightBit;
}
@Override
public void close() throws RuntimeIOException {
gpioExpander.close();
}
}
/**
* Connect via an Output Shift Register.
*/
@Deprecated(since="1.3.5")
public static class OutputShiftRegisterLcdConnection extends GpioExpansionLcdConnection {
/**
* Constructor.
*
* @param osr the output shift register instance
* @param port the port containing the 8 outputs that are connected
* to the LCD
* @param dataInHighNibble set to true if the d4:d7 of the LCD are connected to
* GPIOs 4-7 in the specified port
* @param registerSelectBit the output number in the specified port that is
* connected to the RS pin of the LCD
* @param dataReadWriteBit the output number in the specified port that is
* connected to the RW pin of the LCD
* @param enableBit the output number in the specified port that is
* connected to the E pin of the LCD
* @param backlightBit the output number in the specified port that is
* connected to the A pin of the LCD
*/
public OutputShiftRegisterLcdConnection(OutputShiftRegister osr, int port, boolean dataInHighNibble,
int registerSelectBit, int dataReadWriteBit, int enableBit, int backlightBit) {
super(osr, port, dataInHighNibble, registerSelectBit, dataReadWriteBit, enableBit, backlightBit);
}
}
/**
* MCP23S17 GPIOB to HD44780.
*
* Wiring:
*
*
* PH_PIN_D4 = 0
* PH_PIN_D5 = 1
* PH_PIN_D6 = 2
* PH_PIN_D7 = 3
* PH_PIN_ENABLE = 4
* PH_PIN_RW = 5
* PH_PIN_RS = 6
* PH_PIN_LED_EN = 7
*
*/
public static class PiFaceCadLcdConnection extends GpioExpansionLcdConnection {
private static final int CHIP_SELECT = 1;
private static final int ADDRESS = 0;
private static final int PORT = 1;
private static final byte REGISTER_SELECT_BIT = 6;
private static final byte DATA_READ_WRITE_BIT = 5;
private static final byte ENABLE_BIT = 4;
private static final int BACKLIGHT_BIT = 7;
public PiFaceCadLcdConnection(int controller) {
super(new MCP23S17(controller, CHIP_SELECT, ADDRESS, MCP23xxx.INTERRUPT_GPIO_NOT_SET), PORT, false,
REGISTER_SELECT_BIT, DATA_READ_WRITE_BIT, ENABLE_BIT, BACKLIGHT_BIT);
}
}
/**
* Connected via the PCF8574 I2C GPIO expansion backpack.
*
* Default PCF8574 GPIO to HD44780 pin map:
*
*
* PH_PIN_RS = 0
* PH_PIN_RW = 1
* PH_PIN_ENABLE = 2
* PH_PIN_LED_EN = 3
* PH_PIN_D4 = 4
* PH_PIN_D5 = 5
* PH_PIN_D6 = 6
* PH_PIN_D7 = 7
*
*/
public static class PCF8574LcdConnection extends GpioExpansionLcdConnection {
// Default I2C device address for the PCF8574
public static final int DEFAULT_DEVICE_ADDRESS = 0x27;
// Only one port
private static final int PORT = 0;
private static final boolean DEFAULT_DATA_IN_HIGH_NIBBLE = true;
private static final int DEFAULT_REGISTER_SELECT_BIT = 0;
private static final int DEFAULT_DATA_READ_WRITE_BIT = 1;
private static final int DEFAULT_ENABLE_BIT = 2;
private static final int DEFAULT_BACKLIGHT_BIT = 3;
public PCF8574LcdConnection(int controller) {
this(controller, DEFAULT_DEVICE_ADDRESS, DEFAULT_DATA_IN_HIGH_NIBBLE, DEFAULT_REGISTER_SELECT_BIT,
DEFAULT_DATA_READ_WRITE_BIT, DEFAULT_ENABLE_BIT, DEFAULT_BACKLIGHT_BIT);
}
public PCF8574LcdConnection(int controller, int deviceAddress) {
this(controller, deviceAddress, DEFAULT_DATA_IN_HIGH_NIBBLE, DEFAULT_REGISTER_SELECT_BIT,
DEFAULT_DATA_READ_WRITE_BIT, DEFAULT_ENABLE_BIT, DEFAULT_BACKLIGHT_BIT);
}
public PCF8574LcdConnection(int controller, int deviceAddress, boolean dataInHighNibble, int registerSelectBit,
int dataReadWriteBit, int enableBit, int backlightBit) {
super(new PCF8574(controller, deviceAddress), PORT, dataInHighNibble, registerSelectBit, dataReadWriteBit,
enableBit, backlightBit);
}
}
/**
* Connect via individual GPIO pins, uses 4-bit mode (data pins D4-D7).
*
* Wiring (from left-to-right):
*
*
* Vss: GND
* Vdd: 5v
* V0: Contrast adjustment (connect to Vdd for full brightness)
* RS: Register Select - GPIO
* RW: Data read/write (not required, read mode not used - can connect to GND)
* E: Enable - GPIO
* D0-D3: Don't connect (currently only 4-bit mode is supported)
* D4-D7: Data pins - GPIO
* A: Backlight LED Cathode (+) - GPIO (need to check 3v3/5v) or Vdd (always on)
* K: Backlight LED Anode (-) - GND
*
*/
public static class GpioLcdConnection implements LcdConnection {
private static final int DATA_RW_BIT = 4;
private static final int REGISTER_SELECT_BIT = 5;
private static final int ENABLE_BIT = 6;
private static final int BACKLIGHT_BIT = 7;
private final DigitalOutputDevice[] dataPins;
private final DigitalOutputDevice registerSelectPin;
private final DigitalOutputDevice dataRwPin;
private final DigitalOutputDevice enablePin;
private final DigitalOutputDevice backlightPin;
/**
* Use the default device factory and specify GPIO numbers. Assumes the RW pin
* is pulled low and the backlight pin pulled high.
*
* @param d4 GPIO number for d4 pin
* @param d5 GPIO number for d5 pin
* @param d6 GPIO number for d6 pin
* @param d7 GPIO number for d7 pin
* @param enableGpio enable GPIO number
* @param registerSelectGpio register select GPIO number
*/
public GpioLcdConnection(int d4, int d5, int d6, int d7, int enableGpio, int registerSelectGpio) {
this(new DigitalOutputDevice(d4), new DigitalOutputDevice(d5), new DigitalOutputDevice(d6),
new DigitalOutputDevice(d7), null, new DigitalOutputDevice(enableGpio), null,
new DigitalOutputDevice(registerSelectGpio));
}
/**
* Use the default device factory and specify GPIO numbers. Assumes the RW pin
* is pulled low.
*
* @param d4 GPIO number for d4 pin
* @param d5 GPIO number for d5 pin
* @param d6 GPIO number for d6 pin
* @param d7 GPIO number for d7 pin
* @param backlightGpio backlight control GPIO number (set to -1 if not
* connected)
* @param enableGpio enable GPIO number
* @param registerSelectGpio register select GPIO number
*/
public GpioLcdConnection(int d4, int d5, int d6, int d7, int backlightGpio, int enableGpio,
int registerSelectGpio) {
this(new DigitalOutputDevice(d4), new DigitalOutputDevice(d5), new DigitalOutputDevice(d6),
new DigitalOutputDevice(d7), backlightGpio == -1 ? null : new DigitalOutputDevice(backlightGpio),
new DigitalOutputDevice(enableGpio), null, new DigitalOutputDevice(registerSelectGpio));
}
/**
* Use the default device factory and specify GPIO numbers.
*
* @param d4 GPIO number for d4 pin
* @param d5 GPIO number for d5 pin
* @param d6 GPIO number for d6 pin
* @param d7 GPIO number for d7 pin
* @param backlightGpio backlight control GPIO number (set to -1 if not
* connected)
* @param enableGpio enable GPIO number
* @param dataRwGpio data read/write GPIO number (not used - connect to
* GND, set to -1 if not connected)
* @param registerSelectGpio register select GPIO number
*/
public GpioLcdConnection(int d4, int d5, int d6, int d7, int backlightGpio, int enableGpio, int dataRwGpio,
int registerSelectGpio) {
this(new DigitalOutputDevice(d4), new DigitalOutputDevice(d5), new DigitalOutputDevice(d6),
new DigitalOutputDevice(d7), backlightGpio == -1 ? null : new DigitalOutputDevice(backlightGpio),
new DigitalOutputDevice(enableGpio), dataRwGpio == -1 ? null : new DigitalOutputDevice(dataRwGpio),
new DigitalOutputDevice(registerSelectGpio));
}
/**
* Use the specified device factory and specify GPIO numbers.
*
* @param deviceFactory the device factory to use for provisioning the
* GPIOs
* @param d4 GPIO number for d4 pin
* @param d5 GPIO number for d5 pin
* @param d6 GPIO number for d6 pin
* @param d7 GPIO number for d7 pin
* @param backlightGpio backlight control GPIO number (set to -1 if not
* connected)
* @param enableGpio enable GPIO number
* @param dataRwGpio data read/write GPIO number (not used - connect to
* GND, set to -1 if not connected)
* @param registerSelectGpio register select GPIO number
*/
public GpioLcdConnection(GpioDeviceFactoryInterface deviceFactory, int d4, int d5, int d6, int d7,
int backlightGpio, int enableGpio, int dataRwGpio, int registerSelectGpio) {
this(DigitalOutputDevice.Builder.builder(d4).setDeviceFactory(deviceFactory).build(),
DigitalOutputDevice.Builder.builder(d5).setDeviceFactory(deviceFactory).build(),
DigitalOutputDevice.Builder.builder(d6).setDeviceFactory(deviceFactory).build(),
DigitalOutputDevice.Builder.builder(d7).setDeviceFactory(deviceFactory).build(),
backlightGpio == -1 ? null
: DigitalOutputDevice.Builder.builder(backlightGpio).setDeviceFactory(deviceFactory)
.build(),
DigitalOutputDevice.Builder.builder(enableGpio).setDeviceFactory(deviceFactory).build(),
dataRwGpio == -1 ? null
: DigitalOutputDevice.Builder.builder(dataRwGpio).setDeviceFactory(deviceFactory).build(),
DigitalOutputDevice.Builder.builder(registerSelectGpio).setDeviceFactory(deviceFactory).build());
}
/**
* Use the specified digital output devices.
*
* @param d4 Digital output device for d4 pin
* @param d5 Digital output device for d5 pin
* @param d6 Digital output device for d6 pin
* @param d7 Digital output device for d7 pin
* @param backlightPin backlight control digital output device (set to null
* if not connected)
* @param enablePin enable digital output device
* @param dataRwPin data read/write digital output device (not used -
* connect to GND, set to null if not connected)
* @param registerSelectPin register select digital output device
*/
public GpioLcdConnection(DigitalOutputDevice d4, DigitalOutputDevice d5, DigitalOutputDevice d6,
DigitalOutputDevice d7, DigitalOutputDevice backlightPin, DigitalOutputDevice enablePin,
DigitalOutputDevice dataRwPin, DigitalOutputDevice registerSelectPin) {
dataPins = new DigitalOutputDevice[4];
dataPins[0] = d4;
dataPins[1] = d5;
dataPins[2] = d6;
dataPins[3] = d7;
this.backlightPin = backlightPin;
this.enablePin = enablePin;
this.dataRwPin = dataRwPin;
this.registerSelectPin = registerSelectPin;
}
@Override
public void write(byte values) {
if (backlightPin != null) {
backlightPin.setValue(BitManipulation.isBitSet(values, BACKLIGHT_BIT));
}
enablePin.setValue(BitManipulation.isBitSet(values, ENABLE_BIT));
if (dataRwPin != null) {
dataRwPin.setValue(BitManipulation.isBitSet(values, DATA_RW_BIT));
}
registerSelectPin.setValue(BitManipulation.isBitSet(values, REGISTER_SELECT_BIT));
for (int i = 0; i < dataPins.length; i++) {
dataPins[i].setValue(BitManipulation.isBitSet(values, i));
}
}
@Override
public boolean isDataInHighNibble() {
return false;
}
@Override
public int getRegisterSelectBit() {
return REGISTER_SELECT_BIT;
}
@Override
public int getDataReadWriteBit() {
return DATA_RW_BIT;
}
@Override
public int getEnableBit() {
return ENABLE_BIT;
}
@Override
public int getBacklightBit() {
return BACKLIGHT_BIT;
}
@Override
public void close() throws RuntimeIOException {
Arrays.asList(dataPins).forEach(DeviceInterface::close);
if (backlightPin != null) {
backlightPin.close();
}
enablePin.close();
if (dataRwPin != null) {
dataRwPin.close();
}
registerSelectPin.close();
}
}
}