1+ from time import sleep
2+ from pymata4 import pymata4
3+ from typing import (
4+ AnyStr
5+ )
6+
7+
8+ class LiquidCrystal_I2C :
9+ LCD_CLEARDISPLAY = 0x01
10+ LCD_RETURNHOME = 0x02
11+ LCD_ENTRYMODESET = 0x04
12+ LCD_DISPLAYCONTROL = 0x08
13+ LCD_CURSORSHIFT = 0x10
14+ LCD_FUNCTIONSET = 0x20
15+ LCD_SETCGRAMADDR = 0x40
16+ LCD_SETDDRAMADDR = 0x80
17+
18+ LCD_ENTRYRIGHT = 0x00
19+ LCD_ENTRYLEFT = 0x02
20+ LCD_ENTRYSHIFTINCREMENT = 0x01
21+ LCD_ENTRYSHIFTDECREMENT = 0x00
22+
23+ LCD_DISPLAYON = 0x04
24+ LCD_DISPLAYOFF = 0x00
25+ LCD_CURSORON = 0x02
26+ LCD_CURSOROFF = 0x00
27+ LCD_BLINKON = 0x01
28+ LCD_BLINKOFF = 0x00
29+
30+ LCD_DISPLAYMOVE = 0x08
31+ LCD_CURSORMOVE = 0x00
32+ LCD_MOVERIGHT = 0x04
33+ LCD_MOVELEFT = 0x00
34+
35+ LCD_8BITMODE = 0x10
36+ LCD_4BITMODE = 0x00
37+ LCD_2LINE = 0x08
38+ LCD_1LINE = 0x00
39+ LCD_5x10DOTS = 0x04
40+ LCD_5x8DOTS = 0x00
41+
42+ LCD_BACKLIGHT = 0x08
43+ LCD_NOBACKLIGHT = 0x00
44+
45+ ENABLE_BIT = 0B00000100 # Enable bit
46+ READ_WRITE_BIT = 0B00000010 # Read/Write bit
47+ REGISTER_SELECT_BIT = 0B00000001 # Register select bit
48+
49+ _backlight_value : int = LCD_NOBACKLIGHT
50+ _display_function : int = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS
51+ _numlines : int = None
52+ _display_control : int = None
53+ _display_mode : int = None
54+ _oled : bool = True
55+
56+ def write (self , value : int ):
57+ self .send (value , self .REGISTER_SELECT_BIT )
58+
59+ def __init__ (self , address : int , column : int , row : int , board : pymata4 .Pymata4 , dotsize : int = 1 ) -> None :
60+ self .address : int = address
61+ self .column : int = column
62+ self .row : int = row
63+ if not isinstance (board , pymata4 .Pymata4 ):
64+ raise AttributeError ("argument board not from pymata4.Pymata4" )
65+ else :
66+ self .board : pymata4 .Pymata4 = board
67+
68+ self .begin (self .column , self .row , dotsize = dotsize )
69+
70+ def begin (self , column : int , lines : int , dotsize : int = LCD_5x8DOTS ) -> None :
71+ self .board .set_pin_mode_i2c ()
72+
73+ if lines >= 1 :
74+ self ._display_function = self ._display_function | self .LCD_2LINE
75+
76+ self ._numlines = lines
77+
78+ if dotsize != 0 and lines == 1 :
79+ self ._display_function = self ._display_function | self .LCD_5x10DOTS
80+
81+ sleep (0.05 )
82+
83+ self .expander_write (self ._backlight_value )
84+ sleep (1 )
85+
86+ self .write_4_bits (0x03 << 0x4 )
87+ sleep (0.0045 )
88+
89+ self .write_4_bits (0x03 << 0x4 )
90+ sleep (0.0045 )
91+
92+ self .write_4_bits (0x03 << 0x4 )
93+ sleep (0.00015 )
94+
95+ self .write_4_bits (0x02 << 0x4 )
96+
97+ self .command (self .LCD_FUNCTIONSET | self ._display_function )
98+
99+ self ._display_control = self .LCD_DISPLAYON | self .LCD_CURSOROFF | self .LCD_BLINKOFF
100+ self .enable_display ()
101+
102+ self .clear ()
103+
104+ self ._display_mode = self .LCD_ENTRYLEFT | self .LCD_ENTRYSHIFTDECREMENT
105+ self .command (self .LCD_ENTRYMODESET | self ._display_mode )
106+
107+ self .home ()
108+
109+ def clear (self ):
110+ self .command (self .LCD_CLEARDISPLAY )
111+ sleep (0.002 )
112+ if self ._oled :
113+ self .set_cursor (0 , 0 )
114+
115+ def home (self ) -> None :
116+ self .command (self .LCD_RETURNHOME )
117+ sleep (0.002 )
118+
119+ def set_cursor (self , column : int , row : int ) -> None :
120+ row_offsets = [0x00 , 0x40 , 0x14 , 0x54 ]
121+ if row > self ._numlines :
122+ row = self ._numlines - 1
123+ self .command (self .LCD_SETDDRAMADDR | (column + row_offsets [row ]))
124+
125+ def disable_display (self ) -> None :
126+ self ._display_control = self ._display_control & ~ self .LCD_DISPLAYON
127+ self .command (self .LCD_DISPLAYON | self ._display_control )
128+
129+ def enable_display (self ) -> None :
130+ self ._display_control = self ._display_control | self .LCD_DISPLAYON
131+ self .command (self .LCD_DISPLAYCONTROL | self ._display_control )
132+
133+ def disable_cursor (self ) -> None :
134+ self ._display_control = self ._display_control & ~ self .LCD_CURSORON
135+ self .command (self .LCD_DISPLAYCONTROL | self ._display_control )
136+
137+ def enable_cursor (self ) -> None :
138+ self ._display_control = self ._display_control | self .LCD_CURSORON
139+ self .command (self .LCD_DISPLAYCONTROL | self ._display_control )
140+
141+ def disable_blink (self ) -> None :
142+ self ._display_control = self ._display_control & ~ self .LCD_BLINKON
143+ self .command (self .LCD_DISPLAYCONTROL | self ._display_control )
144+
145+ def enable_blink (self ) -> None :
146+ self ._display_control = self ._display_control | self .LCD_BLINKON
147+ self .command (self .LCD_DISPLAYCONTROL | self ._display_control )
148+
149+ def scroll_display_left (self ) -> None :
150+ self .command (self .LCD_CURSORSHIFT | self .LCD_DISPLAYMOVE | self .LCD_MOVELEFT )
151+
152+ def scroll_display_right (self ) -> None :
153+ self .command (self .LCD_CURSORSHIFT | self .LCD_DISPLAYMOVE | self .LCD_MOVERIGHT )
154+
155+ def left_to_right (self ) -> None :
156+ self ._display_mode = self ._display_mode | self .LCD_ENTRYLEFT
157+ self .command (self .LCD_ENTRYMODESET | self ._display_mode )
158+
159+ def right_to_left (self ) -> None :
160+ self ._display_mode = self ._display_mode & ~ self .LCD_ENTRYLEFT
161+ self .command (self .LCD_ENTRYMODESET | self ._display_mode )
162+
163+ def enable_auto_scroll (self ) -> None :
164+ self ._display_mode = self ._display_mode | self .LCD_ENTRYSHIFTINCREMENT
165+ self .command (self .LCD_ENTRYMODESET | self ._display_mode )
166+
167+ def disable_auto_scroll (self ) -> None :
168+ self ._display_mode = self ._display_mode & ~ self .LCD_ENTRYSHIFTINCREMENT
169+ self .command (self .LCD_ENTRYMODESET | self ._display_mode )
170+
171+ def disable_backlight (self ) -> None :
172+ self ._backlight_value = self .LCD_NOBACKLIGHT
173+ self .expander_write (0 )
174+
175+ def enable_backlight (self ) -> None :
176+ self ._backlight_value = self .LCD_BACKLIGHT
177+ self .expander_write (0 )
178+
179+ def command (self , value ) -> None :
180+ self .send (value , 0 )
181+
182+ def send (self , value : int , mode : int ) -> None :
183+ high_nibble : int = value & 0xf0
184+ low_nibble : int = (value << 4 ) & 0xf0
185+ self .write_4_bits (high_nibble | mode )
186+ self .write_4_bits (low_nibble | mode )
187+
188+ def write_4_bits (self , value : int ) -> None :
189+ self .expander_write (value )
190+ self .pulse_enable (value )
191+
192+ def expander_write (self , data : int ) -> None :
193+ self .board .i2c_write (self .address , [data , self ._backlight_value ])
194+
195+ def pulse_enable (self , data : int ) -> None :
196+ self .expander_write (data | self .ENABLE_BIT )
197+ sleep (0.000001 )
198+
199+ self .expander_write (data & ~ self .ENABLE_BIT )
200+ sleep (0.00005 )
201+
202+ def print (self , string : AnyStr ) -> None :
203+ for character in string :
204+ self .write (ord (character ))
205+ sleep (0.000001 )
206+ else :
207+ sleep (0.00005 )
208+
209+
210+ Board = pymata4 .Pymata4 ("/dev/ttyACM0" )
211+ LCD = LiquidCrystal_I2C (0x27 , 0 , 1 , Board )
212+ LCD .enable_backlight ()
213+ LCD .print ("Hello, Worlds!" )
0 commit comments