NodeMCU and HD44780 – part 2

We played a little with lcd and we know that it works 🙂 It is a good idea to create a class that can be used in any project.  Such class must allow setting width, height and pins if they are different from default one. It’s behaviour is based on lcd direct from CharLCD python class.
That means it is gonna display chars directly without buffer.

Modelling

As we are modelling from existing class we may prepare functions stubs. With each step we will fill function with correct code. Name lcd_hd44870.lua looks nice so create such file and start with:

local lcd_hd44870 = {}

lcd_hd44870.width = 0
lcd_hd44870.height = 0
lcd_hd44870.x = 0
lcd_hd44870.y = 0

lcd_hd44870.lines = {
    0x80, 0xc0, 0x94, 0xd4
}
lcd_hd44870.pins = {
    RS= 7,
    E1= 6,
    E2= nil,
    DB4= 5,
    DB5= 3,
    DB6= 1,
    DB7= 2,
}

lcd_hd44870.lcd = function(width, height, pins)
    lcd_hd44870.width = width
    lcd_hd44870.height = height
    if pins ~= nil then
        lcd_hd44870.pins = pins
    end
end

lcd_hd44870.init = function ()
    if lcd_hd44870.width == 0 or lcd_hd44870.height == 0 then
        print("Initialize via lcd(width, height, [pins])")
        return
    end
    
    for k,v in pairs(lcd_hd44870.pins) do 
        gpio.mode(v, gpio.OUTPUT)
        gpio.write(v, gpio.LOW)
    end

    lcd_hd44870._init_lcd()
end

lcd_hd44870._init_lcd = function()

end

lcd_hd44870._write4 = function()

end

lcd_hd44870._write8 = function()

end

lcd_hd44870.command = function()

end

lcd_hd44870.write = function()

end

lcd_hd44870._send = function()

end

lcd_hd44870.set_xy = function()

end

return lcd_hd44870

Define local variables to keep screen size and cursor position. Next we have addresses for lines and default pinouts, see that we have E1 and E2 – it is ready for big screen like 40×4.
Another function is our constructor, lcd, we pass width, height and required pins there. Next function init is called to initialize pins and screen via _init_lcd.
To communicate with screen we have private functions _write4, _write8, _send. And for user we have command, write and set_xy.

Initialization

In part one we have learned how to initialize lcd, so quickly prepare few function mainly by coping code from there:

lcd_hd44870._send = function()
    gpio.write(lcd_hd44870.pins['E1'], gpio.HIGH)
    tmr.delay(5)
    gpio.write(lcd_hd44870.pins['E1'], gpio.LOW)
end

lcd_hd44870._write4 = function(ch)
    if bit.isset(ch, 0) then gpio.write(lcd_hd44870.pins['DB4'], gpio.HIGH) else gpio.write(lcd_hd44870.pins['DB4'], gpio.LOW) end        
    if bit.isset(ch, 1) then gpio.write(lcd_hd44870.pins['DB5'], gpio.HIGH) else gpio.write(lcd_hd44870.pins['DB5'], gpio.LOW) end        
    if bit.isset(ch, 2) then gpio.write(lcd_hd44870.pins['DB6'], gpio.HIGH) else gpio.write(lcd_hd44870.pins['DB6'], gpio.LOW) end       
    if bit.isset(ch, 3) then gpio.write(lcd_hd44870.pins['DB7'], gpio.HIGH) else gpio.write(lcd_hd44870.pins['DB7'], gpio.LOW) end

    lcd_hd44870._send()
end

lcd_hd44870._write8 = function(ch)
    lcd_hd44870._write4(bit.rshift(ch, 4))
    lcd_hd44870._write4(bit.band(ch, 0x0F))
end

Finally we may copy _init_lcd:

lcd_hd44870._init_lcd = function()
    gpio.write(lcd_hd44870.pins['RS'], gpio.LOW)
    lcd_hd44870._write4(3)
    tmr.delay(50)
    lcd_hd44870._write4(3)
    tmr.delay(50)
    lcd_hd44870._write4(3)
    tmr.delay(50)    
    lcd_hd44870._write4(2)
    lcd_hd44870.command(0x28)
    lcd_hd44870.command(0x08)
    lcd_hd44870.command(0x01)
    lcd_hd44870.command(0x06)
    lcd_hd44870.command(15)
end

lcd_hd44870.command = function(ch)
    gpio.write(lcd_hd44870.pins['RS'], gpio.LOW)
    lcd_hd44870._write8(ch)
end

We cheat a little bit, function command stays as 8bit but because we need some 4bit calls first we use _write4 directly.
It is time to check our code. Open main.lua and copy:

lcd = require("lcd_hd44870")
lcd.lcd(16, 2)
lcd.init()

Yeh! Lcd is initialized and ready to display something.

Displaying

LCD is displaying chars via hex codes, we need to convert letter to hex, simple. And we can not display string directly, our function write takes string as argument, iterate over chars and call _write8 for each.

lcd_hd44870.write = function(string)
    gpio.write(lcd_hd44870.pins['RS'], gpio.HIGH)
    for i = 1, #string do
        lcd_hd44870._write8(string:byte(i))        
    end
    lcd_hd44870.x = lcd_hd44870.x + #string
end

Also x offset is increased.
Test it:

lcd = require("lcd_hd44870")
lcd.lcd(16, 2)
lcd.init()
lcd.write('Zombicide')

We can display a text – that is good, but we cant control where text is displayed – that is bad. Additionally when we reach end of line text goes missing 🙂
Our cure is set_xy function:

lcd_hd44870.set_xy = function(x, y)
    lcd_hd44870.command(lcd_hd44870.lines[y + 1] + x)     
    lcd_hd44870.x = x
    lcd_hd44870.y = y
end

and if we have set it is nice to have get:

lcd_hd44870.get_xy = function()
    return {
        x = lcd_hd44870.x, 
        y = lcd_hd44870.y
    }   
end

We are able to set and read current position.

New main.lua to test new functionality:

print ("core ready")

lcd = require("lcd_hd44870")
lcd.lcd(16, 2)
lcd.init()
lcd.write('Zombicide')
lcd.set_xy(3, 1)
lcd.write('Black Plague')
p = lcd.get_xy()
print (p['x'].." / "..p['y'])

Cursor

I totally forgot about cursor! We should be able to set visibility and blink.
We take similar approach as in CharLCD, create at the top those variables:

lcd_hd44870.cursor_blink = 0
lcd_hd44870.cursor_visible = 0

and change (in _init_lcd function) from

lcd_hd44870.command(15)

to

lcd_hd44870.command(12 + (2*lcd_hd44870.cursor_visible) + lcd_hd44870.cursor_blink)

We hide cursor and disable blinking by default. To change this set

lcd_hd44870.cursor_blink = 1

or

lcd_hd44870.cursor_visible = 1

before calling init().

Summary

We can now use char lcds with hd44870 chipset. I’m adding this library to boilerplate project. It was rather easy so lets increase difficulty and add buffered mode in next part.

Advertisements

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s