使用ESP8266自制廉价Gokit SOC方案
好久都没有捣鼓ESP8266和Gokit了,直到前几周,我把以前的Gokit2挂到咸鱼出掉了(开发板太多了),我就想,反正都是使用的ESP8266,不要STM32或者Arduino的底板那也能用啊,干嘛要两块板子一起用。于是乎我开始了廉价的折腾(并不廉价,花费更高)。
ESP8266的几种版本
ESP8266的版本众多,各有各的区别,在购买和倒腾之前要先看清楚。我这里上传了一张安信可的版本表(旧选型表)。你当然也可以直接去官网看:https://wiki.ai-thinker.com/esp8266。当然当然,还有其他公司的ESP8266,比如:正点原子啥的等等,不过芯片都是乐鑫的。在物联网大行其道的今天,这样的业界里程碑产品居然是中国设计制造的,不错。
上面谈到的都只是核心模块本身,还需要转换板或者相应的外围电路板(复位,TTL),可以是NodeMcu,或者是WeMos D1, D1 R2 & D1 mini。等等廉价的方案。因为NodeMcu的电路图都是开源的,所以衍生版本比较多。可供选择的版本很多很多。
我推荐买ESP8266-12F或者12E,直接FLash就有32Mbit,一般也够用了。Gokit自己也用的12F吧。
ESP8266自带AT指令进行配置
安信可的教程已经很详细了,https://wiki.ai-thinker.com/esp8266/examples/at_demo
可以使用乐鑫ESP-Touch和微信Airkiss来配网。
一般情况下,购买的ESP8266-12F模组会烧录出厂AT固件,如果烧录了ESP8266的其他例程或者下文的GAgent,ESP8266会执行其他功能。除非再次烧录AT固件,否则不能使用AT指令来操作ESP8266。
烧录固件和三个常见工具
烧录固件要遵循Flash地址。这个是无论什么烧写软件都不变的。
1.可以使用乐鑫官方提供的ESPFlashDownloadTool。
乐鑫官方可以下载最新版。
2.使用NodeMCU Flasher,多年没更新了(最后更新是2017年),不是很推荐用这个,我用12F没能烧写进去固件。
3.使用NodeMCU-PyFlasher,最新的烧写软件,不过不能手动修改固件的Flash地址,但是可以使用ESPFlashDownloadTool来合并。有Mac版,这是重点!!!
其实是esptool.py,这个工具的UI版。
合并为一个Bin,则能使用PyFlasher顺利烧录。
合并完成后选择target.bin
即可。
SPI MODE
可以移步看一下资料:https://blog.csdn.net/recclay/article/details/78956580,https://electronics.stackexchange.com/questions/28792/what-is-dual-quad-i-o
Standard SPI 为普通序列式闪存,它的 DI DO都是单向的 DUAL
SPI的读写速度是普通序列式闪存的2-3倍,DI和DO是双向的,称作DI0 DI1; DUAD
SPI的读写速度是普通序列式闪存的4-6倍;DI和DO是双向的,称作DI0 DI1,同时,/WP和/HOLD也变成输入输出管脚,称作DI2,DI3
CrystalFreq(晶振频率),默认是26M,如有不同修改即可。
进入刷写模式
按住 FLASH 按键(按住不放)
按下 RST 按键并松开
松开 FLASH 按键
方法是这样,但是我用第1,2个工具都没烧写进去,第3个才进去。
擦除固件
就和正常编程器原理是一样的就是覆盖,但是切记要覆盖完整个颗粒。有时没有正确擦除总有些疑难杂症。
你可以使用esptool.py工具的命令:esptool.py --port COM8 erase_flash
。
或者手动下载官网的空白固件,重新烧录:https://wiki.ai-thinker.com/_media/tools/erase_flash_bins.7z。注意对应的大小。比如:32Mbit_Null.bin
自定义固件
前文提到了,可以使用Lua语言来构建功能代码。自己开发则可以自定义生成所需库的Bin文件,文档见:
https://nodemcu.readthedocs.io/en/master/。
在线构建的地址为:https://nodemcu-build.com/,无需进行注册,只需要留下邮箱就好了,不能使用QQ邮箱,可以是Gmail。
根据自己项目需要进行选择,如果不确定那个库是干嘛的,可以点击小问号,看文档里面写的。下面列举了常用的几个:
WS2801/WS2802/WS2812 effects
相应型号芯片的RGB灯库PWM
就是PWMend user setup
用户可以通过界面配置联网(具体看文档)HTTP
支持HTTP请求(具体看文档)tmr
定时器
强烈建议你把下面的Debug
顺便勾上,TLS/SSL support
也可以选择上,虽然废话有点多,但是不是很大的坏事。
会有两封邮件,第一封是开始Build,第二封就是NodeMCU custom build finished,如下图:
有两个版本,float
和integer
,根据自己的需要进行下载开发,nodemcu-master-10-modules-2019-05-13-10-07-25-float.bin
。
使用Lua开发
在对所需要的库进行配置了后,就可以进行开发看了。
你可以手动验证固件,无需下面所谓的IDE。
file.open("init.lua","w+")
file.writeline([[print("hello world")]])
file.close()
创建了一个init.lua
文件,默认每次模组启动都是从init.lua
文件启动的,你可以通过dofile("yourfile.lua")
命令来修改。
如果一切正常,重新上电或者重启模组的时候会输出hello world。
当然,你不能指望使用file.writeline,写过多的代码,可以使用较新的ESPlorer和NodeMCU Studio 2015,也可以是ArduinoIDE。我最开始使用NodeMCU Studio 2015,一直不行,程序报各种溢出,ESPlorer是基于Java的,没有太大问题,ArduinoIDE我就不多说了。
首先你需要创建一个init.lua
文件,写上代码,然后保存文件,再Sava to Esp,即可,大同小异。
使用MicroPython开发
步骤上和Lua差不多,就不多赘述了。
目的
官方已经发布了Gokit2,3(s)等版本的开发板。一般使用的就是独立MCU方案。官方的板子能够实现:红外传感器,温湿度传感器,小电机,RGB灯,用户按键等几个外设的驱动。我们只使用ESP8266也能实现该功能。
官方也提供了两种方案,前面是独立MCU方案,程序还是写在STM32或者Arduino底板上,ESP8266上就烧写GAgent,进行通讯。后面就是我们这次说的SOC方案,只有ESP8266,可以无需安装STM32或者Arduino。机智云提供了很好的教程:GoKit3(S) 二次开发--开发环境搭建
搭建开发环境
前面的生成出来的Bin相当于是已经编译好的,但是如何自己想要开发,就需要自己来编译Bin,本质上都是C Makefile Project,大同小异。安信可官方称为两种编译方法,分别为新旧。
旧的就是搭建ubuntu虚拟机开发环境。需要下载VirtualBox,通过乐鑫官方的esp8266开发环境,加载编译环境的虚拟镜像(ESP8266_lubuntu_20141021.ova),可以直接使用。如果需要自己搭建的话,可以使用VMware Workstation + ubuntu 16.X,手动安装xtensa-lx106-elf.tar.bz2,交叉编译工具。在GoKit3(S) 二次开发--开发环境搭建,中有讲到。
新的就是指的安信可一体化开发环境,基于 Windows + Cygwin + Eclipse + GCC 的综合 IDE 环境,可以认为就是配置好了环境的Eclipse IDE for C/C++ Developers。
无需安装虚拟机,直接使用Windows即可。可以看:如何安装安信可一体化开发环境,下面是引用的官方的操作步骤。
- 打开 ConfigTool.exe,点击 Default 可以检测当前所在路径,或手动进行路径配置;
- 配置后点击 Save 进行保存;
- 打开 AiThinker_IDE.exe,可以直接进行固件的编译;
- 点击 OpenWorkSpace.bat,可以快速打开默认的project目录;
- 点击 Register 可注册 Cygwin Here快捷方式到鼠标右键,可实现在当前目录打开终端。
平台生成代码
各个官方都提供了良好的开源案例,NodeMCU和机智云还提供了生成源码。这能为我们再次简化非常多的开发时间。
例如在安信可官网提供了ESP8266 最新SDK,例如前面用到的AT:AiCloud 2.0 AT 固件,乐鑫原厂,乐鑫修改版等。
下面说的是机智云的代码生成。
首先你要生成相应的数据节点:
可以看机智云的定义数据点教程,我创建了典型的宠物屋数据点,下面是一部分的截图。
在服务->MCU开发中进行选择。
我们这里当然是选择SOC方案。Product Secret从基本信息中复制填写。
如果选择SOC,可以有如下方案,根据你自己的实际情况选择了。
如果选择MCU,可以有如下方案,MCU能选择的就很多了,就是底板,但是本文不讨论这个方面。
移植功能代码
上面的操作无误后,稍等片刻即会生成代码包,下载并解压。
帮助说明文件均在包内,如下图:
你可以使用安信可的Eclipse来进行编辑,我使用的VS Code。
整个云端自动生成的SOC源码里面,用户只需要关心文件路径为“GizLamp\app”下面的几个地方:
如果你需要添加8266的外设,只需要在
“GizLamp\app\driver”文件目录下添加相应外设的驱动的.c文件
“GizLamp\app\include\driver”文件目录下添加相应外设的驱动的.h文件 App通过云端下发控制事件处理,可以在“GizLamp\app\Gizwits”文件目录下“gizwits_product.c”文件里面的
“gizwitsEventProcess()函数里添加驱动外设执行事件函数即可实现控制设备 上报云端状态事件处理,可以在“GizLamp\app\user”文件目录下“user_main.c”文件里面的“userTimerFunc()”函数里添加数据状态上报函数即可以实现状态上报。
在这套SOC源码里面需要关心也就这几个主要的地方,模块联网以及底层驱动均不需要开发者去处理和修改。
我们需要有用到的驱动外设的源文件,这取决与你需要那些设备,我们使用红外传感器,温湿度传感器,小电机,RGB灯,用户按键等几个外设的驱动,和Gokit相同。官方提供了ESP8266-SOC快速入门,讲了如何将代码移植进去。
首先我们下载需要的驱动外设的源文件,从机智云的下载中心。这些教程在DIY微信宠物屋_SOC版.pdf
中都有,只是需要进行相应的修改。
将GoKit_SoC_ESP8266_V03000003测试固件及开发资源2017072815.zip\驱动库代码\
,所有.c的源文件
,解压到SoC_ESP8266_32M_source\app\driver
中。官方使用的hal_rgb_led.c
,比如我的RGB不同,则使用的Adafruit_NeoPixel.c
(下图中没有体现)
将GoKit_SoC_ESP8266_V03000003测试固件及开发资源2017072815.zip\驱动库代码\
,所有.h的头文件
,解压到SoC_ESP8266_32M_source\app\include\driver
中,如果前面的库也进行了修改,该处也要改(常识)。
然后我们就需要修改相关的函数调用。
首先找到SoC_ESP8266_32M_source\app\Gizwits
中的gizwits_product.c
在头部写进:
//新增外置设备
#include "driver/hal_infrared.h"
#include "driver/hal_motor.h"
#include "driver/hal_rgb_led.h"
#include "driver/hal_temp_hum.h"
和
#define USER_TIME_MS 100 ///< 新添加代码: 更改定
// 时器间隔为100ms
#define TH_TIMEOUT (1000 / USER_TIME_MS) ///< 新添加代码: 温湿度
// 采集间隔为1S(1000ms)
#define INF_TIMEOUT (500 / USER_TIME_MS) ///< 新添加代码: 红外采
// 集间隔为500ms
在void ICACHE_FLASH_ATTR userInit(void)
函数中,增加:
///< 新添加代码: RGB LED初始化
rgbGpioInit();
rgbLedInit();
///< 新添加代码: 电机初始化
motorInit();
motorControl(0);
///< 新添加代码: 温湿度初始化
dh11Init();
///< 新添加代码: 红外初始化
irInit();
其他需要修改的代码多半在user handle
中。void ICACHE_FLASH_ATTR userHandle(void)
:
void ICACHE_FLASH_ATTR userHandle(void)
{
/*
currentDataPoint.valueInfrared = ;//Add Sensor Data Collection
currentDataPoint.valueTemperature = ;//Add Sensor Data Collection
currentDataPoint.valueHumidity = ;//Add Sensor Data Collection
currentDataPoint.valueAlert_1 = ;//Add Sensor Data Collection
currentDataPoint.valueAlert_2 = ;//Add Sensor Data Collection
currentDataPoint.valueFault_LED = ;//Add Sensor Data Collection
currentDataPoint.valueFault_Motor = ;//Add Sensor Data Collection
currentDataPoint.valueFault_TemHum = ;//Add Sensor Data Collection
currentDataPoint.valueFault_IR = ;//Add Sensor Data Collection
*/
// system_os_post(USER_TASK_PRIO_2, SIG_UPGRADE_DATA, 0);
uint8_t ret = 0;
uint8_t curTemperature = 0;
uint8_t curHumidity = 0;
uint8_t curIr = 0;
static uint8_t thCtime = 0;
static uint8_t irCtime = 0;
thCtime++;
irCtime++;
///< 新添加代码: 红外传感器数据获取
if (INF_TIMEOUT < irCtime)
{
irCtime = 0;
curIr = irUpdateStatus();
currentDataPoint.valueInfrared = curIr;
}
///< 新添加代码: 温湿度传感器数据获取
if (TH_TIMEOUT < thCtime)
{
thCtime = 0;
ret = dh11Read(&curTemperature, &curHumidity);
if (0 == ret)
{
currentDataPoint.valueTemperature = curTemperature;
currentDataPoint.valueHumidity = curHumidity;
}
else
{
os_printf("@@@@ dh11Read error ! \n");
}
}
system_os_post(USER_TASK_PRIO_0, SIG_UPGRADE_DATA, 0);
}
增加按钮事件,在SoC_ESP8266_32M_source\app\user
中user_main.c
。我板子的按钮设置有点不同,就不贴出来了,下面是官方的。
有一段提示:
如果是使用得Gokit3 SoC开发板,由于驱动 LED 的 GPIO 是 GPIO0(Gokit3 SoC 开发板上对应
D6),而生成的代码包默认使用了 GPIO0 连接到了 Gokit3 SoC 版的按键 key1,因此把按键 1
相关删除,一般不需要使用产测功能,若自己使用 esp8266-12f 搭建最小系统,可保留此功能。
/**
* Key1 key short press processing
* @param none
* @return none
*/
LOCAL void ICACHE_FLASH_ATTR key1ShortPress(void)
{
GIZWITS_LOG("#### KEY1 short press ,Production Mode\n");
gizwitsSetMode(WIFI_PRODUCTION_TEST);
}
/**
* Key1 key presses a long press
* @param none
* @return none
*/
LOCAL void ICACHE_FLASH_ATTR key1LongPress(void)
{
GIZWITS_LOG("#### key1 long press, default setup\n");
gizwitsSetMode(WIFI_RESET_MODE);
}
/**
* Key2 key to short press processing
* @param none
* @return none
*/
LOCAL void ICACHE_FLASH_ATTR key2ShortPress(void)
{
GIZWITS_LOG("#### key2 short press, soft ap mode \n");
gizwitsSetMode(WIFI_SOFTAP_MODE);
}
/**
* Key2 button long press
* @param none
* @return none
*/
LOCAL void ICACHE_FLASH_ATTR key2LongPress(void)
{
GIZWITS_LOG("#### key2 long press, airlink mode\n");
gizwitsSetMode(WIFI_AIRLINK_MODE);
}
在gizwits_product.c
中继续修改int8_t ICACHE_FLASH_ATTR gizwitsEventProcess(eventInfo_t *info, uint8_t *data, uint32_t len)
,在每个//user handle
,后面填入代码:
如果使用的Adafruit_NeoPixel.c
库,则RGB代码为:setAllPixelColor(0, 0, 0);
(图中没有体现),其他则是rgbControl(0, 0, 0);
。
int8_t ICACHE_FLASH_ATTR gizwitsEventProcess(eventInfo_t *info, uint8_t *data, uint32_t len)
{
uint8_t i = 0;
dataPoint_t * dataPointPtr = (dataPoint_t *)data;
moduleStatusInfo_t * wifiData = (moduleStatusInfo_t *)data;
if((NULL == info) || (NULL == data))
{
GIZWITS_LOG("!!! gizwitsEventProcess Error \n");
return -1;
}
for(i = 0; i < info->num; i++)
{
switch(info->event[i])
{
case EVENT_LED_OnOff :
currentDataPoint.valueLED_OnOff = dataPointPtr->valueLED_OnOff;
GIZWITS_LOG("Evt: EVENT_LED_OnOff %d \n", currentDataPoint.valueLED_OnOff);
if(0x01 == currentDataPoint.valueLED_OnOff)
{
//user handle
rgbControl(254, 0, 0); ///< 新添加代码: 对应开启红灯
}
else
{
//user handle
rgbControl(0, 0, 0); ///< 新添加代码: 对应关闭红灯
}
break;
case EVENT_LED_Color:
currentDataPoint.valueLED_Color = dataPointPtr->valueLED_Color;
GIZWITS_LOG("Evt: EVENT_LED_Color %d\n", currentDataPoint.valueLED_Color);
switch(currentDataPoint.valueLED_Color)
{
case LED_Color_VALUE0:
//user handle
rgbControl(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B);
break;
case LED_Color_VALUE1:
//user handle
rgbControl(254, 254, 0); ///< 新添加代码: 对应LED组合颜色‐黄色
break;
case LED_Color_VALUE2:
//user handle
rgbControl(254, 0, 70); ///< 新添加代码: 对应LED组合颜色‐紫色
break;
case LED_Color_VALUE3:
//user handle
rgbControl(238, 30, 30); ///< 新添加代码: 对应LED组合颜色‐粉色
break;
default:
break;
}
break;
case EVENT_LED_R:
currentDataPoint.valueLED_R= dataPointPtr->valueLED_R;
GIZWITS_LOG("Evt:EVENT_LED_R %d\n",currentDataPoint.valueLED_R);
//user handle
///< 新添加代码: 对应设置LED组合色
rgbControl(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B);
break;
case EVENT_LED_G:
currentDataPoint.valueLED_G= dataPointPtr->valueLED_G;
GIZWITS_LOG("Evt:EVENT_LED_G %d\n",currentDataPoint.valueLED_G);
//user handle
///< 新添加代码: 对应设置LED组合色
rgbControl(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B);
break;
case EVENT_LED_B:
currentDataPoint.valueLED_B= dataPointPtr->valueLED_B;
GIZWITS_LOG("Evt:EVENT_LED_B %d\n",currentDataPoint.valueLED_B);
//user handle
///< 新添加代码: 对应设置LED组合色
rgbControl(currentDataPoint.valueLED_R, currentDataPoint.valueLED_G, currentDataPoint.valueLED_B);
break;
case EVENT_Motor_Speed:
currentDataPoint.valueMotor_Speed= dataPointPtr->valueMotor_Speed;
GIZWITS_LOG("Evt:EVENT_Motor_Speed %d\n",currentDataPoint.valueMotor_Speed);
//user handle
///< 新添加代码: 对应设定电机转速
motorControl(currentDataPoint.valueMotor_Speed);
break;
case WIFI_SOFTAP:
break;
case WIFI_AIRLINK:
break;
case WIFI_STATION:
break;
case WIFI_CON_ROUTER:
GIZWITS_LOG("@@@@ connected router\n");
break;
case WIFI_DISCON_ROUTER:
GIZWITS_LOG("@@@@ disconnected router\n");
break;
case WIFI_CON_M2M:
GIZWITS_LOG("@@@@ connected m2m\n");
setConnectM2MStatus(0x01);
break;
case WIFI_DISCON_M2M:
GIZWITS_LOG("@@@@ disconnected m2m\n");
setConnectM2MStatus(0x00);
break;
case WIFI_RSSI:
GIZWITS_LOG("@@@@ RSSI %d\n", wifiData->rssi);
break;
case TRANSPARENT_DATA:
GIZWITS_LOG("TRANSPARENT_DATA \n");
//user handle , Fetch data from [data] , size is [len]
break;
case MODULE_INFO:
GIZWITS_LOG("MODULE INFO ...\n");
break;
default:
break;
}
}
system_os_post(USER_TASK_PRIO_2, SIG_UPGRADE_DATA, 0);
return 0;
}
深入了解上面的例程
GoKit-SoC程序详解
GoKit3(S)二次开发-程序详解(旧)
ESP8266-SOC方案UART0教程
编译固件
编写完成后就准备编译,你在编译的时候会看到有不同的bin,有user1和user2,分别对应不同的开始地址,前文中的图片有提到。
进入app/
目录,使用gen_misc.sh
,没有问题会显示如下结果,表示编译通过没有问题。不要把源码等文件放到桌面!!!不是好习惯,下面仅为演示。
务必注意分区和spi mode等。
机智云配网
使用机智云APP即可。
题外话-调试工具
如果烧写的GAgent,则可以用机智云串口调试助手,模拟MCU的指令。
安信可的串口调试工具,AiThinker Serial Tool V1.2.3。
题外话-其他传感器连接
可以参照Gokit的电路图。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。