Skip to content

Commit e474320

Browse files
committed
Added machine_i2c_lcd.py
1 parent 3b1f724 commit e474320

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ The files containing **adafruit_lcd** were tested on an Adafruit
5050
| i2c_lcd.py | Linux PCF8574 I2C HAL |
5151
| i2c_lcd_test.py | Linux test using PCF8574 backpack |
5252
| lcd_api.py | Core logic |
53+
| machine_i2c_lcd.py | Pyboard machine.I2C PCF8574 backpack |
54+
| machine_i2c_lcd_test.py | Test for machine.I2C PCF8574 backpack |
5355
| nodemcu_gpio_lcd.py | NodeMCU GPIO HAL |
5456
| nodemcu_gpio_lcd_test.py | NodeMCU test using 4-bit GPIO |
5557
| pyb_gpio_lcd.py | Pyboard GPIO HAL |

lcd/machine_i2c_lcd.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C.
2+
This was tested with: https://www.wemos.cc/product/d1-mini.html"""
3+
4+
from lcd_api import LcdApi
5+
from machine import I2C
6+
from time import sleep_ms
7+
8+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
9+
DEFAULT_I2C_ADDR = 0x27
10+
11+
# Defines shifts or masks for the various LCD line attached to the PCF8574
12+
13+
MASK_RS = 0x01
14+
MASK_RW = 0x02
15+
MASK_E = 0x04
16+
SHIFT_BACKLIGHT = 3
17+
SHIFT_DATA = 4
18+
19+
20+
class I2cLcd(LcdApi):
21+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""
22+
23+
def __init__(self, i2c, i2c_addr, num_lines, num_columns):
24+
self.i2c = i2c
25+
self.i2c_addr = i2c_addr
26+
self.i2c.writeto(self.i2c_addr, bytearray([0]))
27+
sleep_ms(20) # Allow LCD time to powerup
28+
# Send reset 3 times
29+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
30+
sleep_ms(5) # need to delay at least 4.1 msec
31+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
32+
sleep_ms(1)
33+
self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
34+
sleep_ms(1)
35+
# Put LCD into 4 bit mode
36+
self.hal_write_init_nibble(self.LCD_FUNCTION)
37+
sleep_ms(1)
38+
LcdApi.__init__(self, num_lines, num_columns)
39+
cmd = self.LCD_FUNCTION
40+
if num_lines > 1:
41+
cmd |= self.LCD_FUNCTION_2LINES
42+
self.hal_write_command(cmd)
43+
44+
def hal_write_init_nibble(self, nibble):
45+
"""Writes an initialization nibble to the LCD.
46+
47+
This particular function is only used during initialization.
48+
"""
49+
byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
50+
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))
51+
self.i2c.writeto(self.i2c_addr, bytearray([byte]))
52+
53+
def hal_backlight_on(self):
54+
"""Allows the hal layer to turn the backlight on."""
55+
self.i2c.writeto(self.i2c_addr, bytearray([1 << SHIFT_BACKLIGHT]))
56+
57+
def hal_backlight_off(self):
58+
"""Allows the hal layer to turn the backlight off."""
59+
self.i2c.writeto(self.i2c_addr, bytearray([0]))
60+
61+
def hal_write_command(self, cmd):
62+
"""Writes a command to the LCD.
63+
64+
Data is latched on the falling edge of E.
65+
"""
66+
byte = ((self.backlight << SHIFT_BACKLIGHT) | (((cmd >> 4) & 0x0f) << SHIFT_DATA))
67+
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))
68+
self.i2c.writeto(self.i2c_addr, bytearray([byte]))
69+
byte = ((self.backlight << SHIFT_BACKLIGHT) | ((cmd & 0x0f) << SHIFT_DATA))
70+
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))
71+
self.i2c.writeto(self.i2c_addr, bytearray([byte]))
72+
if cmd <= 3:
73+
# The home and clear commands require a worst case delay of 4.1 msec
74+
sleep_ms(5)
75+
76+
def hal_write_data(self, data):
77+
"""Write data to the LCD."""
78+
byte = (MASK_RS | (self.backlight << SHIFT_BACKLIGHT) | (((data >> 4) & 0x0f) << SHIFT_DATA))
79+
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))
80+
self.i2c.writeto(self.i2c_addr, bytearray([byte]))
81+
byte = (MASK_RS | (self.backlight << SHIFT_BACKLIGHT) | ((data & 0x0f) << SHIFT_DATA))
82+
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))
83+
self.i2c.writeto(self.i2c_addr, bytearray([byte]))

lcd/machine_i2c_lcd_test.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C.
2+
This was tested using an I2C backpack similar to this one:
3+
https://www.electroschematics.com/arduino-i2c-lcd-backpack-introductory-tutorial/
4+
and using a Raspberry Pi Pico
5+
"""
6+
7+
from time import sleep_ms, ticks_ms
8+
from machine import I2C, Pin
9+
from machine_i2c_lcd import I2cLcd
10+
11+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
12+
DEFAULT_I2C_ADDR = 0x27
13+
14+
def test_main():
15+
"""Test function for verifying basic functionality."""
16+
print("Running test_main")
17+
# On the RPi Pico, I2C0 shows up on GP8 (sda) and GP9 (scl)
18+
i2c = I2C(0, freq=400000)
19+
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
20+
lcd.putstr("It Works!\nSecond Line")
21+
sleep_ms(3000)
22+
lcd.clear()
23+
count = 0
24+
while True:
25+
lcd.move_to(0, 0)
26+
lcd.putstr("%7d" % (ticks_ms() // 1000))
27+
sleep_ms(1000)
28+
count += 1
29+
if count % 10 == 3:
30+
print("Turning backlight off")
31+
lcd.backlight_off()
32+
if count % 10 == 4:
33+
print("Turning backlight on")
34+
lcd.backlight_on()
35+
if count % 10 == 5:
36+
print("Turning display off")
37+
lcd.display_off()
38+
if count % 10 == 6:
39+
print("Turning display on")
40+
lcd.display_on()
41+
if count % 10 == 7:
42+
print("Turning display & backlight off")
43+
lcd.backlight_off()
44+
lcd.display_off()
45+
if count % 10 == 8:
46+
print("Turning display & backlight on")
47+
lcd.backlight_on()
48+
lcd.display_on()
49+
50+
#if __name__ == "__main__":
51+
test_main()

0 commit comments

Comments
 (0)