From c95424b6ecb771f57dbbacd59a69894c1150d4fd Mon Sep 17 00:00:00 2001 From: Saumit Dinesan Date: Sat, 22 Apr 2023 23:31:40 +0530 Subject: Adding 16x2 lcd drivers+IP Display script --- lcd-ipaddress-display/dispip.py | 20 +++ lcd-ipaddress-display/drivers/__init__.py | 1 + lcd-ipaddress-display/drivers/i2c_dev.py | 272 ++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 lcd-ipaddress-display/dispip.py create mode 100644 lcd-ipaddress-display/drivers/__init__.py create mode 100644 lcd-ipaddress-display/drivers/i2c_dev.py (limited to 'lcd-ipaddress-display') diff --git a/lcd-ipaddress-display/dispip.py b/lcd-ipaddress-display/dispip.py new file mode 100644 index 0000000..22b044c --- /dev/null +++ b/lcd-ipaddress-display/dispip.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +import drivers +from time import sleep +from subprocess import check_output + +display = drivers.Lcd() + +try: + # Retrieve the IP address + IP = check_output(["hostname", "-I"]).split()[0].decode() + print("Writing to display") + while True: + display.lcd_display_string("IP Address: ", 1) + display.lcd_display_string(str(IP), 2) # Display the IP address on the second line + # sleep(1) # Uncomment the following line to loop with 1 sec delay +except KeyboardInterrupt: + # If there is a KeyboardInterrupt (when you press ctrl+c), exit the program and cleanup + print("Cleaning up!") + display.lcd_clear() diff --git a/lcd-ipaddress-display/drivers/__init__.py b/lcd-ipaddress-display/drivers/__init__.py new file mode 100644 index 0000000..f6fa541 --- /dev/null +++ b/lcd-ipaddress-display/drivers/__init__.py @@ -0,0 +1 @@ +from .i2c_dev import Lcd, CustomCharacters diff --git a/lcd-ipaddress-display/drivers/i2c_dev.py b/lcd-ipaddress-display/drivers/i2c_dev.py new file mode 100644 index 0000000..3a0a252 --- /dev/null +++ b/lcd-ipaddress-display/drivers/i2c_dev.py @@ -0,0 +1,272 @@ +from smbus import SMBus +from RPi.GPIO import RPI_REVISION +from time import sleep +from re import findall, match +from subprocess import check_output +from os.path import exists + +# old and new versions of the RPi have swapped the two i2c buses +# they can be identified by RPI_REVISION (or check sysfs) +BUS_NUMBER = 0 if RPI_REVISION == 1 else 1 + +# other commands +LCD_CLEARDISPLAY = 0x01 +LCD_RETURNHOME = 0x02 +LCD_ENTRYMODESET = 0x04 +LCD_DISPLAYCONTROL = 0x08 +LCD_CURSORSHIFT = 0x10 +LCD_FUNCTIONSET = 0x20 +LCD_SETCGRAMADDR = 0x40 +LCD_SETDDRAMADDR = 0x80 + +# flags for display entry mode +LCD_ENTRYRIGHT = 0x00 +LCD_ENTRYLEFT = 0x02 +LCD_ENTRYSHIFTINCREMENT = 0x01 +LCD_ENTRYSHIFTDECREMENT = 0x00 + +# flags for display on/off control +LCD_DISPLAYON = 0x04 +LCD_DISPLAYOFF = 0x00 +LCD_CURSORON = 0x02 +LCD_CURSOROFF = 0x00 +LCD_BLINKON = 0x01 +LCD_BLINKOFF = 0x00 + +# flags for display/cursor shift +LCD_DISPLAYMOVE = 0x08 +LCD_CURSORMOVE = 0x00 +LCD_MOVERIGHT = 0x04 +LCD_MOVELEFT = 0x00 + +# flags for function set +LCD_8BITMODE = 0x10 +LCD_4BITMODE = 0x00 +LCD_2LINE = 0x08 +LCD_1LINE = 0x00 +LCD_5x10DOTS = 0x04 +LCD_5x8DOTS = 0x00 + +# flags for backlight control +LCD_BACKLIGHT = 0x08 +LCD_NOBACKLIGHT = 0x00 + +En = 0b00000100 # Enable bit +Rw = 0b00000010 # Read/Write bit +Rs = 0b00000001 # Register select bit + +class I2CDevice: + def __init__(self, addr=None, addr_default=None, bus=BUS_NUMBER): + if not addr: + # try autodetect address, else use default if provided + try: + self.addr = int('0x{}'.format( + findall("[0-9a-z]{2}(?!:)", check_output(['/usr/sbin/i2cdetect', '-y', str(BUS_NUMBER)]).decode())[0]), base=16) \ + if exists('/usr/sbin/i2cdetect') else addr_default + except: + self.addr = addr_default + else: + self.addr = addr + self.bus = SMBus(bus) + + # write a single command + def write_cmd(self, cmd): + self.bus.write_byte(self.addr, cmd) + sleep(0.0001) + + # write a command and argument + def write_cmd_arg(self, cmd, data): + self.bus.write_byte_data(self.addr, cmd, data) + sleep(0.0001) + + # write a block of data + def write_block_data(self, cmd, data): + self.bus.write_block_data(self.addr, cmd, data) + sleep(0.0001) + + # read a single byte + def read(self): + return self.bus.read_byte(self.addr) + + # read + def read_data(self, cmd): + return self.bus.read_byte_data(self.addr, cmd) + + # read a block of data + def read_block_data(self, cmd): + return self.bus.read_block_data(self.addr, cmd) + + +class Lcd: + def __init__(self, addr=None): + self.addr = addr + self.lcd = I2CDevice(addr=self.addr, addr_default=0x27) + self.lcd_write(0x03) + self.lcd_write(0x03) + self.lcd_write(0x03) + self.lcd_write(0x02) + self.lcd_write(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS | LCD_4BITMODE) + self.lcd_write(LCD_DISPLAYCONTROL | LCD_DISPLAYON) + self.lcd_write(LCD_CLEARDISPLAY) + self.lcd_write(LCD_ENTRYMODESET | LCD_ENTRYLEFT) + sleep(0.2) + + # clocks EN to latch command + def lcd_strobe(self, data): + self.lcd.write_cmd(data | En | LCD_BACKLIGHT) + sleep(.0005) + self.lcd.write_cmd(((data & ~En) | LCD_BACKLIGHT)) + sleep(.0001) + + def lcd_write_four_bits(self, data): + self.lcd.write_cmd(data | LCD_BACKLIGHT) + self.lcd_strobe(data) + + # write a command to lcd + def lcd_write(self, cmd, mode=0): + self.lcd_write_four_bits(mode | (cmd & 0xF0)) + self.lcd_write_four_bits(mode | ((cmd << 4) & 0xF0)) + + # put string function + def lcd_display_string(self, string, line): + if line == 1: + self.lcd_write(0x80) + if line == 2: + self.lcd_write(0xC0) + if line == 3: + self.lcd_write(0x94) + if line == 4: + self.lcd_write(0xD4) + for char in string: + self.lcd_write(ord(char), Rs) + + # put extended string function. Extended string may contain placeholder like {0xFF} for + # displaying the particular symbol from the symbol table + def lcd_display_extended_string(self, string, line): + if line == 1: + self.lcd_write(0x80) + if line == 2: + self.lcd_write(0xC0) + if line == 3: + self.lcd_write(0x94) + if line == 4: + self.lcd_write(0xD4) + # Process the string + while string: + # Trying to find pattern {0xFF} representing a symbol + result = match(r'\{0[xX][0-9a-fA-F]{2}\}', string) + if result: + self.lcd_write(int(result.group(0)[1:-1], 16), Rs) + string = string[6:] + else: + self.lcd_write(ord(string[0]), Rs) + string = string[1:] + + # clear lcd and set to home + def lcd_clear(self): + self.lcd_write(LCD_CLEARDISPLAY) + self.lcd_write(LCD_RETURNHOME) + + # backlight control (on/off) + # options: lcd_backlight(1) = ON, lcd_backlight(0) = OFF + def lcd_backlight(self, state): + if state == 1: + self.lcd.write_cmd(LCD_BACKLIGHT) + elif state == 0: + self.lcd.write_cmd(LCD_NOBACKLIGHT) + +class CustomCharacters: + def __init__(self, lcd): + self.lcd = lcd + # Data for custom character #1. Code {0x00}. + self.char_1_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #2. Code {0x01} + self.char_2_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #3. Code {0x02} + self.char_3_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #4. Code {0x03} + self.char_4_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #5. Code {0x04} + self.char_5_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #6. Code {0x05} + self.char_6_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #7. Code {0x06} + self.char_7_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + # Data for custom character #8. Code {0x07} + self.char_8_data = ["11111", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "11111"] + + # load custom character data to CG RAM for later use in extended string. Data for + # characters is hold in file custom_characters.txt in the same folder as i2c_dev.py + # file. These custom characters can be used in printing of extended string with a + # placeholder with desired character codes: 1st - {0x00}, 2nd - {0x01}, 3rd - {0x02}, + # 4th - {0x03}, 5th - {0x04}, 6th - {0x05}, 7th - {0x06} and 8th - {0x07}. + def load_custom_characters_data(self): + self.chars_list = [self.char_1_data, self.char_2_data, self.char_3_data, + self.char_4_data, self.char_5_data, self.char_6_data, + self.char_7_data, self.char_8_data] + + # commands to load character adress to RAM srarting from desired base adresses: + char_load_cmds = [0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x78] + for char_num in range(8): + # command to start loading data into CG RAM: + self.lcd.lcd_write(char_load_cmds[char_num]) + for line_num in range(8): + line = self.chars_list[char_num][line_num] + binary_str_cmd = "0b000{0}".format(line) + self.lcd.lcd_write(int(binary_str_cmd, 2), Rs) -- cgit v1.2.3