Witajcie!
Mam ostatnio (mówiąc ostatnio mam na myśli 2 tygodnie) bardzo duży problem z moim wyświetlaczem LCD do Raspberry Pi 3.
Żaden znaleziony w necie kod nie działa, wszelkie próby napisania go własnoręcznie legły w gruzach. Pojawił się jednak promyk nadziei - mam kod w Pythonie, który działa. Spróbowałem go przepisać na Javę i spróbować go wykonać.
Hardware
Software
Działający kod w Pythonie
#!/usr/bin/python
import smbus
import time
# Define some device parameters
I2C_ADDR = 0x3f # I2C device address
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
# LCD_BACKLIGHT = 0x00 # Off
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
# Open I2C interface
# bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33, LCD_CMD) # 110011 Initialise
lcd_byte(0x32, LCD_CMD) # 110010 Initialise
lcd_byte(0x06, LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C, LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28, LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01, LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR, (bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message, line):
# Send string to display
message = message.ljust(LCD_WIDTH, " ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]), LCD_CHR)
def main():
# Main program block
# Initialise display
lcd_init()
while True:
# Send some test
lcd_string("RPiSpy <", LCD_LINE_1)
lcd_string("I2C LCD <", LCD_LINE_2)
time.sleep(3)
# Send some more text
lcd_string("> RPiSpy", LCD_LINE_1)
lcd_string("> I2C LCD", LCD_LINE_2)
time.sleep(3)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
lcd_byte(0x01, LCD_CMD)
Prawie działający kod w Javie:
package com.burdzi0;
import com.pi4j.io.i2c.I2CBus;
import com.pi4j.io.i2c.I2CDevice;
import com.pi4j.io.i2c.I2CFactory;
import com.pi4j.io.i2c.I2CFactoryProviderRaspberry;
import com.sun.org.apache.bcel.internal.generic.I2C;
import java.io.IOException;
public class LCDController {
int I2C_ADDR = 0x3f;
int LCD_WIDTH = 16;
int LCD_CHR = 1;
int LCD_CMD = 0;
int LCD_LINE_1 = 0x80;
int LCD_LINE_2 = 0xC0;
int LCD_BACKLIGHT_ON = 0x08;
int LCD_BACKLIGHT_OFF = 0x00;
int ENABLE = 0b00000100;
int E_PULSE = 5;
int E_DELAY = 5;
I2CBus bus;
I2CDevice dev;
public LCDController() throws IOException, InterruptedException {
bus = I2CFactory.getInstance(I2CBus.BUS_1);
dev = bus.getDevice(I2C_ADDR);
init();
}
void init() throws InterruptedException, IOException {
lcd_byte(0x33, LCD_CMD);
lcd_byte(0x32, LCD_CMD);
lcd_byte(0x06, LCD_CMD);
lcd_byte(0x0C, LCD_CMD);
lcd_byte(0x28, LCD_CMD);
lcd_byte(0x01, LCD_CMD);
Thread.sleep(E_DELAY);
}
void lcd_byte(int bits, int mode) throws IOException, InterruptedException {
int bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT_ON;
int bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT_ON;
dev.write(I2C_ADDR, (byte) bits_high);
lcd_toggle_enable((byte) bits_high);
dev.write(I2C_ADDR, (byte) bits_low);
lcd_toggle_enable((byte) bits_low);
}
void lcd_toggle_enable(byte bits) throws InterruptedException, IOException {
Thread.sleep(E_DELAY);
dev.write(I2C_ADDR, (byte) (bits | ENABLE));
Thread.sleep(E_PULSE);
dev.write(I2C_ADDR, (byte) (bits & ~ENABLE));
Thread.sleep(E_DELAY);
}
void lcd_string(String message, int line) throws IOException, InterruptedException {
lcd_byte(line, LCD_CMD);
for (int i = 0; i < LCD_WIDTH; i++) {
lcd_byte(message.charAt(i), LCD_CHR);
}
}
public static void main(String[] args) {
LCDController lcd = null;
try {
lcd = new LCDController();
lcd.init();
while (true) {
lcd.lcd_string("RPiSpy <", lcd.LCD_LINE_1);
lcd.lcd_string("I2C LCD <", lcd.LCD_LINE_2);
Thread.sleep(3000);
lcd.lcd_string("> RPiSpy", lcd.LCD_LINE_1);
lcd.lcd_string("> I2C LCD", lcd.LCD_LINE_2);
Thread.sleep(3000);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
lcd.lcd_byte(0x01, lcd.LCD_CMD);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Wiem, że kod nie jest ładny, ale ma być przede wszystkim funkcjonalny. Efektem tego kodu jest:
Gdzie popełniłem błąd?
- wyswietlacz-lcd-2x16-znakow.jpg (40 KB) - ściągnięć: 134
- IMG_20170913_123509.jpg (544 KB) - ściągnięć: 113
- IMG_20170913_123512.jpg (629 KB) - ściągnięć: 180
- konwerter-i2c-dla-wyswietlacza-lcd-hd44780.jpg (43 KB) - ściągnięć: 149
- IMG_20170913_123514.jpg (685 KB) - ściągnięć: 161
- konwerter-poziomow-logicznych-dwukierunkowy-4-kanalowy-msx-.jpg (55 KB) - ściągnięć: 159
scibi92dev.write
nalistaIntów.add
, a na końcu testu porównam wynikową listę z predefiniowaną i już mam podstawowy test. Nieco trudniej by było gdybyśmy sprawdzali też jednocześnie odstępy czasowe, ale tylko nieco. Wtedy można by zrobić listę przechowującą jakiś typ podstawowy np Wrapped mający dwa podtypy WrappedData i WrappedDelay, a potem można porównywać nagrane wartości z predefiniowanymi tak samo jak w wariancie podstawowym. Banalne byłoby też przeniesienie takich testów z Pythona do Javy.Wystarczy, że na czas testu jednostkowego podmienię dev.write na listaIntów.add, a na końcu testu porównam wynikową listę z predefiniowaną i już mam podstawowy test.
w tym wypadku nie mam czegoś takiego jak lista predefiniowana, brodzę po ciemku w tym momencie, w każdym razie dzięki za pomysł ;)vpiotr