0%

NodeMCU和oled制作桌面显示器

想做一个显示网站访问次数的显示器,使用NodeMCU和0.96寸oled。由于以前使用过NodeMCU,估计一天就能完成了,再用3d打印个盒子。做的过程中出现很多新问题,就没有时间设计盒子了,买来的电池也没用上,直接usb供电了。

项目地址:GitHub

固件

克隆 nodemcu 固件仓库

1
2
git clone --recurse-submodules  https://github.com/nodemcu/nodemcu-firmware.git 
#最新固件使用了submodule,如果不克隆submodules,会报缺少某某文件的错误。

检出相应版本

1
2
git tag
git checkout 2.2.0-master_20180608

拉取 docker 镜像

1
docker pull marcelstoer/nodemcu-build

选择需要的module

nodemcu-firmware/app/include/user_modules.h
1
2
3
4
5
6
7
8
9
10
#define LUA_USE_MODULES_DHT
#define LUA_USE_MODULES_FILE
#define LUA_USE_MODULES_GPIO
#define LUA_USE_MODULES_HTTP
#define LUA_USE_MODULES_I2C
#define LUA_USE_MODULES_RTCTIME
#define LUA_USE_MODULES_SJSON
#define LUA_USE_MODULES_TMR
#define LUA_USE_MODULES_U8G2
#define LUA_USE_MODULES_WIFI

打开智能配网

nodemcu-firmware/app/include/user_config.h
1
#define WIFI_SMART_ENABLE

添加字体(u8g2使用)

nodemcu-firmware/app/include/u8g2_fonts.h
1
2
3
4
5
6
7
#define U8G2_FONT_TABLE \
U8G2_FONT_TABLE_ENTRY(font_6x10_tf) \
U8G2_FONT_TABLE_ENTRY(font_unifont_t_symbols) \
U8G2_FONT_TABLE_ENTRY(font_helvR24_tf) \
U8G2_FONT_TABLE_ENTRY(font_9x18_tf) \
U8G2_FONT_TABLE_ENTRY(font_open_iconic_weather_4x_t) \
U8G2_FONT_TABLE_ENTRY(font_courB24_tf ) \

编译固件

1
2
3
4
5
cd nodemcu-firmware
docker run --rm -ti -v `pwd`:/opt/nodemcu-firmware marcelstoer/nodemcu-build build
#最后一个build是命令,还可以使用lfs-image命令,把lua直接写到固件中:
docker run --rm -ti -v `pwd`:/opt/nodemcu-firmware -v {PathToLuaSourceFolder}:/opt/lua marcelstoer/nodemcu-build lfs-image
#这将编译并存储给定文件夹及其目录中中的所有 Lua 文件。

拷贝固件

进入固件目录 nodemcu-firmware/bin 中,得到编译完成后的固件。

1
2
3
4
5
6
7
8
9
NodeMCU 2.2.0.0 built with Docker provided by frightanic.com
branch: HEAD
commit: 4905381c004bdeaf744a60bb940c1906c2e052d4
SSL: false
Build type: integer
LFS: disabled
modules: dht,file,gpio,http,i2c,rtctime,sjson,tmr,u8g2,wifi
build created on 2019-09-12 16:24
powered by Lua 5.1.4 on SDK 2.2.1(6ab97e9)

坑-not enough memory

购买的时候,写的是32M的内存,理论上不会出现内存不足的情况,然而二三百行的lua就出现”not enough memory”的错误。

查阅网络,发现github上一个issue说:

It doesn’t really matter who makes a board since the chip is designed by espressif, and espressif’s datasheet says it supports only up to 16MB (128Mbits).My opinion: I think sellers intentionally write it is 32MB (which is wrong should be 32Mb or 4MB) just to sell those boards to people that don’t pay much attention.

The Chinaman either doesn’t know or doesn’t care about the difference between MB and Mb – always keep this in mind when buying stuff like this.

板子芯片最大支持16MB,那个公司制造的都是不会到32MB。淘宝上说的32M指的是32Mbits。为的是故意夸大,和家里宽带一个套路,实际下载速率需要带宽除以8。

u8g2的简单使用

nodemcu-firmware\lua_examples\u8g2下面有例子。

初始化屏幕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- setup I2c and connect display
function init_i2c_display()
-- SDA and SCL can be assigned freely to available GPIOs
local sda = 1 -- GPIO14
local scl = 2 -- GPIO12
local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)
disp = u8g2.ssd1306_i2c_128x64_noname(0, sla)
end

-- setup SPI and connect display
function init_spi_display()
-- Hardware SPI CLK = GPIO14
-- Hardware SPI MOSI = GPIO13
-- Hardware SPI MISO = GPIO12 (not used)
-- Hardware SPI /CS = GPIO15 (not used)
-- CS, D/C, and RES can be assigned freely to available GPIOs
local cs = 8 -- GPIO15, pull-down 10k to GND
local dc = 4 -- GPIO2
local res = 0 -- GPIO16

spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
-- we won't be using the HSPI /CS line, so disable it again
gpio.mode(8, gpio.INPUT, gpio.PULLUP)

disp = u8g2.ssd1306_128x64_noname(1, cs, dc, res)
end

显示字

1
2
3
4
5
6
function draw_status(x,s)
disp:clearBuffer()
disp:setFont(u8g2.font_helvR24_tf)--25px
disp:drawStr(x, 22, s)
disp:sendBuffer()
end

添加字体

nodemcu-firmware/app/include/u8g2_fonts.h添加字体,编译固件的时候就给编译进去了。

绘制字体中的图形

查找nodemcu的文档u8g2,一步步的可以找到字体中的字符图片,但是并没有可以复制的字符。

看一下u8g2的api,这个实心的点是 UTF-8 encoded text,怎么从字体中得到呢?

1
2
disp:setFont(u8g2.font_unifont_t_symbols)
disp:drawUTF8(105, 54, "●")

下载字体文件:unifont-12.1.02.ttf
下载字体软件:BabelPad Ver12.1.0.4简体中文版
把字体拖入字体软件,点击工具,字符映射表

在跳至编码处输入字符图片中字符的编码,即可找到可以复制的字符。比如闹钟字符,编码23f0。

背景色的设置

oled显示菜单,选择的菜单是背景有色,字符无色。没有选中的是字符有色,背景无色。
这是由两个api控制的
disp:setDrawColor() disp:setFontMode()

智能配网

需要在user_config.h打开智能配网设置:
SmartConfig is disabled by default and can be enabled by setting WIFI_SMART_ENABLE in user_config.h before you build the firmware.

1
2
3
4
wifi.setmode(wifi.STATION)
wifi.startsmart(0,function(ssid, password)
print("smart config success")
end)

手机商店搜索相关软件(Esptouch等),即可配网。

硬件设计

NodeMCU连接一个dht11,一个声音传感器,一个按钮。声音传感器可以唤醒屏幕,按钮可以唤醒屏幕和配网。

软件设计

服务器后台每一个小时,爬取当前网站访问量和天气数据,并缓存。NodeMCU访问时候拿到的是这个小时缓存的数据,速度就非常快了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"msg": "成功",
"time": 1570627620,
"todayDate": 9,
"todayWeather": "rain",
"todayTempHigh": 14,
"todayTempLow": 14,
"tomorrowDate": 10,
"tomorrowWeather": "cloud",
"tomorrowTempHigh": 21,
"tomorrowTempLow": 13,
"visitcount1": 2568,
"visitcount2": 299
}

显示时间,并没有使用NodeMCU的SNTP Module,而是通过服务器返回的时间戳和rtctime Module完成的。