Skip to content

Commit 6c6f244

Browse files
mcauserdhylands
authored andcommitted
Add SeeedStudio Grove RGB LCD (#10)
Uses JHD1313M1 I2C HD44780 compatible character LCD with PCA9633 I2C RGB LED driver
1 parent 50976ac commit 6c6f244

File tree

3 files changed

+257
-0
lines changed

3 files changed

+257
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Files
4343
| pyb_gpio_lcd_test.py | Pyboard test using 4-bit GPIO |
4444
| pyb_i2c_adafruit_lcd.py | Pyboard MCP23008 I2C HAL |
4545
| pyb_i2c_adafruit_lcd_test.py | Pyboard test using Adafruit backpack |
46+
| pyb_i2c_grove_rgb_lcd.py | Pyboard Grove I2C RGB LCD HAL |
47+
| pyb_i2c_grove_rgb_lcd_test.py | Pyboard test using Grove I2C RGB LCD |
4648
| pyb_i2c_lcd.py | Pyboard PCF8574 I2C HAL |
4749
| pyb_i2c_lcd_test.py | Pyboard test using PCF8574 backpack |
4850

lcd/pyb_i2c_grove_rgb_lcd.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Implements a SeeedStudio Grove RGB LCD JHD1313M1 HD44780 compatible character LCD connected on I2C."""
2+
3+
from lcd_api import LcdApi
4+
from pyb import I2C, delay
5+
6+
# No jumper selectable address
7+
DEFAULT_LCD_I2C_ADDR = 0x3e
8+
# Software configurable address
9+
DEFAULT_RGB_I2C_ADDR = 0x62
10+
11+
class I2cLcd(LcdApi):
12+
"""Implements a HD44780 character LCD connected to I2C."""
13+
14+
def __init__(self, i2c, i2c_addr, num_lines, num_columns, bl_i2c_addr):
15+
self.i2c = i2c
16+
self.i2c_addr = i2c_addr
17+
self.bl_i2c_addr = bl_i2c_addr
18+
# Put LCD into 4 bit mode
19+
self.hal_write_command(self.LCD_FUNCTION)
20+
delay(1)
21+
LcdApi.__init__(self, num_lines, num_columns)
22+
cmd = self.LCD_FUNCTION
23+
if num_lines > 1:
24+
cmd |= self.LCD_FUNCTION_2LINES
25+
self.hal_write_command(cmd)
26+
# init backlight
27+
self.i2c.mem_write(0, self.bl_i2c_addr, 0) # MODE1
28+
self.i2c.mem_write(0, self.bl_i2c_addr, 1) # MODE2
29+
30+
def backlight_rgb(self, r, g, b):
31+
self.i2c.mem_write(170, self.bl_i2c_addr, 8) # LEDOUT
32+
self.i2c.mem_write(r, self.bl_i2c_addr, 4) # Red
33+
self.i2c.mem_write(g, self.bl_i2c_addr, 3) # Green
34+
self.i2c.mem_write(b, self.bl_i2c_addr, 2) # Blue
35+
36+
def backlight_invert_on(self):
37+
self.i2c.mem_write(16, self.bl_i2c_addr, 1) # MODE2 bit4 INVRT 1=on
38+
39+
def backlight_invert_off(self):
40+
self.i2c.mem_write(0, self.bl_i2c_addr, 1) # MODE2 bit4 INVRT 0=off
41+
42+
def backlight_blink(self, duty, freq):
43+
self.i2c.mem_write(32, self.bl_i2c_addr, 1) # MODE2 bit5 DMBLNK 1=blinking
44+
self.i2c.mem_write(255, self.bl_i2c_addr, 8) # LEDOUT = PWMx + GRPPWM
45+
# blink
46+
self.i2c.mem_write(duty, self.bl_i2c_addr, 6) # GRPPWM = duty cycle
47+
self.i2c.mem_write(freq, self.bl_i2c_addr, 7) # GRPFREQ = blinking period (24hz - 10.73s)
48+
49+
def backlight_brightness(self, duty):
50+
self.i2c.mem_write(0, self.bl_i2c_addr, 1) # MODE2 bit5 DMBLNK 0=dimming
51+
self.i2c.mem_write(255, self.bl_i2c_addr, 8) # LEDOUT = PWMx + GRPPWM
52+
# set brightness
53+
self.i2c.mem_write(duty, self.bl_i2c_addr, 6) # GRPPWM = global brightness
54+
55+
def backlight_normal(self):
56+
self.i2c.mem_write(170, self.bl_i2c_addr, 8) # LEDOUT = PWMx
57+
58+
def backlight_sleep(self):
59+
self.i2c.mem_write(16, self.bl_i2c_addr, 0) # MODE1 bit4 SLEEP 1=low power mode, oscillator off
60+
61+
def backlight_wake(self):
62+
self.i2c.mem_write(0, self.bl_i2c_addr, 0) # MODE1 bit4 SLEEP 0=normal power mode
63+
64+
def hal_backlight_on(self):
65+
"""Allows the hal layer to turn the backlight on."""
66+
self.i2c.mem_write(85, self.bl_i2c_addr, 0x08)
67+
68+
def hal_backlight_off(self):
69+
"""Allows the hal layer to turn the backlight off."""
70+
self.i2c.mem_write(0, self.bl_i2c_addr, 0x08)
71+
72+
def hal_write_command(self, cmd):
73+
"""Writes a command to the LCD."""
74+
self.i2c.mem_write(cmd, self.i2c_addr, self.LCD_DDRAM)
75+
if cmd <= 3:
76+
# The home and clear commands require a worst
77+
# case delay of 4.1 msec
78+
delay(5)
79+
80+
def hal_write_data(self, data):
81+
"""Write data to the LCD."""
82+
self.i2c.mem_write(data, self.i2c_addr, self.LCD_CGRAM)

lcd/pyb_i2c_grove_rgb_lcd_test.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
"""Implements a SeeedStudio Grove RGB LCD JHD1313M1 HD44780 compatible character LCD connected on I2C."""
2+
3+
from pyb import I2C, delay, millis
4+
from pyb_i2c_grove_rgb_lcd import I2cLcd
5+
6+
import time
7+
from urandom import getrandbits
8+
9+
# No jumper selectable address
10+
DEFAULT_LCD_I2C_ADDR = 0x3e
11+
# Software configurable address
12+
DEFAULT_RGB_I2C_ADDR = 0x62
13+
14+
def test_main():
15+
"""Test function for verifying basic functionality."""
16+
print("Running test_main")
17+
i2c = I2C(1, I2C.MASTER)
18+
lcd = I2cLcd(i2c, DEFAULT_LCD_I2C_ADDR, 2, 16, DEFAULT_RGB_I2C_ADDR)
19+
lcd.putstr("It Works!\nSecond Line")
20+
lcd.backlight_rgb(255,255,255)
21+
lcd.blink_cursor_on()
22+
time.sleep_ms(1000)
23+
24+
lcd.clear()
25+
lcd.putstr("Seeed Grove LCD RGB Backlight")
26+
time.sleep_ms(1000)
27+
28+
# 16 columns, 2 rows
29+
lcd.clear()
30+
lcd.putstr("1234567890123456abcdefghijklmnop")
31+
time.sleep_ms(1000)
32+
33+
lcd.hide_cursor();
34+
lcd.clear()
35+
lcd.putstr("Red")
36+
lcd.backlight_rgb(255,0,0)
37+
time.sleep_ms(1000)
38+
39+
lcd.clear()
40+
lcd.putstr("Green")
41+
lcd.backlight_rgb(0,255,0)
42+
time.sleep_ms(1000)
43+
44+
lcd.clear()
45+
lcd.putstr("Blue")
46+
lcd.backlight_rgb(0,0,255)
47+
time.sleep_ms(1000)
48+
49+
# invert background colour
50+
lcd.clear()
51+
lcd.putstr("Blue")
52+
time.sleep_ms(1000)
53+
lcd.backlight_invert_on()
54+
lcd.putstr(" Inverted")
55+
time.sleep_ms(1000)
56+
lcd.clear()
57+
lcd.putstr("Blue")
58+
lcd.backlight_invert_off()
59+
time.sleep_ms(1000)
60+
61+
# pwm blinking
62+
lcd.clear()
63+
lcd.putstr("Blinking PWM\nDuty=127 Freq=1")
64+
lcd.backlight_rgb(255,0,0)
65+
lcd.backlight_blink(127,1)
66+
time.sleep_ms(2000)
67+
lcd.backlight_normal()
68+
69+
lcd.clear()
70+
lcd.putstr("Blinking PWM\nDuty=100 Freq=10")
71+
lcd.backlight_rgb(255,255,0)
72+
lcd.backlight_blink(100,10)
73+
time.sleep_ms(2000)
74+
lcd.backlight_normal()
75+
76+
lcd.clear()
77+
lcd.putstr("Blinking PWM\nDuty=10 Freq=20")
78+
lcd.backlight_rgb(0,255,255)
79+
lcd.backlight_blink(10,20)
80+
time.sleep_ms(5000)
81+
lcd.backlight_normal()
82+
83+
# pwm global brightness
84+
lcd.clear()
85+
lcd.putstr("Brightness 255")
86+
lcd.backlight_brightness(255)
87+
time.sleep_ms(1000)
88+
lcd.clear()
89+
lcd.putstr("Brightness 127")
90+
lcd.backlight_brightness(127)
91+
time.sleep_ms(1000)
92+
lcd.clear()
93+
lcd.putstr("Brightness 63")
94+
lcd.backlight_brightness(63)
95+
time.sleep_ms(1000)
96+
lcd.clear()
97+
lcd.putstr("Brightness 1")
98+
lcd.backlight_brightness(1)
99+
time.sleep_ms(1000)
100+
lcd.clear()
101+
lcd.putstr("Brightness 0")
102+
lcd.backlight_brightness(0)
103+
time.sleep_ms(1000)
104+
105+
# take the rgb driver oscillator offline
106+
lcd.clear()
107+
lcd.backlight_normal()
108+
lcd.backlight_brightness(255)
109+
lcd.backlight_rgb(255,0,0)
110+
111+
# low power mode
112+
lcd.backlight_sleep()
113+
lcd.putstr("low power mode\n")
114+
time.sleep_ms(2000)
115+
116+
# cant change background colour while oscillator is offline
117+
lcd.backlight_rgb(0,255,255)
118+
lcd.putstr("cant change bg")
119+
time.sleep_ms(2000)
120+
121+
# full power mode
122+
lcd.clear()
123+
lcd.putstr("full power mode\n")
124+
lcd.backlight_wake()
125+
# pending change applied
126+
lcd.putstr("bg now changed")
127+
time.sleep_ms(2000)
128+
129+
# rainbow
130+
lcd.clear()
131+
lcd.putstr("Rainbow")
132+
for i in range(2):
133+
rainbow(lcd, 10)
134+
time.sleep_ms(1000)
135+
136+
# random
137+
lcd.clear()
138+
lcd.putstr("Random")
139+
randomColors(lcd, 30, 100)
140+
141+
142+
# Helper for converting 0-255 offset to a colour tuple
143+
def wheel(offset):
144+
# The colours are a transition r - g - b - back to r
145+
offset = 255 - offset
146+
if offset < 85:
147+
return (255 - offset * 3, 0, offset * 3)
148+
if offset < 170:
149+
offset -= 85
150+
return (0, offset * 3, 255 - offset * 3)
151+
offset -= 170
152+
return (offset * 3, 255 - offset * 3, 0)
153+
154+
# Helper for setting a colour tuple
155+
def hue(lcd, n):
156+
r,g,b = wheel(n & 255)
157+
lcd.backlight_rgb(r,g,b)
158+
159+
# cycle through all colours of the rainbow
160+
def rainbow(lcd, sleep):
161+
for n in range(256):
162+
hue(lcd, n)
163+
time.sleep_ms(sleep)
164+
165+
# show n random colours
166+
def randomColors(lcd, count, sleep):
167+
for r in range(count):
168+
r,g,b = (getrandbits(8), getrandbits(8), getrandbits(8))
169+
lcd.backlight_rgb(r,g,b)
170+
time.sleep_ms(sleep)
171+
172+
#if __name__ == "__main__":
173+
test_main()

0 commit comments

Comments
 (0)