Using an i2c 128×64 OLED display with Lua on a NodeMCU

NodeMCU and an i2c OLED display

Small 128×64 OLED i2c displays can picked up for just over £3 on Amazon, and they are great for interfacing with a NodeMCU IoT device.

Wiring is simple…

  • NodeMCU 3.3v – OLED VCC
  • NodeMCU GND – OLED GND
  • NodeMCU D1 – OLED SDA
  • NodeMCU D2 – OLED SCL or SCK

Wiring an i2c OLED display to a NodeMCU

Your NodeMCU firmware must have been compiled with the i2c and u8g modules included. If you need to add these, see my previous post – NodeMCU Lua setup using a Mac. It also explains how to upload the example Lua code below.

The u8g module comes with some great examples. I’ve taken some of the relevant parts for a simple two page Lua script that prints out two alternating screens of text.

sda = 1 -- SDA Pin
scl = 2 -- SCL Pin

function init_display(sda,scl) --Set up the u8glib lib
     sla = 0x3C
     i2c.setup(0, sda, scl, i2c.SLOW)
     disp = u8g.ssd1306_128x64_i2c(sla)
     disp:setFont(u8g.font_6x10)
     disp:setFontRefHeightExtendedText()
     disp:setDefaultForegroundColor()
     disp:setFontPosTop()
end

function updateDisplay(func)
  -- Draws one page and schedules the next page, if there is one
  local function drawPages()
    func()
    if (disp:nextPage() == true) then
      node.task.post(drawPages)
    end
  end
  -- Restart the draw loop and start drawing pages
  disp:firstPage()
  node.task.post(drawPages)
end

function drawScreen1()
     disp:drawFrame(2,2,126,62)
     disp:drawFrame(5,5,121,57)
     disp:drawStr(5, 20, "  RobertPrice.co.uk")
     disp:drawStr(5, 35, "    @robertprice")
end

function drawScreen2()
     disp:drawFrame(2,2,126,62)
     disp:drawFrame(5,5,121,57)
     disp:drawStr(5, 20, "  NodeMCU OLED Test")
     disp:drawStr(5, 35, "   12th July 2017")
end

local drawDemo = { drawScreen1, drawScreen2 }

function demoLoop()
  -- Start the draw loop with one of the demo functions
  local f = table.remove(drawDemo,1)
  updateDisplay(f)
  table.insert(drawDemo,f)
end

init_display(sda,scl)
demoLoop()
tmr.alarm(4, 5000, 1, demoLoop)

This may look a bit complex for just displaying text, but it aims to be reusable. We use the tmr.alarm to avoid bogging the CPU down in a loop.

NodeMCU driving an i2c OLED display

I’ve tried this with two different i2c OLED displays, and they both work.