Osheep

时光不回头,当下最重要。

15、nodeMCU学习笔记--u8glib模块·一

oled  spi  esp8266  nodeMCU

《15、nodeMCU学习笔记--u8glib模块·一》

Hello NodeMCU

闲言碎语

终于知道如何调整简书的图片大小了。这回准备说说u8glib模块。这个模块我折腾了好几天才弄懂怎么用。关于这个模块,官方的文档显然没有其他模块讲的详细,在没有接触过u8glib模块的人,看nodeMCU的文档估计是点不亮屏幕的。或许想我一开始一样,只有花屏。

真正要知道如何用还要靠u8glib这个图形库的官方文档。这里有个文档说如何显示一行字符串。

如果不想看英文文档,下面这段代码可以让oled显示一段文字(当然是英文的)。效果就是文章开头的那图片所展示的。

cs  = 8 
dc  = 2 -- D2
res = 0 -- D0
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
disp:setFont(u8g.font_6x10)

str = "Hello NodeMCU!"
function draw()     
    disp:drawStr(0, 16, str)
end

disp:firstPage()
while (disp:nextPage())
do 
    draw()
end

函数模块

如果说上面的代码看起来有点难度的话。没关系,先看看nodeMCU的u8glib模块的API。模块的API看起来是有点多。但完全不需要看那么多,这里只关注几个API。

序号 函数名 参数 返回值
1 i2c.setup() id, pinSDA, pinSCL, speed speed
2 spi.setup() id, mode, cpol, cpha, databits, clock_div[, duplex_mode] 1
3 ssd1306_128x64_i2c() address[, use_delay] object
4 ssd1306_128x64_spi() cs, dc[, res[, use_delay]] object

这里前两个API是硬件接口初始化函数,来自i2c模块和spi模块。i2c模块比较简单,还是说说spi模块把。esp8266有2个spi硬件接口,其中一个用于flash了。因此要使用spi驱动oled的话,就只能用另一个接口了。
HSCLK对应了D5, HMISO对应D6,HMOSI对应D7。

后面两个API则是u8glib的初始化函数,具体的函数名和编译的固件有关,后面还会说到。

u8glib相关的API,nodeMCU的文档并没有详细的介绍。要弄清楚各个API具体怎么用,可能还需要看u8glib的官方文档

这里简单的说一下,开头的源码。这里oled的CS直接接到GND了,所以在配置完spi后,可以把gpio配置成输入,把IO利用起来。当然不配置也OK。

spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
disp:setFont(u8g.font_6x10)

接着初始化u8glib,返回一个u8glib的object。之后都是围绕object来用,比如用setFont()来设置字体。使用drawStr()来显示字符串。但是,想要实现显示,还需要类似于下面的代码。u8glib官方称其为Picture Loop

disp:firstPage()
while (disp:nextPage())
do 
    draw()
end

因为嵌入式设备的RAM很有限,所以u8glib采用了多种内存操作方式。具体怎么操作,应用层不用理会。u8glib会循环写入显存,以实现显示。在循环开始前,需要使用firstPage(),然后等待写入结束。当nextPage()返回0,则表示写入完成。

实际上,这段代码要放在主循环里面,才能刷新屏幕的显示内容。有了这些感性认识后,我就可以开始实际了。

实践一下

开始实践之前,你可能需要重新编译一个固件!这里我们可以选择云编译

《15、nodeMCU学习笔记--u8glib模块·一》

Paste_Image.png

I2C和SPI至少要选择一个。再者就是本文的主角——u8glib模块,选择这个模块后,会多一个U8G options栏目,用来选择字体和驱动IC。需要根据使用的液晶驱动IC选择对应的xxx_i2c和xxx_spi。

还有就是选择字体。点击select会弹出一个字体窗口,里面有很多字体可以选择。可以随意选择自己喜欢的字体。不过,不要选太多。同时注意字体的大小,别选择了大字体后没法正常显示。最后,千万要把字体名字记录下来千万要把字体名字记录下来千万要把字体名字记录下来

准备工作做完后,就可以开始code了。先从几个简单的画图API开始。代码有点长,这里面涉及的函数包括了:

cs  = 8 -- GPIO15, pull-down 10k to GND
dc  = 2
res = 0
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
disp:setFont(u8g.font_6x10)

local s = 0
function draw(state)     
    if state == 0 then 
        disp:drawStr(0, 15, "drawBox")
        disp:drawBox(0, 23, 10, 20)
    elseif state == 1 then
        disp:drawStr(0, 15, "drawCircle")
        disp:drawCircle(36, 36, 10)
    elseif state == 2 then
        disp:drawStr(0, 15, "drawDisc")
        disp:drawDisc(36, 36, 15)
    elseif state == 3 then
        disp:drawStr(0, 15, "drawEllipse")
        disp:drawEllipse(60, 30, 20, 10, U8G_DRAW_ALL)
    elseif state == 4 then
        disp:drawStr(0, 15, "drawFrame")
        disp:drawFrame(60, 20, 20, 30)   
    elseif state == 5 then
        disp:drawStr(0, 15, "drawLine")
        disp:drawLine(5,26, 25, 40)
    elseif state == 6 then
        disp:drawStr(0, 15, "drawStr")
        disp:drawStr90(60, 20, "drawStr90") 
    else  
        disp:drawStr(0, 15, "drawTriangle")
        disp:drawTriangle(14,20, 45,32, 9,42);    
    end
end
disp:begin()
tmr.alarm(0, 1000, tmr.ALARM_AUTO, function()
    if s == 7 then
        s = 0
    else 
        s = s + 1
    end
    disp:firstPage()
    while (disp:nextPage())
    do 
        draw(s)
    end
end)

draw函数中切换的使用u8glib中的几种画图函数。然后使用一个定时器来执行Picture Loop以刷新屏幕。

把上面的代码save到nodeMCU中就可以看到屏幕不断的变化了。更多的内容可以查看U8glib Reference Manual。当然了,nodeMCU的u8g模块并没有完全实现u8glib库的全部API,具体可以看Unimplemented Functions

这回就先到这里吧,回头我继续研究一下u8glib。看看有没有什么高级点应用。

一点问题

使用drawStr()函数,这样写disp:drawStr(0, 0, "drawFrame")是看不到屏幕显示字符串的。只有调整一下Y坐标到16左右才可以正常显示。

更多内容

↑ 点击上面的标题可用查看同文集的其它文章。

点赞