-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlcdui.py
262 lines (210 loc) · 8 KB
/
lcdui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
import smbus
import getopt
import sys
from time import *
from time import gmtime, strftime
# TODO: Factor out all device_write calls to some PCF8574 specific module ...
# will be different with another io expander
# communication from expander to display: high nibble first, then low nibble
# communication via i2c to the PCF 8547: bits are processed from highest to lowest (send P7 bit first)
# General i2c device class so that other devices can be added easily
class i2c_device:
def __init__(self, addr, port):
self.addr = addr
self.bus = smbus.SMBus(port)
def write(self, byte):
self.bus.write_byte(self.addr, byte)
def read(self):
return self.bus.read_byte(self.addr)
def read_nbytes_data(self, data, n): # For sequential reads > 1 byte
return self.bus.read_i2c_block_data(self.addr, data, n)
class ioexpander:
def __init__(self):
pass
class lcd:
#initializes objects and lcd
# LCD Commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# Flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# Flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# Flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
# flags for backlight control
LCD_BACKLIGHT = 0x08
LCD_NOBACKLIGHT = 0x00
EN = 0b00000100 # Enable bit
RW = 0b00000010 # Read/Write bit
RS = 0b00000001 # Register select bit
'''
new pinout:
----------
0x80 P7 - - D7
0x40 P6 - - D6
0x20 P5 - - D5
0x10 P4 - - D4
-----------
0x08 P3 - - BL Backlight ???
0x04 P2 - - EN Starts Data read/write
0x02 P1 - - RW low: write, high: read
0x01 P0 - - RS Register Select: 0: Instruction Register (IR) (AC when read), 1: data register (DR)
'''
def __init__(self, addr, port, withBacklight=True, withOneTimeInit=False):
'''
device writes!
crosscheck also http://www.monkeyboard.org/tutorials/81-display/70-usb-serial-to-hd44780-lcd
here a sequence is listed
'''
self.displayshift = (self.LCD_CURSORMOVE |
self.LCD_MOVERIGHT)
self.displaymode = (self.LCD_ENTRYLEFT |
self.LCD_ENTRYSHIFTDECREMENT)
self.displaycontrol = (self.LCD_DISPLAYON |
self.LCD_CURSOROFF |
self.LCD_BLINKOFF)
if withBacklight:
self.blFlag=self.LCD_BACKLIGHT
else:
self.blFlag=self.LCD_NOBACKLIGHT
self.lcd_device = i2c_device(addr, port)
# we can initialize the display only once after it had been powered on
if(withOneTimeInit):
self.lcd_device.write(0x20)
self.lcd_strobe()
sleep(0.0100) # TODO: Not clear if we have to wait that long
self.lcd_write(self.LCD_FUNCTIONSET | self.LCD_4BITMODE | self.LCD_2LINE | self.LCD_5x8DOTS) # 0x28
self.lcd_write(self.LCD_DISPLAYCONTROL | self.displaycontrol) # 0x08 + 0x4 = 0x0C
self.lcd_write(self.LCD_ENTRYMODESET | self.displaymode) # 0x06
self.lcd_write(self.LCD_CLEARDISPLAY) # 0x01
self.lcd_write(self.LCD_CURSORSHIFT | self.displayshift) # 0x14
self.lcd_write(self.LCD_RETURNHOME)
# Try to make a function to control backlight
def lcd_backlight(self, value):
if value:
self.blFlag=self.LCD_BACKLIGHT
else:
self.blFlag=self.LCD_NOBACKLIGHT
# clocks EN to latch command
def lcd_strobe(self):
self.lcd_device.write((self.lcd_device.read() | self.EN | self.blFlag)) # | 0b0000 0100 # set "EN" high
self.lcd_device.write(( (self.lcd_device.read() | self.blFlag) & 0xFB)) # & 0b1111 1011 # set "EN" low
# write data to lcd in 4 bit mode, 2 nibbles
# high nibble is sent first
def lcd_write(self, cmd):
#write high nibble first
self.lcd_device.write( (cmd & 0xF0) | self.blFlag )
hi= self.lcd_device.read()
self.lcd_strobe()
# write low nibble second ...
self.lcd_device.write( (cmd << 4) | self.blFlag )
lo= self.lcd_device.read()
self.lcd_strobe()
self.lcd_device.write(self.blFlag)
# write a character to lcd (or character rom) 0x09: backlight | RS=DR
# works as expected
def lcd_write_char(self, charvalue):
controlFlag = self.blFlag | self.RS
# write high nibble
self.lcd_device.write((controlFlag | (charvalue & 0xF0)))
self.lcd_strobe()
# write low nibble
self.lcd_device.write((controlFlag | (charvalue << 4)))
self.lcd_strobe()
self.lcd_device.write(self.blFlag)
# put char function
def lcd_putc(self, char):
self.lcd_write_char(ord(char))
def _setDDRAMAdress(self, line, col):
# we write to the Data Display RAM (DDRAM)
# TODO: Factor line offsets for other display organizations; this is for 20x4 only
if line == 1:
self.lcd_write(self.LCD_SETDDRAMADDR | (0x00 + col) )
if line == 2:
self.lcd_write(self.LCD_SETDDRAMADDR | (0x40 + col) )
if line == 3:
self.lcd_write(self.LCD_SETDDRAMADDR | (0x14 + col) )
if line == 4:
self.lcd_write(self.LCD_SETDDRAMADDR | (0x54 + col) )
# put string function
def lcd_puts(self, string, line):
self._setDDRAMAdress(line, 0)
for char in string:
self.lcd_putc(char)
# clear lcd and set to home
def lcd_clear(self):
# self.lcd_write(0x10)
self.lcd_write(self.LCD_CLEARDISPLAY)
# self.lcd_write(0x20)
self.lcd_write(self.LCD_RETURNHOME)
# add custom characters (0 - 7)
def lcd_load_custon_chars(self, fontdata):
self.lcd_device.bus.write(0x40);
for char in fontdata:
for line in char:
self.lcd_write_char(line)
# Let them know how it works
def usage():
print 'Usage: lcdui.py --init --debug --backlightoff'
# Handle the command line arguments
def main():
initFlag=False
debug=False
backlight=True
try:
opts, args = getopt.getopt(sys.argv[1:],"idb",["init","debug","backlightoff"])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt == '-h':
usage()
sys.exit()
elif opt in ("-i", "--init"):
initFlag = True
elif opt in ("-d", "--debug"):
debug = True
elif opt in ("-b", "--backlightoff"):
backlight = False
if initFlag:
print "Doing initial init ..."
else:
print "Skipping init ..."
device = lcd(0x27,1,backlight, initFlag)
device.lcd_puts("01234567890123456789",1)
device.lcd_puts("Test test og test 12",2)
device.lcd_puts("Og test paa 3 raekke",3)
device.lcd_puts(strftime("%Y-%m-%d %H:%M:%S", gmtime()),4)
sleep(3)
device.lcd_clear()
device.lcd_puts(" Simple Clock ",1)
while True:
device.lcd_puts(strftime("%Y-%m-%d %H:%M:%S ", gmtime()),3)
sleep(1)
if __name__ == '__main__':
main()