nodemcu-firmware/lua_modules/liquidcrystal/liquidcrystal.lua

184 lines
5.4 KiB
Lua

local bit = 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