15、nodeMCU学习笔记--u8glib模块·一
Hello NodeMCUoled spi esp8266 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,则表示写入完成。
实际上,这段代码要放在主循环里面,才能刷新屏幕的显示内容。有了这些感性认识后,我就可以开始实际了。
实践一下
开始实践之前,你可能需要重新编译一个固件!这里我们可以选择云编译
Paste_Image.pngI2C和SPI至少要选择一个。再者就是本文的主角——u8glib模块,选择这个模块后,会多一个U8G options栏目,用来选择字体和驱动IC。需要根据使用的液晶驱动IC选择对应的xxx_i2c和xxx_spi。
还有就是选择字体。点击select会弹出一个字体窗口,里面有很多字体可以选择。可以随意选择自己喜欢的字体。不过,不要选太多。同时注意字体的大小,别选择了大字体后没法正常显示。最后,千万要把字体名字记录下来。千万要把字体名字记录下来。千万要把字体名字记录下来。
准备工作做完后,就可以开始code了。先从几个简单的画图API开始。代码有点长,这里面涉及的函数包括了:
- 画 矩 形:drawBox
- 画 圆:drawCircle
- 画实心圆:drawDisc
- 画 椭 圆:drawEllipse
- 画 方 框:drawFrame
- 画 线:drawLine
- 写字符串:drawStr
- 画三角形:drawTriangle
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左右才可以正常显示。
更多内容
↑ 点击上面的标题可用查看同文集的其它文章。