Skip to content

Instantly share code, notes, and snippets.

@donrestarone
Last active January 26, 2025 23:32
Show Gist options
  • Save donrestarone/812dcd467b0df8af6a13f398156c3a3b to your computer and use it in GitHub Desktop.
Save donrestarone/812dcd467b0df8af6a13f398156c3a3b to your computer and use it in GitHub Desktop.
raspberry pi LCD 1602 I2C display script
#!/usr/bin/env python3
########################################################################
# Filename : I2CLCD1602.py
# Description : Use the LCD display data
# Author : freenove
# modification: 2023/05/15
########################################################################
import time
from time import sleep, strftime
import smbus
import subprocess
from datetime import datetime
import psutil
import os
# library class - do not change
class CharLCD1602(object):
def __init__(self):
# Note you need to change the bus number to 0 if running on a revision 1 Raspberry Pi.
self.bus = smbus.SMBus(1)
self.BLEN = 1 # turn on/off background light
self.PCF8574_address = 0x27 # I2C address of the PCF8574 chip.
self.PCF8574A_address = 0x3f # I2C address of the PCF8574A chip.
self.LCD_ADDR =self.PCF8574_address
def write_word(self,addr, data):
temp = data
if self.BLEN == 1:
temp |= 0x08
else:
temp &= 0xF7
self.bus.write_byte(addr ,temp)
def send_command(self,comm):
# Send bit7-4 firstly
buf = comm & 0xF0
buf |= 0x04 # RS = 0, RW = 0, EN = 1
self.write_word(self.LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
self.write_word(self.LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (comm & 0x0F) << 4
buf |= 0x04 # RS = 0, RW = 0, EN = 1
self.write_word(self.LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
self.write_word(self.LCD_ADDR ,buf)
def send_data(self,data):
# Send bit7-4 firstly
buf = data & 0xF0
buf |= 0x05 # RS = 1, RW = 0, EN = 1
self.write_word(self.LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
self.write_word(self.LCD_ADDR ,buf)
# Send bit3-0 secondly
buf = (data & 0x0F) << 4
buf |= 0x05 # RS = 1, RW = 0, EN = 1
self.write_word(self.LCD_ADDR ,buf)
time.sleep(0.002)
buf &= 0xFB # Make EN = 0
self.write_word(self.LCD_ADDR ,buf)
def i2c_scan(self):
cmd = "i2cdetect -y 1 |awk \'NR>1 {$1=\"\";print}\'"
result = subprocess.check_output(cmd, shell=True).decode()
result = result.replace("\n", "").replace(" --", "")
i2c_list = result.split(' ')
return i2c_list
def init_lcd(self,addr=None, bl=1):
i2c_list = self.i2c_scan()
# print(f"i2c_list: {i2c_list}")
if addr is None:
if '27' in i2c_list:
self.LCD_ADDR = self.PCF8574_address
elif '3f' in i2c_list:
self.LCD_ADDR = self.PCF8574A_address
else:
raise IOError("I2C address 0x27 or 0x3f no found.")
else:
self.LCD_ADDR = addr
if str(hex(addr)).strip('0x') not in i2c_list:
raise IOError(f"I2C address {str(hex(addr))} or 0x3f no found.")
self.BLEN = bl
try:
self.send_command(0x33) # Must initialize to 8-line mode at first
time.sleep(0.005)
self.send_command(0x32) # Then initialize to 4-line mode
time.sleep(0.005)
self.send_command(0x28) # 2 Lines & 5*7 dots
time.sleep(0.005)
self.send_command(0x0C) # Enable display without cursor
time.sleep(0.005)
self.send_command(0x01) # Clear Screen
self.buswrite_byte(self.LCD_ADDR, 0x08)
except:
return False
else:
return True
def clear(self):
self.send_command(0x01) # Clear Screen
def openlight(self): # Enable the backlight
self.bus.write_byte(0x27,0x08)
self.bus.close()
def write(self,x, y, str):
if x < 0:
x = 0
if x > 15:
x = 15
if y <0:
y = 0
if y > 1:
y = 1
# Move cursor
addr = 0x80 + 0x40 * y + x
self.send_command(addr)
for chr in str:
self.send_data(ord(chr))
def display_num(self,x, y, num):
addr = 0x80 + 0x40 * y + x
self.send_command(addr)
self.send_data(num)
#!/usr/bin/env python3
########################################################################
# Filename : I2CLCD1602.py
# Description : Use the LCD display data
# Author : freenove, @donrestarone
# modification: 2023/05/15
########################################################################
lcd1602 = CharLCD1602()
# write custom code here
def get_cpu_temp(): # get CPU temperature from file "/sys/class/thermal/thermal_zone0/temp"
tmp = open('/sys/class/thermal/thermal_zone0/temp')
cpu = tmp.read()
tmp.close()
return '{:.2f}'.format( float(cpu)/1000 ) + ' C '
def get_uptime():
uptime = os.popen('uptime -p').read()[:-1]
return uptime
def get_cpu_usage():
usage = str(psutil.cpu_percent())
return usage
def get_memory_usage():
usage = str(round(psutil.virtual_memory().available * 100 / psutil.virtual_memory().total, 2))
return usage
def get_storage():
hdd = psutil.disk_usage('/')
return '{:.2f}'.format( hdd.percent ) + ' % '
def get_time_now(): # get system time
return datetime.now().strftime("%-I:%-M %p")
def get_current_date():
return datetime.now().strftime("%a %b %-d %Y")
def loop():
lcd1602.init_lcd()
count = 0
while(True):
# alternate between greeting and dynamic info
lcd1602.clear()
lcd1602.write(0, 0, 'Hello World!' )# display greeting
lcd1602.write(0, 1, get_uptime()) # display the counter
time.sleep(1)
lcd1602.clear()
lcd1602.write(0, 0, 'Storage' )
lcd1602.write(0, 1, get_storage() + ' used' )
time.sleep(1)
lcd1602.clear()
lcd1602.write(0, 0, 'CPU' )
lcd1602.write(0, 1, get_cpu_usage() + '% ' + 'used' )
time.sleep(1)
lcd1602.clear()
lcd1602.write(0, 0, 'Memory' )
lcd1602.write(0, 1, get_memory_usage() + '% ' + 'free' )
time.sleep(1)
lcd1602.clear()
lcd1602.write(0, 0, 'CPU Temperature')# display CPU temperature
lcd1602.write(0, 1, get_cpu_temp() )
time.sleep(1)
lcd1602.clear()
lcd1602.write(0, 0, get_current_date())
lcd1602.write(0, 1, get_time_now() )
time.sleep(1)
lcd1602.clear()
count += 1
def destroy():
lcd1602.clear()
if __name__ == '__main__':
print ('Program is starting ... ')
try:
loop()
except KeyboardInterrupt:
destroy()
@donrestarone
Copy link
Author

code above adopted by combining the LCD display class and custom display script here: https://github.com/Freenove/Freenove_Complete_Starter_Kit_for_Raspberry_Pi/tree/main/Code/Python_GPIOZero_Code/20.1.1_I2CLCD1602

@donrestarone
Copy link
Author

donrestarone commented Jan 21, 2025

readme

first start

  • ensure tmux is installed
  • ensure I2C & SPI are enabled by entering raspi config: sudo raspi-config
  • at the ~ level create bash script named display.sh (dont forget to chmod +x display.sh to make it executable) that starts tmux and kicks off the python display service (display.py)
  • at the ~ level copy paste the python source above to the python script display.py
  • ensure the service file display.service exists at /etc/systemd/system/display.service
  • enable the display.service by running: sudo systemctl start display.service && sudo systemctl enable display.service

display.sh

#!/bin/bash
sessname="display"


# Create a new session named "$sessname", and run command
tmux new-session -d -s "$sessname"
tmux send-keys -t "$sessname" "python3 display.py" Enter

# Attach to session named "$sessname"
#tmux attach -t "$sessname"

display.py

see here: https://gist.github.com/donrestarone/812dcd467b0df8af6a13f398156c3a3b#file-i2clcd1602-py

display.service

[Unit]
Description=Display service
After=network.target

[Service]
WorkingDirectory=/home/donrestarone
ExecStart=/bin/bash /home/donrestarone/display.sh
Type=forking
User=donrestarone
[Install]
WantedBy=multi-user.target
  • dont forget to start and enable it! sudo systemctl start display.service && sudo systemctl enable display.service

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment