fancontrol/LCD.py
2026-09-26 21:21:02 +00:00

102 lines
3.2 KiB
Python

import asyncio
import smbus
import time
lock = asyncio.Lock()
class LCD:
def __init__(self, pi_rev = 2, i2c_addr = 0x3F, backlight = True):
# device constants
self.I2C_ADDR = i2c_addr
self.LCD_WIDTH = 20 # Max. characters per line
self.LCD_CHR = 1 # Mode - Sending data
self.LCD_CMD = 0 # Mode - Sending command
self.LCD_LINE_1 = 0x80 # LCD RAM addr for line one
self.LCD_LINE_2 = 0xC0 # LCD RAM addr for line two
self.LCD_LINE_3 = 0x94 # LCD RAM addr for line three
self.LCD_LINE_4 = 0xD4 # LCD RAM addr for line four
if backlight:
# on
self.LCD_BACKLIGHT = 0x08
else:
# off
self.LCD_BACKLIGHT = 0x00
self.ENABLE = 0b00000100 # Enable bit
# Timing constants
self.E_PULSE = 0.0005
self.E_DELAY = 0.0005
# Open I2C interface
if pi_rev == 2:
# Rev 2 Pi uses 1
self.bus = smbus.SMBus(1)
elif pi_rev == 1:
# Rev 1 Pi uses 0
self.bus = smbus.SMBus(0)
else:
raise ValueError('pi_rev param must be 1 or 2')
# Initialise display
self.lcd_byte(0x33, self.LCD_CMD) # 110011 Initialise
self.lcd_byte(0x32, self.LCD_CMD) # 110010 Initialise
self.lcd_byte(0x06, self.LCD_CMD) # 000110 Cursor move direction
self.lcd_byte(0x0C, self.LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
self.lcd_byte(0x28, self.LCD_CMD) # 101000 Data length, number of lines, font size
self.lcd_byte(0x01, self.LCD_CMD) # 000001 Clear display
def lcd_byte(self, bits, mode):
# Send byte to data pins
# bits = data
# mode = 1 for data, 0 for command
bits_high = mode | (bits & 0xF0) | self.LCD_BACKLIGHT
bits_low = mode | ((bits<<4) & 0xF0) | self.LCD_BACKLIGHT
# High bits
self.bus.write_byte(self.I2C_ADDR, bits_high)
self.toggle_enable(bits_high)
# Low bits
self.bus.write_byte(self.I2C_ADDR, bits_low)
self.toggle_enable(bits_low)
def toggle_enable(self, bits):
time.sleep(self.E_DELAY)
self.bus.write_byte(self.I2C_ADDR, (bits | self.ENABLE))
time.sleep(self.E_PULSE)
self.bus.write_byte(self.I2C_ADDR,(bits & ~self.ENABLE))
time.sleep(self.E_DELAY)
async def async_message(self, string, line = 1):
async with lock:
result = await asyncio.to_thread(self._message, string = string, line = line)
def _message(self, string, line = 1):
# display message string on indicated LCD line
if line == 1:
lcd_line = self.LCD_LINE_1
elif line == 2:
lcd_line = self.LCD_LINE_2
elif line == 3:
lcd_line = self.LCD_LINE_3
elif line == 4:
lcd_line = self.LCD_LINE_4
else:
raise ValueError('line number out of range')
string = string.ljust(self.LCD_WIDTH," ")
self.lcd_byte(lcd_line, self.LCD_CMD)
for i in range(self.LCD_WIDTH):
self.lcd_byte(ord(string[i]), self.LCD_CHR)
def clear(self):
# clear LCD display
self.lcd_byte(0x01, self.LCD_CMD)