在实现了基于YModem和XModem协议的单片机代码更新之后就在琢磨如何真正实现远程升级,直接通过网络就可以更新代码。
参考了网上很多关于WIFI通信升级的帖子,先梳理了一下WiFi通信升级的流程,然后开始着手实现这一功能。
首先是WiFi通信模块的通信工具的选择,我这里选用的是ESP8266。
然后是通信协议的选择,可以选择自定义通信协议,不过因为ESP8266模块有MQTT的库可以直接调用,因此这里我选用的是MQTT协议作为WiFi模块和服务器之间的通信协议。
一、WiFi模块的选用与介绍
我选用的是基于乐鑫esp8266的NodeMcu开发板,具有GPIO、PWM、I2C、1-Wire、ADC等功能,结合NodeMcu 固件为原型开发提供最快速的途径。
官方网站:
NodeMcu --像Arduino一样简单的开源可编程固件
NodeMcu开发板操作起来很简单,使用Lua脚本语言对其进行操作。如果没有入这款开发板,直接用ESP8266接上必要的外围电路,然后利用ESP8266的串口就可进行烧写了。如此要使用NodeMcu的固件只需要将其固件烧写到ESP8266上即可。下面将介绍NodeMcu固件库的烧写过程。
二、ESP8266的固件擦除与烧写
1、ESP8266 Flash擦除工具的安装与使用。
在写ESP8266的控制代码时,偶尔会遇到需要彻底擦除Flash里的内容,然后重新烧写的情况,这里介绍一款比较好用的Flash擦除工具—esptool.py
(1)首先安装python环境,版本不宜过高,最好在2.0~3.0之间;
(2)安装完成后通过cmd输入python,若出现相关版本信息,则安装成功。
(3)使用:先找到安装python的文件夹,看是否该文件夹下存在esptool.py,若存在则通过cmd运行该程序,例如在我的安装情况下运行:
C:\Python27\Lib\site-packages>esptool.py --port COM4 erase_flash
这句话的意思就是擦除串口4连接的ESP8266的Flash。等待擦除完成之后我们就可以往里面重新烧写固件了。
注意:在运行命令前,一定要先将ESP8266置于Flash模式,即必须先将GPIO0引脚拉低。
2、ESP8266固件烧写
(1)在线获取固件文件
NodeMCU custom builds
NodeMcu提供在线生成固件,用户可以根据自己的需要选择模块生成固件,NodeMcu会将集成好的固件文件发送至用户邮箱,只需通过邮箱里的链接即可下载我们所需要的固件。烧写地址(0x00000)
(2)获取SDK init数据
在如上所述,通过esptool.py完全擦除芯片之后,需要先给ESP8266烧写SDK之后再烧写NodeMcu固件。
NodeMCU版本是针对Espressif SDK的特定版本编译的。SDK在闪存中保留用于存储校准和其他数据的空间。此数据在SDK版本之间更改,如果它无效或不存在,则固件可能无法正确启动。
Espressif SDK下载
解压该压缩包之后在bin文件夹下就能找到我们所需要的SDK文件。
- esp_init_data_dedault.bin 初始化其他射频参数区,至少烧录一次。烧写地址(0x3FC000)
- blank.bin 初始化RF_CAL参数区,烧写地址(0x3FE000)
(3)ESP8266 Flash烧写工具的使用
使用的是ESP8266Flasher.exe
下载安装好,运行该文件,先选择串口,然后配置文件,可以将SDK和固件一次性下载到ESP8266模块中,如图:
然后点击Flash按钮,若出现芯片的MAC地址,则表示开始烧写中,然后等待片刻,当左下角出现绿色的圆标打勾,则表示烧录完毕。
三、NodeMcu基于Lua脚本开发
1、上传代码到ESP8266
选用的上传代码工具为ESPlorer
需要Java运行环境,下载安装之后,通过串口连接ESP8266,打开串口,然后重启ESP8266,若是固件烧写成功,则串口会打印相应的固件模块,并且提示“lua: cannot open init.lua”。
ESPlorer工具的窗口布局如下图所示:
左侧窗口主要用于查看和编辑Lua脚本,然后通过左下角的按钮可以将编辑好的Lua脚本保存(Save to ESP)、发送(Send to ESP)以及上传(Upload to ESP)到ESP8266上。
最右侧的纵向列表显示了目前ESP8266上所存的lua脚本数量。
运行NodeMcu首先得先写好init.lua脚本,然后上传到板子上,再重启运行。init.lua就相当于C语言中得main()函数,是程序的入口,必不可少的部分。
2、init.lua 连上WiFi
一切准备就绪之后我们就可以开始着手编写我们的lua脚本了。
没有接触过lua,则可以先通过教程简单学习一下lua编程。Lua教程
要运行lua脚本,可以选择命令行运行的lua.exe,或者编译环境友好的SciTE.exe以及LuaStudio。目前我用的最多的是后面两款工具,其中LuaStudio在试用阶段特别的好用。
利用Lua模块,可以直接将WiFi连接配置的部分写成一个模块然后直接在init.lua中调用WiFi连接函数即可。具体代码如下:
--wifi_cfg.lua
local module = {}
local led = require("led")
local function mWifiConfig()
wifi.setmode(wifi.STATION)
local station_cfg = {}
station_cfg.ssid = "WiFi名字"
station_cfg.pwd = "WiFi密码"
station_cfg.save = false
wifi.sta.config(station_cfg)
local cfg = {}
cfg.ssid = "NodeMCU"
cfg.pwd = "20180719"
wifi.ap.config(cfg)
wifi.sta.autoconnect(1)
end
function module.connectWIFI() -- timer1
print('Setting up WIFI date in 20180730...')
mWifiConfig()
led.LEDInit()
--connect to a wireless network
tmr.alarm(1, 1000, tmr.ALARM_AUTO, function()
if wifi.sta.getip() == nil then
print('Waiting for IP ...')
led.RedLED()
else
print('IP is ' .. wifi.sta.getip())
led.GreenLED()
tmr.stop(1)
end
end)
end
return module
-- init.lua
local my_wifi = require("wifi_cfg")
-------main---------
--connect wifi
my_wifi.connectWIFI()
然后将wifi_cfg.lua和init.lua两个文件一起上传到ESP8266上,上传完成之后,重启板子,然后ESP8266就连上了WiFi了。
3、更多ESP8266 关于lua脚本开发
在学习NodeMcu时,在网上找到了不少好的帖子,里面关于NodeMcu入门lua开发讲得很详细了,这里就不再赘述了,贴出链接供大家学习。
NodeMcu之旅(一):构建、刷入固件、上传代码
NodeMcu之旅(二):断线自动重连,闪烁连接状态
NodeMcu之旅(三):响应配置按钮
NodeMcu之旅(四):实现Web配置页面
看完网上的教程后发现,教程中所用的代码大多数是NodeMcu提供的官方文档中的样例改写来的,所以,多多研究官方的API,想要什么功能自己实现就好了。
NodeMcu官方文档
四、通信协议的选择与使用
在学会了如何用lua脚本控制WiFi模块之后,现在就需要着手选择通信协议了,这里我用的是MQTT。
因为MQTT可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
并且NodeMcu固件库中包含了MQTT模块,其中关于MQTT的客户端与代理服务器的连接,订阅和发布消息的操作都很简单。
1、MQTT协议原理
关于MQTT协议的介绍和原理,网上有许多帖子介绍的,这里就贴出,我学习时看的帖子。
MQTT协议简介及协议原理
MQTT协议解析
2、搭建MQTT代理服务器
在知道了协议通信原理之后,就可以在本地搭建一个MQTT的代理服务器了,方便日后的调试使用。
这里我用的是Apache Apollo 服务器。在安装之前需首先安装JAVA jdk,配置环境变量,注意版本不要太高。
(1)Apollo服务器下载,下载地址 直接下载 apache-apollo-1.7.1-windows 的安装包。下载后解压到一个文件夹,注意路径不要包含中文。安装时参照安装手册 一步一步安装即可。
(2)创建apollo的服务器应用实例,通过cmd进入apache-apollo-1.7.1的目录里面运行apollo.cmd create mybroker,如下:
F:\apache-apollo-1.7.1-windows-distro\apache-apollo-1.7.1\bin\apollo.cmd create mybroker
(3)创建成功之后进入mybroker文件运行服务器,如下:
F:\apache-apollo-1.7.1-windows-distro\apache-apollo-1.7.1\bin\mybroker\bin>apollo-broker run
(4)启动服务后,在浏览器上面输入:https://127.0.0.1:61681/或http://127.0.0.1:61680/使用默认的用户名和密码登录 (admin;password),进入服务器页面,如图:
3、安装MQTT客户端
搭建好代理服务器之后,再安装一个MQTT客户端,即可测试MQTT通信协议了。因为MQTT属于订阅/转发类的通信协议,而MQTT的代理服务器只具备信息转发功能,所以我们可以使用ESP8266作为一个客户端,PC即是客户端又是代理服务器,通过ESP8266发布消息,PC端订阅消息,则可以实现两者之间的通信。
这里我安装的PC客户端是MQTT.fx 通过配置代理服务器的IP和端口号即可连接。
后面涉及到测试ESP8266通过MQTT接收16进制数,我又使用了另一个串口工具:通信猫调试软件,一款很小但是功能齐全的串口调试工具,也可以连上MQTT代理服务器,并且能够发送16进制数据
五、基于MQTT协议WiFi远程升级的具体实现
1、自定义MQTT文件发送客户端
在测试了ESP8266通过MQTT与代理服务器连接良好,并且之间通信16进制数据也正常之后,此时面临的问题就是,没有合适的MQTT客户端能够直接发送文件。而且因为ESP8266的接收缓存有线,所以一个更新文件我们也不能一次性发送,所以得分包发送。
如此,最好的就是自定义一个可以分包发送文件的客户端,我主要负责单片机方面的开发,所以自定义的客户端具体实现过程我也不太清楚。这里就说下我使用的客户端的满足的要求。
(1)满足TCP连接,能够正常连接上MQTT代理服务器;
(2)能够读取出文件大小及文件名;
(3)能够将文件分成指定大小的数据包,并且加上包头,校验和包尾后通过发布消息发送给代理服务器。
2、客户端与ESP8266的通信过程
完成了以上所有工作之后,最后的就是协调客户端和ESP8266之间的通信了。
这里我通过订阅主题update接收来自客户端的文件数据包,当然这里我上传给客户端的文件是直接可执行的bin文件。
然后客户端通过订阅主题back来接收单片机的反馈信息。
主要通信过程为:
(1)单片机做好更新程序的准备后,发布主题为back,消息为–请求的数据包号给客户端;
(2)客户端收到单片机做好准备的标识和包号之后,通过识别包号,发布主题为update,消息为—包数据给ESP8266;
(3)单片机收到一包数据处理完成之后,请求下一包;
(4)客户端收到请求之后发送下一包数据,直至文件发送完成,发送结束标识。
这里客户端发送的第一包也可包含文件大小和文件名,然后单片机的处理就类似与YModem协议处理即可。
通过ESP8266远程升级单片机程序,除了通信协议不一样,其余部分都可按照之前说的YModem和XModem协议处理即可。