Skip to content

Commit e07e0e3

Browse files
mcauserdhylands
authored andcommitted
Docs, spelling and testing (#4)
* Move i2c_lcd tests to separate file * Spelling fixes * Use DEFAULT_I2C_ADDR constant * Combine imports * Improve comments * Add I2C address ranges * Update the Readme * Fix pyb import
1 parent 8409421 commit e07e0e3

16 files changed

+140
-117
lines changed

README.md

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,56 @@
11
lcd and i2c_lcd
22
===============
33

4-
Python code for talking to character based LCDs.
5-
6-
The I2c_Lcd class allows for talking to i2c based LCDs. There are also variants
7-
of the code for MicroPython. All of the files which start with pyb were tested
8-
on the pyboard.
4+
Python code for talking to HD44780 compatible character based dot matrix LCDs.
5+
6+
You can communicate with the LCDs using either 4 or 8 GPIO pins.
7+
8+
Alternatively, the I2C classes implement 8-bit GPIO expander boards
9+
[PCF8574](http://www.ti.com/lit/ds/symlink/pcf8574.pdf) and
10+
[MCP23008](http://www.microchip.com/wwwproducts/en/MCP23008)
11+
which reduces the number of required GPIO pins to two (SCL, SDA).
12+
The boards usually mount behind the LCDs and are commonly called "backpacks".
13+
14+
The most commonly used display is a "1602" or "16x2", which features 16 columns
15+
and 2 rows of characters. There are also other LCDs using the same HD44780
16+
controller. eg. 8x2, 16x1, 16x4, 20x2, 20x4, 40x1, 40x2. Each come in various
17+
backlight and pixel colours.
18+
19+
There are also variants of the code for [MicroPython](http://micropython.org/).
20+
All of the files which start with **pyb_** were tested on the
21+
[pyboard](https://store.micropython.org/store/#/products/PYBv1_1).
22+
Files starting with **esp8266_** were tested on a
23+
[WeMos D1 Mini](https://www.wemos.cc/product/d1-mini.html).
24+
Files starting with **nodemcu_** were tested on a
25+
[NodeMCU development board](https://en.wikipedia.org/wiki/NodeMCU).
26+
The files containing **adafruit_lcd** were tested on an Adafruit
27+
[I2C / SPI character LCD backpack](https://www.adafruit.com/product/292)
928

1029
Files
1130
=====
1231

1332
| File | Description |
1433
| ----- | ----------- |
34+
| esp8266_i2c_lcd.py | ESP8266 PCF8574 I2C HAL |
35+
| esp8266_i2c_lcd_test.py | ESP8266 test using PCF8574 backpack |
36+
| i2c_lcd.pyb | Linux PCF8574 I2C HAL |
37+
| i2c_lcd_test.pyb | Linux test using PCF8574 backpack |
1538
| lcd.py | Core logic |
16-
| i2c_lcd.pyb | Linux I2C HAL |
39+
| nodemcu_gpio_lcd.py | NodeMCU GPIO HAL |
40+
| nodemcu_gpio_lcd_test.py | NodeMCU test using 4-bit GPIO |
1741
| pyb_gpio_lcd.py | Pyboard GPIO HAL |
1842
| pyb_gpio_lcd_test8.py | Pyboard test using 8-bit GPIO |
1943
| pyb_gpio_lcd_test.py | Pyboard test using 4-bit GPIO |
20-
| pyb_i2c_adafruit_lcd.py | Pyboard I2C HAL for Adafruit backpack |
21-
| pyb_i2c_adafruit_lcd_test.py | Test for Adafruit backpack |
22-
| pyb_i2c_lcd.py | Pyboard I2C HAL for PCF8574 backpack |
23-
| pyb_i2c_lcd_test.py | Test for PCF8574 backpack |
24-
| nodemcu_gpio_lcd.py | NodeMCU GPIO HAL |
25-
| nodemcu_gpio_lcd_test.py | NodeMCU test using 4-bit GPIO |
44+
| pyb_i2c_adafruit_lcd.py | Pyboard MCP23008 I2C HAL |
45+
| pyb_i2c_adafruit_lcd_test.py | Pyboard test using Adafruit backpack |
46+
| pyb_i2c_lcd.py | Pyboard PCF8574 I2C HAL |
47+
| pyb_i2c_lcd_test.py | Pyboard test using PCF8574 backpack |
2648

2749

28-
The files which end in _test.py are examples which show how the corresponding
50+
The files which end in **_test.py** are examples which show how the corresponding
2951
file is used.
3052

31-
i2c_lcd.py was tested on a BeagleBone Black using a 2 x 16 LCD with an i2c
53+
**i2c_lcd.py** was tested on a [BeagleBone Black](https://beagleboard.org/black) using a 2 x 16 LCD with an I2C
3254
module similar to [this one](http://arduino-info.wikispaces.com/LCD-Blue-I2C).
3355

3456
This code was adapted from some C code that I had written previously for

lcd/esp8266_i2c_lcd.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
"""Implements a character based lcd connected via PCF8574 on I2C."""
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C.
2+
This was tested with: https://www.wemos.cc/product/d1-mini.html"""
23

34
from lcd_api import LcdApi
45
from machine import I2C
56
from time import sleep_ms
67

8+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
79
DEFAULT_I2C_ADDR = 0x27
810

911
# Defines shifts or masks for the various LCD line attached to the PCF8574
@@ -16,7 +18,7 @@
1618

1719

1820
class I2cLcd(LcdApi):
19-
"""Implements a character based lcd connected via PCF8574 on i2c."""
21+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""
2022

2123
def __init__(self, i2c, i2c_addr, num_lines, num_columns):
2224
self.i2c = i2c
@@ -42,8 +44,7 @@ def __init__(self, i2c, i2c_addr, num_lines, num_columns):
4244
def hal_write_init_nibble(self, nibble):
4345
"""Writes an initialization nibble to the LCD.
4446
45-
46-
This particular function is only used during intiialization.
47+
This particular function is only used during initialization.
4748
"""
4849
byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
4950
self.i2c.writeto(self.i2c_addr, bytearray([byte | MASK_E]))

lcd/esp8266_i2c_lcd_test.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1-
"""Implements a character based lcd connected via PCF8574 on i2c."""
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C.
2+
This was tested with: https://www.wemos.cc/product/d1-mini.html"""
23

34
from time import sleep_ms, ticks_ms
45
from machine import I2C, Pin
56
from esp8266_i2c_lcd import I2cLcd
67

8+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
79
DEFAULT_I2C_ADDR = 0x27
810

911
def test_main():
1012
"""Test function for verifying basic functionality."""
1113
print("Running test_main")
1214
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000)
13-
lcd = I2cLcd(i2c, 0x27, 2, 16)
15+
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
1416
lcd.putstr("It Works!\nSecond Line")
1517
sleep_ms(3000)
1618
lcd.clear()
@@ -43,4 +45,3 @@ def test_main():
4345

4446
#if __name__ == "__main__":
4547
test_main()
46-

lcd/i2c_lcd.py

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
"""Implements a character based lcd connected via PCF8574 on i2c."""
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""
22

33
from lcd_api import LcdApi
44
import smbus
55
import time
66

7+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
78
DEFAULT_I2C_ADDR = 0x27
89

910
# Defines shifts or masks for the various LCD line attached to the PCF8574
@@ -16,7 +17,7 @@
1617

1718

1819
class I2cLcd(LcdApi):
19-
"""Implements a character based lcd connected via PCF8574 on i2c."""
20+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""
2021

2122
def __init__(self, port, i2c_addr, num_lines, num_columns):
2223
self.port = port
@@ -43,7 +44,7 @@ def __init__(self, port, i2c_addr, num_lines, num_columns):
4344
def hal_write_init_nibble(self, nibble):
4445
"""Writes an initialization nibble to the LCD.
4546
46-
This particular function is only used during intiialization.
47+
This particular function is only used during initialization.
4748
"""
4849
byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
4950
self.bus.write_byte(self.i2c_addr, byte | MASK_E)
@@ -87,40 +88,3 @@ def hal_write_data(self, data):
8788
((data & 0x0f) << SHIFT_DATA))
8889
self.bus.write_byte(self.i2c_addr, byte | MASK_E)
8990
self.bus.write_byte(self.i2c_addr, byte)
90-
91-
def test_main():
92-
"""Test function for verifying basic functionality."""
93-
lcd = I2cLcd(1, 0x27, 2, 16)
94-
lcd.putstr("It Works!\nSecond Line")
95-
time.sleep(3)
96-
lcd.clear()
97-
count = 0
98-
while True:
99-
lcd.move_to(0, 0)
100-
lcd.putstr(time.strftime('%b %d %Y\n%H:%M:%S', time.localtime()))
101-
time.sleep(1)
102-
count += 1
103-
if count % 10 == 3:
104-
print "Turning backlight off"
105-
lcd.backlight_off()
106-
if count % 10 == 4:
107-
print "Turning backlight on"
108-
lcd.backlight_on()
109-
if count % 10 == 5:
110-
print "Turning display off"
111-
lcd.display_off()
112-
if count % 10 == 6:
113-
print "Turning display on"
114-
lcd.display_on()
115-
if count % 10 == 7:
116-
print "Turning display & backlight off"
117-
lcd.backlight_off()
118-
lcd.display_off()
119-
if count % 10 == 8:
120-
print "Turning display & backlight on"
121-
lcd.backlight_on()
122-
lcd.display_on()
123-
124-
if __name__ == "__main__":
125-
test_main()
126-

lcd/i2c_lcd_test.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""Implements a HD44780 character LCD connected via PCF8574 on I2C."""
2+
3+
from i2c_lcd import I2cLcd
4+
import time
5+
6+
# The PCF8574 has a jumper selectable address: 0x20 - 0x27
7+
DEFAULT_I2C_ADDR = 0x27
8+
9+
def test_main():
10+
"""Test function for verifying basic functionality."""
11+
lcd = I2cLcd(1, DEFAULT_I2C_ADDR, 2, 16)
12+
lcd.putstr("It Works!\nSecond Line")
13+
time.sleep(3)
14+
lcd.clear()
15+
count = 0
16+
while True:
17+
lcd.move_to(0, 0)
18+
lcd.putstr(time.strftime('%b %d %Y\n%H:%M:%S', time.localtime()))
19+
time.sleep(1)
20+
count += 1
21+
if count % 10 == 3:
22+
print "Turning backlight off"
23+
lcd.backlight_off()
24+
if count % 10 == 4:
25+
print "Turning backlight on"
26+
lcd.backlight_on()
27+
if count % 10 == 5:
28+
print "Turning display off"
29+
lcd.display_off()
30+
if count % 10 == 6:
31+
print "Turning display on"
32+
lcd.display_on()
33+
if count % 10 == 7:
34+
print "Turning display & backlight off"
35+
lcd.backlight_off()
36+
lcd.display_off()
37+
if count % 10 == 8:
38+
print "Turning display & backlight on"
39+
lcd.backlight_on()
40+
lcd.display_on()
41+
42+
if __name__ == "__main__":
43+
test_main()

lcd/lcd_api.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
"""Provides an API for talking to HD44780 style character LCDs."""
1+
"""Provides an API for talking to HD44780 compatible character LCDs."""
22

33

44
class LcdApi:
5-
"""Implements the API for talking with n LCD. This class only knows what
6-
commands to send to the LCD, and not how t get them to the LCD.
5+
"""Implements the API for talking with HD44780 compatible character LCDs.
6+
This class only knows what commands to send to the LCD, and not how to get
7+
them to the LCD.
78
89
It is expected that a derived class will implement the hal_xxx functions.
910
"""
@@ -65,7 +66,6 @@ def __init__(self, num_lines, num_columns):
6566
def clear(self):
6667
"""Clears the LCD display and moves the cursor to the top left
6768
corner.
68-
6969
"""
7070
self.hal_write_command(self.LCD_CLR)
7171
self.hal_write_command(self.LCD_HOME)
@@ -131,7 +131,7 @@ def move_to(self, cursor_x, cursor_y):
131131
self.hal_write_command(self.LCD_DDRAM | addr)
132132

133133
def putchar(self, char):
134-
"""Writes the indicated charcter to the LCD at the current cursor
134+
"""Writes the indicated character to the LCD at the current cursor
135135
position, and advances the cursor by one position.
136136
"""
137137
if self.cursor_x >= self.num_columns or char == '\n':
@@ -163,7 +163,6 @@ def hal_backlight_off(self):
163163
164164
If desired, a derived HAL class will implement this function.
165165
"""
166-
167166
pass
168167

169168
def hal_write_command(self, cmd):

lcd/nodemcu_gpio_lcd.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
"""Implements a HD44780 character LCD connected via NodeMCU GPIO pins."""
2+
13
from lcd_api import LcdApi
24
from machine import Pin
35
from utime import sleep_ms, sleep_us
46

7+
58
class GpioLcd(LcdApi):
6-
"""Implements a character based lcd connected via GPIO pins."""
9+
"""Implements a HD44780 character LCD connected via NodeMCU GPIO pins."""
710

811
def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
912
d2_pin=None, d3_pin=None, d4_pin=None, d5_pin=None,
1013
d6_pin=None, d7_pin=None, rw_pin=None, backlight_pin=None,
1114
num_lines=2, num_columns=16):
12-
"""Constructs the GpioLcd object. All of the arguments must pyb.Pin
13-
objects which ddescribe which pin the given line from the LCD is
15+
"""Constructs the GpioLcd object. All of the arguments must be Pin
16+
objects which describe which pin the given line from the LCD is
1417
connected to.
1518
1619
When used in 4-bit mode, only D4, D5, D6, and D7 are physically
@@ -19,7 +22,7 @@ def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
1922
if you had actually called:
2023
GpioLcd(rs, enable, d4=D4, d5=D5, d6=D6, d7=D7)
2124
22-
The enable 8-bit mode, you need pass d0 thru d7.
25+
The enable 8-bit mode, you need pass d0 through d7.
2326
2427
The rw pin isn't used by this library, but if you specify it, then
2528
it will be set low.
@@ -111,7 +114,7 @@ def hal_pulse_enable(self):
111114
def hal_write_init_nibble(self, nibble):
112115
"""Writes an initialization nibble to the LCD.
113116
114-
This particular function is only used during intiialization.
117+
This particular function is only used during initialization.
115118
"""
116119
self.hal_write_4bits(nibble >> 4)
117120

lcd/nodemcu_gpio_lcd_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Implements a character based lcd connected general purpose IO pins."""
1+
"""Implements a HD44780 character LCD connected via NodeMCU GPIO pins."""
22

33
from machine import Pin
44
from utime import sleep, ticks_ms
@@ -28,7 +28,7 @@
2828
# The Contrast line (pin 3) typically connects to the center tap of a
2929
# 10K potentiometer, and the other 2 legs of the 10K potentiometer are
3030
# connected to pins 1 and 2 (Ground and VDD)
31-
#
31+
3232

3333
def test_main():
3434
"""Test function for verifying basic functionality."""

lcd/pyb_gpio_lcd.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
1-
"""Implements a character based lcd connected via PCF8574 on i2c."""
1+
"""Implements a HD44780 character LCD connected via pyboard GPIO pins."""
22

33
from lcd_api import LcdApi
4-
from pyb import Pin
5-
from pyb import delay, udelay
4+
from pyb import Pin, delay, udelay
65

76

87
class GpioLcd(LcdApi):
9-
"""Implements a character based lcd connected via GPIO pins."""
8+
"""Implements a HD44780 character LCD connected via pyboard GPIO pins."""
109

1110
def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
1211
d2_pin=None, d3_pin=None, d4_pin=None, d5_pin=None,
1312
d6_pin=None, d7_pin=None, rw_pin=None, backlight_pin=None,
1413
num_lines=2, num_columns=16):
15-
"""Constructs the GpioLcd object. All of the arguments must pyb.Pin
16-
objects which ddescribe which pin the given line from the LCD is
14+
"""Constructs the GpioLcd object. All of the arguments must be pyb.Pin
15+
objects which describe which pin the given line from the LCD is
1716
connected to.
1817
1918
When used in 4-bit mode, only D4, D5, D6, and D7 are physically
@@ -22,7 +21,7 @@ def __init__(self, rs_pin, enable_pin, d0_pin=None, d1_pin=None,
2221
if you had actually called:
2322
GpioLcd(rs, enable, d4=D4, d5=D5, d6=D6, d7=D7)
2423
25-
The enable 8-bit mode, you need pass d0 thru d7.
24+
The enable 8-bit mode, you need pass d0 through d7.
2625
2726
The rw pin isn't used by this library, but if you specify it, then
2827
it will be set low.
@@ -114,7 +113,7 @@ def hal_pulse_enable(self):
114113
def hal_write_init_nibble(self, nibble):
115114
"""Writes an initialization nibble to the LCD.
116115
117-
This particular function is only used during intiialization.
116+
This particular function is only used during initialization.
118117
"""
119118
self.hal_write_4bits(nibble >> 4)
120119

0 commit comments

Comments
 (0)