102 lines
3.2 KiB
Python
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)
|
|
|
|
def async_message(self, string, line = 1):
|
|
async with lock:
|
|
result = await asyncio.to_thread(_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)
|