Last active
January 26, 2025 23:32
-
-
Save donrestarone/812dcd467b0df8af6a13f398156c3a3b to your computer and use it in GitHub Desktop.
raspberry pi LCD 1602 I2C display script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() | |
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 nameddisplay.sh
(dont forget tochmod +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 scriptdisplay.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
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