-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathliquidcrystal.lua
183 lines (153 loc) · 5.4 KB
/
liquidcrystal.lua
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
local bit = bit --luacheck: read globals bit
-- metatable
local LiquidCrystal = {}
LiquidCrystal.__index = LiquidCrystal
-- commands
local LCD_CLEARDISPLAY = 0x01
local LCD_RETURNHOME = 0x02
local LCD_ENTRYMODESET = 0x04
local LCD_DISPLAYCONTROL = 0x08
local LCD_CURSORSHIFT = 0x10
local LCD_FUNCTIONSET = 0x20
local LCD_SETCGRAMADDR = 0x40
local LCD_SETDDRAMADDR = 0x80
-- flags for display entry mode
-- local LCD_ENTRYRIGHT = 0x00
local LCD_ENTRYLEFT = 0x02
local LCD_ENTRYSHIFTINCREMENT = 0x01
-- local LCD_ENTRYSHIFTDECREMENT = 0x00
-- flags for display on/off control
local LCD_DISPLAYON = 0x04
-- local LCD_DISPLAYOFF = 0x00
local LCD_CURSORON = 0x02
-- local LCD_CURSOROFF = 0x00
local LCD_BLINKON = 0x01
-- local LCD_BLINKOFF = 0x00
-- flags for display/cursor shift
local LCD_DISPLAYMOVE = 0x08
local LCD_CURSORMOVE = 0x00
local LCD_MOVERIGHT = 0x04
local LCD_MOVELEFT = 0x00
-- flags for function set
local LCD_8BITMODE = 0x10
local LCD_4BITMODE = 0x00
local LCD_2LINE = 0x08
local LCD_1LINE = 0x00
local LCD_5x10DOTS = 0x04
local LCD_5x8DOTS = 0x00
function LiquidCrystal:autoscroll(on)
if on then
self._displaymode = bit.bor(self._displaymode, LCD_ENTRYSHIFTINCREMENT)
else
self._displaymode = bit.band(self._displaymode, bit.bnot(LCD_ENTRYSHIFTINCREMENT))
end
return self:_command(bit.bor(LCD_ENTRYMODESET, self._displaymode))
end
function LiquidCrystal:blink(on)
if on then
self._displaycontrol = bit.bor(self._displaycontrol, LCD_BLINKON)
else
self._displaycontrol = bit.band(self._displaycontrol, bit.bnot(LCD_BLINKON))
end
return self:_command(bit.bor(LCD_DISPLAYCONTROL, self._displaycontrol))
end
function LiquidCrystal:clear() return self:_command(LCD_CLEARDISPLAY) end
function LiquidCrystal:cursorLeft()
return self:_command(bit.bor(LCD_CURSORSHIFT, LCD_CURSORMOVE, LCD_MOVELEFT))
end
function LiquidCrystal:cursorMove(col, row)
return self:_command(bit.bor(LCD_SETDDRAMADDR, col + (row and (self._offsets[row] - 1) or 0)))
end
function LiquidCrystal:cursor(on)
if on then
self._displaycontrol = bit.bor(self._displaycontrol, LCD_CURSORON)
else
self._displaycontrol = bit.band(self._displaycontrol, bit.bnot(LCD_CURSORON))
end
return self:_command(bit.bor(LCD_DISPLAYCONTROL, self._displaycontrol))
end
function LiquidCrystal:cursorRight()
return self:_command(bit.bor(LCD_CURSORSHIFT, LCD_CURSORMOVE, LCD_MOVERIGHT))
end
function LiquidCrystal:customChar(index, bytes)
local pos = self:position()
self:_command(bit.bor(LCD_SETCGRAMADDR,
bit.lshift(bit.band(self._eightdots and index or bit.clear(index, 0),
0x7), 3)))
for i=1,(self._eightdots and 8 or 11) do self:_write(bytes[i] or 0) end
self:cursorMove(pos)
end
function LiquidCrystal:display(on)
if on then
self._displaycontrol = bit.bor(self._displaycontrol, LCD_DISPLAYON)
else
self._displaycontrol = bit.band(self._displaycontrol, bit.bnot(LCD_DISPLAYON))
end
return self:_command(bit.bor(LCD_DISPLAYCONTROL, self._displaycontrol))
end
function LiquidCrystal:home() return self:_command(LCD_RETURNHOME) end
function LiquidCrystal:leftToRight()
self._displaymode = bit.bor(self._displaymode, LCD_ENTRYLEFT)
return self:_command(bit.bor(LCD_ENTRYMODESET, self._displaymode))
end
function LiquidCrystal:readCustom(index)
local pos = self:position()
local data = {}
self:_command(bit.bor(LCD_SETCGRAMADDR,
bit.lshift(bit.band(self._eightdots and index or bit.clear(index, 0),
0x7), 3)))
for i=1,(self._eightdots and 8 or 11) do data[i] = self:read() end
self:cursorMove(pos)
return data
end
function LiquidCrystal:rightToLeft()
self._displaymode = bit.band(self._displaymode, bit.bnot(LCD_ENTRYLEFT))
self:_command(bit.bor(LCD_ENTRYMODESET, self._displaymode))
end
function LiquidCrystal:scrollLeft()
return self:_command(bit.bor(LCD_CURSORSHIFT, LCD_DISPLAYMOVE, LCD_MOVELEFT))
end
function LiquidCrystal:scrollRight()
return self:_command(bit.bor(LCD_CURSORSHIFT, LCD_DISPLAYMOVE, LCD_MOVERIGHT))
end
function LiquidCrystal:write(...)
for _, x in ipairs({...}) do
if type(x) == "number" then
self:_write(x)
end
if type(x) == "string" then
for i=1,#x do
self:_write(string.byte(x, i))
end
end
end
end
return function (backend, onelinemode, eightdotsmode, column_width)
local self = {}
setmetatable(self, LiquidCrystal)
-- copy out backend functions, to avoid a long-lived table
self._command = backend.command
self.busy = backend.busy
self.position = backend.position
self._write = backend.write
self.read = backend.read
self.backlight = backend.backlight
-- defaults
self._displaycontrol = 0
self._displaymode = 0
self._eightdots = eightdotsmode
self._offsets = {0, 0x40}
if column_width ~= nil then
self._offsets[3] = 0 + column_width
self._offsets[4] = 0x40 + column_width
end
self:_command(bit.bor(LCD_FUNCTIONSET,
bit.bor(
backend.fourbits and LCD_4BITMODE or LCD_8BITMODE,
onelinemode and LCD_1LINE or LCD_2LINE,
eightdotsmode and LCD_5x8DOTS or LCD_5x10DOTS)))
self:_command(bit.bor(LCD_ENTRYMODESET, self._displaymode))
self:display(true)
self:clear()
return self
end