好久都没有捣鼓ESP8266和Gokit了,直到前几周,我把以前的Gokit2挂到咸鱼出掉了(开发板太多了),我就想,反正都是使用的ESP8266,不要STM32或者Arduino的底板那也能用啊,干嘛要两块板子一起用。于是乎我开始了廉价的折腾(并不廉价,花费更高)。

20190517160349.png

ESP8266的几种版本

ESP8266的版本众多,各有各的区别,在购买和倒腾之前要先看清楚。我这里上传了一张安信可的版本表(旧选型表)。你当然也可以直接去官网看:https://wiki.ai-thinker.com/esp8266。当然当然,还有其他公司的ESP8266,比如:正点原子啥的等等,不过芯片都是乐鑫的。在物联网大行其道的今天,这样的业界里程碑产品居然是中国设计制造的,不错。

esp8266_module_list.png

上面谈到的都只是核心模块本身,还需要转换板或者相应的外围电路板(复位,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地址。这个是无论什么烧写软件都不变的。

20190516143532.png

1.可以使用乐鑫官方提供的ESPFlashDownloadTool

20190515225218.png

乐鑫官方可以下载最新版。

20190516145532.png

2.使用NodeMCU Flasher,多年没更新了(最后更新是2017年),不是很推荐用这个,我用12F没能烧写进去固件。

20190516145751.png

20190516145811.png

20190516145819.png

3.使用NodeMCU-PyFlasher,最新的烧写软件,不过不能手动修改固件的Flash地址,但是可以使用ESPFlashDownloadTool来合并。有Mac版,这是重点!!!
其实是esptool.py,这个工具的UI版。

20190516151014.png

合并为一个Bin,则能使用PyFlasher顺利烧录。

20190516143956.png

合并完成后选择target.bin即可。

20190516151401.png

SPI MODE

可以移步看一下资料:https://blog.csdn.net/recclay/article/details/78956580https://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,如有不同修改即可。

进入刷写模式

20190517131009.png

20190517130953.png

按住 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。

20190517113607.png

根据自己项目需要进行选择,如果不确定那个库是干嘛的,可以点击小问号,看文档里面写的。下面列举了常用的几个:

  • WS2801/WS2802/WS2812 effects 相应型号芯片的RGB灯库
  • PWM 就是PWM
  • end user setup 用户可以通过界面配置联网(具体看文档)
  • HTTP 支持HTTP请求(具体看文档)
  • tmr 定时器

强烈建议你把下面的Debug顺便勾上,TLS/SSL support也可以选择上,虽然废话有点多,但是不是很大的坏事。
会有两封邮件,第一封是开始Build,第二封就是NodeMCU custom build finished,如下图:

20190517113415.png

有两个版本,floatinteger,根据自己的需要进行下载开发,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")命令来修改。

20190517131614.png

如果一切正常,重新上电或者重启模组的时候会输出hello world。

当然,你不能指望使用file.writeline,写过多的代码,可以使用较新的ESPlorer和NodeMCU Studio 2015,也可以是ArduinoIDE。我最开始使用NodeMCU Studio 2015,一直不行,程序报各种溢出,ESPlorer是基于Java的,没有太大问题,ArduinoIDE我就不多说了。

20190517114837.png

20190517114927.png

首先你需要创建一个init.lua文件,写上代码,然后保存文件,再Sava to Esp,即可,大同小异。

使用MicroPython开发

步骤上和Lua差不多,就不多赘述了。

目的

官方已经发布了Gokit2,3(s)等版本的开发板。一般使用的就是独立MCU方案。官方的板子能够实现:红外传感器,温湿度传感器,小电机,RGB灯,用户按键等几个外设的驱动。我们只使用ESP8266也能实现该功能。

20190516141555.png

官方也提供了两种方案,前面是独立MCU方案,程序还是写在STM32或者Arduino底板上,ESP8266上就烧写GAgent,进行通讯。后面就是我们这次说的SOC方案,只有ESP8266,可以无需安装STM32或者Arduino。机智云提供了很好的教程:GoKit3(S) 二次开发--开发环境搭建

20190516141829.png

搭建开发环境

前面的生成出来的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即可。可以看:如何安装安信可一体化开发环境,下面是引用的官方的操作步骤。

  1. 打开 ConfigTool.exe,点击 Default 可以检测当前所在路径,或手动进行路径配置;
  2. 配置后点击 Save 进行保存;
  3. 打开 AiThinker_IDE.exe,可以直接进行固件的编译;
  4. 点击 OpenWorkSpace.bat,可以快速打开默认的project目录;
  5. 点击 Register 可注册 Cygwin Here快捷方式到鼠标右键,可实现在当前目录打开终端。

平台生成代码

各个官方都提供了良好的开源案例,NodeMCU和机智云还提供了生成源码。这能为我们再次简化非常多的开发时间。
例如在安信可官网提供了ESP8266 最新SDK,例如前面用到的AT:AiCloud 2.0 AT 固件,乐鑫原厂,乐鑫修改版等。
下面说的是机智云的代码生成。
首先你要生成相应的数据节点:
可以看机智云的定义数据点教程,我创建了典型的宠物屋数据点,下面是一部分的截图。

20190517142348.png

在服务->MCU开发中进行选择。

20190517142529.png

我们这里当然是选择SOC方案。Product Secret从基本信息中复制填写。

20190516114021.png

如果选择SOC,可以有如下方案,根据你自己的实际情况选择了。

20190516114047.png

如果选择MCU,可以有如下方案,MCU能选择的就很多了,就是底板,但是本文不讨论这个方面。

20190516114038.png

移植功能代码

上面的操作无误后,稍等片刻即会生成代码包,下载并解压。

20190517144450.png

帮助说明文件均在包内,如下图:

20190517144742.png

你可以使用安信可的Eclipse来进行编辑,我使用的VS Code。

整个云端自动生成的SOC源码里面,用户只需要关心文件路径为“GizLampapp”下面的几个地方:

如果你需要添加8266的外设,只需要在

“GizLampappdriver”文件目录下添加相应外设的驱动的.c文件
“GizLampappincludedriver”文件目录下添加相应外设的驱动的.h文件 App通过云端下发控制事件处理,可以在

“GizLampappGizwits”文件目录下“gizwits_product.c”文件里面的
“gizwitsEventProcess()函数里添加驱动外设执行事件函数即可实现控制设备 上报云端状态事件处理,可以在

“GizLampappuser”文件目录下“user_main.c”文件里面的“userTimerFunc()”函数里添加数据状态上报函数即可以实现状态上报。
在这套SOC源码里面需要关心也就这几个主要的地方,模块联网以及底层驱动均不需要开发者去处理和修改。

我们需要有用到的驱动外设的源文件,这取决与你需要那些设备,我们使用红外传感器,温湿度传感器,小电机,RGB灯,用户按键等几个外设的驱动,和Gokit相同。官方提供了ESP8266-SOC快速入门,讲了如何将代码移植进去。

首先我们下载需要的驱动外设的源文件,从机智云的下载中心。这些教程在DIY微信宠物屋_SOC版.pdf中都有,只是需要进行相应的修改。

20190517150032.png

GoKit_SoC_ESP8266_V03000003测试固件及开发资源2017072815.zip\驱动库代码\,所有.c的源文件,解压到SoC_ESP8266_32M_source\app\driver中。官方使用的hal_rgb_led.c,比如我的RGB不同,则使用的Adafruit_NeoPixel.c(下图中没有体现)

20190517150547.png

GoKit_SoC_ESP8266_V03000003测试固件及开发资源2017072815.zip\驱动库代码\,所有.h的头文件,解压到SoC_ESP8266_32M_source\app\include\driver中,如果前面的库也进行了修改,该处也要改(常识)。

20190517150938.png

然后我们就需要修改相关的函数调用。

首先找到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

20190517151351.png

void ICACHE_FLASH_ATTR userInit(void)函数中,增加:

///< 新添加代码: RGB LED初始化
rgbGpioInit();
rgbLedInit();
///< 新添加代码: 电机初始化
motorInit();
motorControl(0);
///< 新添加代码: 温湿度初始化
dh11Init();
///< 新添加代码: 红外初始化
irInit();

20190517151829.png

其他需要修改的代码多半在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);
}

20190517152535.png

增加按钮事件,在SoC_ESP8266_32M_source\app\useruser_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,没有问题会显示如下结果,表示编译通过没有问题。不要把源码等文件放到桌面!!!不是好习惯,下面仅为演示。

20190515225136.png

务必注意分区和spi mode等。

机智云配网

使用机智云APP即可。

20190516113838.png

题外话-调试工具

如果烧写的GAgent,则可以用机智云串口调试助手,模拟MCU的指令。

20190515225256.png

安信可的串口调试工具,AiThinker Serial Tool V1.2.3。

20190517163641.png

题外话-其他传感器连接

可以参照Gokit的电路图。

20190517163924.png

20190517163932.png

20190517163939.png

20190517164003.png

20190517164240.png