├── .gitignore ├── LICENSE.md ├── README.md ├── example.lua └── i2clcd.lua /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Enrico Gueli. 2 | 3 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `nodemcu-i2clcd`: a NodeMCU module for Adafruit's LCD backpack 2 | 3 | 4 | This small library allows you to connect an ESP8266 running NodeMCU to a character LCD display based on the HD44780 chip. 5 | 6 | To use as little GPIOs as possible, this library assumes that the display is connected to the ESP8266 through an I2C expander, specifically the Microchip MCP23008 in Adafruit's [i2c / SPI character LCD backpack](https://www.adafruit.com/products/292). 7 | 8 | The code is a mix between Adafruit's [LiquidCrystal library](https://github.com/adafruit/LiquidCrystal) for Arduino and the code from [this forum post](http://www.esp8266.com/viewtopic.php?p=11075#p11075). 9 | 10 | ## Usage 11 | ```lua 12 | local lcd = require("i2clcd") 13 | 14 | -- use GPIO pin 7 and 6 for SDA and SCL respectively, 15 | -- and tell the library the display is 16x2 characters big. 16 | lcd.begin(7, 6, 16, 2) 17 | lcd.setBacklight(1) -- will turn on backlight if available 18 | lcd.print("Hello world!") 19 | ``` 20 | 21 | ## Prerequisites 22 | 23 | ### Hardware 24 | * An ESP8266 module 25 | * Adafruit's i2c / SPI character LCD backpack 26 | * A level shifter like [this](http://www.adafruit.com/products/757), because ESP8266 works with 3.3V TTL, but the backpack works at 5V levels 27 | 28 | ### Software 29 | * NodeMCU with the following modules built: node, GPIO, file, i2c, tmr, bit 30 | * The [mcp23008 module for NodeMCU](https://github.com/CHERTS/esp8266-devkit/tree/master/Espressif/examples/nodemcu-firmware/lua_modules/mcp23008) 31 | 32 | 33 | -------------------------------------------------------------------------------- /example.lua: -------------------------------------------------------------------------------- 1 | local lcd = require("i2clcd") 2 | 3 | lcd.begin(7, 6, 16, 2) 4 | lcd.print("Hello world!") 5 | 6 | local t = 0 7 | tmr.alarm(0, 1000, 1, function() 8 | lcd.setCursor(0, 1) 9 | lcd.print(tostring(t)) 10 | lcd.print(" heap:") 11 | lcd.print(tostring(node.heap())) 12 | lcd.setBacklight(1) 13 | tmr.alarm(1, 500, 1, function() 14 | lcd.setBacklight(0) 15 | end) 16 | t = t+1 17 | end) 18 | -------------------------------------------------------------------------------- /i2clcd.lua: -------------------------------------------------------------------------------- 1 | local moduleName = ... 2 | 3 | local M = {} 4 | _G[moduleName] = M 5 | 6 | local mcp = require ("mcp23008") 7 | 8 | local lines = 16 9 | local rows = 2 10 | 11 | local backlight = 0 12 | 13 | local function sendLcdToI2C(rs, e, data) 14 | local value = bit.lshift(rs, 1) 15 | value = value + bit.lshift(e, 2) 16 | value = value + bit.rshift(data, 1) 17 | value = value + backlight 18 | mcp.writeGPIO(value) 19 | end 20 | 21 | local function sendLcdRaw(rs, data) 22 | sendLcdToI2C(rs, 1, data) 23 | sendLcdToI2C(rs, 0, data) 24 | end 25 | 26 | local function sendLcd(rs, data) 27 | sendLcdRaw(rs, bit.band(data, 0xf0)) -- high nibble 28 | sendLcdRaw(rs, bit.lshift(bit.band(data, 0x0f), 4)) -- low nibble 29 | end 30 | 31 | function M.begin(pinSDA,pinSCL,lcdCols,lcdLines,address) 32 | address = address or 0 33 | lines = lcdLines 34 | cols = lcdCols 35 | 36 | mcp.begin(address,pinSDA,pinSCL,i2c.SLOW) 37 | mcp.writeIODIR(0x00) -- make all GPIO pins as outputs 38 | 39 | -- reset 40 | sendLcdRaw(0, 0x30) 41 | tmr.delay(5000) 42 | sendLcdRaw(0, 0x30) 43 | tmr.delay(5000) 44 | sendLcdRaw(0, 0x30) 45 | tmr.delay(5000) 46 | 47 | -- set to 4-bit mode 48 | sendLcdRaw(0, 0x20) 49 | 50 | -- set to 2-line mode (TODO read args) 51 | sendLcd(0, 0x28) 52 | 53 | -- clear display 54 | sendLcd(0, 0x01) 55 | 56 | -- turn on display 57 | sendLcd(0, 0x0c) 58 | end 59 | 60 | function M.write(ch) 61 | sendLcd(1, string.byte(ch, 1)) 62 | end 63 | 64 | function M.print(s) 65 | for i = 1, #s do 66 | sendLcd(1, string.byte(s, i)) 67 | end 68 | end 69 | 70 | M.ROW_OFFSETS = {0, 0x40, 0x14, 0x54} 71 | 72 | function M.setCursor(col, row) 73 | local val = bit.bor(0x80, col, M.ROW_OFFSETS[row + 1]) 74 | sendLcd(0, val) 75 | end 76 | 77 | function M.setBacklight(b) 78 | backlight = bit.lshift(b, 7) 79 | mcp.writeGPIO(backlight) 80 | end 81 | 82 | return M 83 | --------------------------------------------------------------------------------