专栏中心

EEPW首页 > 专栏 > 开源教程:基于ESP8266和机智云的智能雨林缸,成本低、高智能

开源教程:基于ESP8266和机智云的智能雨林缸,成本低、高智能

发布人:Gizwits 时间:2022-01-17 来源:工程师 发布文章
项目内容:
1.灯光控制
2.循环控制
3.温度采集
4.温度和喷淋自动控制(手动控制下加热和喷淋可控,自动模式下加热和喷淋不可控)
5.状态断电记忆



云端部署:
本次设计以esp8266作为主控,SOC方案,利用赛博坦工具快速生成APP。
1.创建产品, 进入开发者中心,点击右上角,创建新产品,按照如图所示创建新的产品。

2.创建数据点。
3.生成ESP8266_32M SOC代码,下载到电脑备用。
4.由左上角的体验新版本切换到新版本开发者中心,点击右上角+创建一个新的移动应用。
5.点开创建好的应用,关联设备到移动应用里面。其他参数根据自己需求进行更改
6.回到新版本主页,在左侧选择自己创建的产品,然后进行模组配置。配置成乐鑫模组,注意只需要修改模组就行,热点参数无需更改。
7.进入应用页面,进行控制页面修改。
8.根据自己需求设置好控制模块的大小以及图标。其余参数根据自己的需求修改。级的每个页面都需要保存。
9.配置好所有参数过后,回到之前创建的移动应用里面,进行应用的构建,构建成功以后扫描后面的二维码下载安装到手机,到此云端部署完成。



硬件接线:
此项目不公开PCB,可以自己购买4路继电器,及防水温度传感器DS18B20探头,ESP12S小系统板。
继电器----GPIO13(加热管)GPIO12(循环电机)GPIO16(喷淋电机)GPIO5(灯光)
配网按键----GPIO14(按下低电平)
温度传感器----GPIO4(传感器需要上拉电阻)



程序修改:
       1.本次采用IDE方式进行开发编译(开发环境链接:https://pan.baidu.com/s/1TTIU-74mBxo9UqxLbX7Grw 提取码:0htq,解压过后即可使用,路径不能有中文),将前面下载的代码进行解压,路径不要含有中文。在IDE环境里面导入项目。导入步步骤易出错,注意根据下图中所示步骤进行导入。

       2.修改编译参数,打开根目录下面的Makefile文件,然后修改23到27行的内容。(注意:本教程代码不可以在网页上进行复制粘贴,由于编码不一致可能会导致程序不能编译,无法编译需要重新解压代码从头再来。代码需要自己手打。每次输入代码过后需要保存以后编译才会生效。)
  1. BOOT?=new

  2. APP?=1

  3. SPI_SPEED?=40

  4. SPI_MODE?=QIO

  5. SPI_SIZE_MAP?=6

复制代码

       3.按键部分无需修改,因为自动生成的代码就是gpio14按键长按短按进行网络配置。继电器引脚的初始化我们写在按键函数的初始化里面, 初始化为输出模式。
  1. GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1);//灯光

  2.     GPIO_OUTPUT_SET(GPIO_ID_PIN(13),1);//加热管

  3.     GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);//循环电机

  4.     gpio16_output_conf();//喷淋电机

复制代码

4.在gizwits_product.c和gizwits_product.h增加全局变量。
  1. //flash相关

  2. #define sec 137 //137扇区,程序小于480K flash存储的安全区域的起始地址137-1024扇区

  3. #define sec1 138 //138扇区,程序小于480K flash存储的安全区域的起始地址137-1024扇区

  4. bool STATE[6] = {0,0,0,0,0,0};//开机各个开关状态标识

  5. uint32_t Set_Temp=0;   //温度自动控制

  6. uint32_t Open_Time=0;       //喷淋开时间

  7. uint32_t Off_Time=0;    //喷淋关时间

  8. extern bool STATE[6];   //开机各个开关状态标识

  9. extern uint32_t Set_Temp;    //温度自动控制

  10. extern uint32_t Open_Time; //喷淋开时间

  11. extern uint32_t Off_Time;     //喷淋关时间

复制代码

       5.在gizwits_product.c的gizwitsEventProcess函数里面对开关状态进行缓存。程序带有注释,此处不做截图,具体参考下面的程序更改。(注意:此函数的是数据点下发过后,可写类型的数据处理,会根据数据点的不同而不同。程序不能再网页复制,会导致编码不一致程序出错)
  1. int8_t ICACHE_FLASH_ATTR gizwitsEventProcess(eventInfo_t *info, uint8_t *data, uint32_t len)

  2. {

  3.     uint8_t i = 0;

  4.     dataPoint_t * dataPointPtr = (dataPoint_t *)data;

  5.     moduleStatusInfo_t * wifiData = (moduleStatusInfo_t *)data;

  6.     if((NULL == info) || (NULL == data))

  7.     {

  8.         GIZWITS_LOG("!!! gizwitsEventProcess Error \n");

  9.         return -1;

  10.     }

  11.     for(i = 0; i < info->num; i++)

  12.     {

  13.         switch(info->event)

  14.         {

  15.         case EVENT_Water_Cycle :

  16.             currentDataPoint.valueWater_Cycle = dataPointPtr->valueWater_Cycle;

  17.             GIZWITS_LOG("Evt: EVENT_Water_Cycle %d \n", currentDataPoint.valueWater_Cycle);

  18.             if(0x01 == currentDataPoint.valueWater_Cycle)

  19.             {

  20.                    STATE[0]=1;   //水循环打开

  21.             }

  22.             else

  23.             {

  24.                    STATE[0]=0;   //水循环关闭

  25.             }

  26.             STATE[6]=1;//flash存储状态

  27.             break;

  28.         case EVENT_Spray :

  29.             currentDataPoint.valueSpray = dataPointPtr->valueSpray;

  30.             GIZWITS_LOG("Evt: EVENT_Spray %d \n", currentDataPoint.valueSpray);

  31.             if(0x01 == currentDataPoint.valueSpray)

  32.             {

  33.                    if(STATE[4]==0)

  34.                             {

  35.                           STATE[2]=1;   //如果为手动模式,喷淋开关打开,否则不动作

  36.                           STATE[6]=1;//flash存储状态

  37.                             }

  38.             }

  39.             else

  40.             {

  41.                    if(STATE[4]==0)

  42.                    {

  43.                           STATE[2]=0; //如果为手动模式,喷淋开关关闭,否则不动作

  44.                           STATE[6]=1;//flash存储状态

  45.                    }

  46.             }

  47.             currentDataPoint.valueSpray = STATE[2];//更新数据点,APP更新

  48.             break;

  49.         case EVENT_Lamp :

  50.             currentDataPoint.valueLamp = dataPointPtr->valueLamp;

  51.             GIZWITS_LOG("Evt: EVENT_Lamp %d \n", currentDataPoint.valueLamp);

  52.             if(0x01 == currentDataPoint.valueLamp)

  53.             {

  54.                    STATE[1]=1;   //灯光打开

  55.             }

  56.             else

  57.             {

  58.                    STATE[1]=0;   //灯光关闭

  59.             }

  60.             STATE[6]=1;//flash存储状态

  61.             break;

  62.         case EVENT_Heating :

  63.             currentDataPoint.valueHeating = dataPointPtr->valueHeating;

  64.             GIZWITS_LOG("Evt: EVENT_Heating %d \n", currentDataPoint.valueHeating);

  65.             if(0x01 == currentDataPoint.valueHeating)

  66.             {

  67.                    if(STATE[4]==0)

  68.                    {

  69.                           STATE[3]=1;   //如果为手动模式,加热开关打开,否则不动作

  70.                           STATE[6]=1;//flash存储状态

  71.                    }

  72.             }

  73.                      else

  74.                      {

  75.                             if(STATE[4]==0)

  76.                             {

  77.                                    STATE[3]=0; //如果为手动模式,加热开关关闭,否则不动作

  78.                                    STATE[6]=1;//flash存储状态

  79.                             }

  80.                      }

  81.                      currentDataPoint.valueHeating = STATE[3];//更新数据点,APP更新

  82.             break;

  83.         case EVENT_mode:

  84.             currentDataPoint.valuemode = dataPointPtr->valuemode;

  85.             GIZWITS_LOG("Evt: EVENT_mode %d\n", currentDataPoint.valuemode);

  86.             switch(currentDataPoint.valuemode)

  87.             {

  88.             case mode_VALUE0:

  89.                    STATE[4]=0;   //手动模式

  90.                 break;

  91.             case mode_VALUE1:

  92.                    STATE[4]=1;   //自动模式

  93.                 break;

  94.             default:

  95.                 break;

  96.             }

  97.             STATE[6]=1;//flash存储状态

  98.             break;

  99.         case EVENT_Set_Temperature:

  100.             currentDataPoint.valueSet_Temperature= dataPointPtr->valueSet_Temperature;

  101.             GIZWITS_LOG("Evt:EVENT_Set_Temperature %d\n",currentDataPoint.valueSet_Temperature);

  102.             Set_Temp = currentDataPoint.valueSet_Temperature;     //缓存设置温度

  103.             STATE[6]=1;//flash存储状态

  104.             break;

  105.         case EVENT_Spray_Open_Time:

  106.             currentDataPoint.valueSpray_Open_Time= dataPointPtr->valueSpray_Open_Time;

  107.             GIZWITS_LOG("Evt:EVENT_Spray_Open_Time %d\n",currentDataPoint.valueSpray_Open_Time);

  108.             Open_Time = currentDataPoint.valueSpray_Open_Time;//缓存设置开时间

  109.             STATE[6]=1;//flash存储状态

  110.             break;

  111.         case EVENT_Spray_Off_Time:

  112.             currentDataPoint.valueSpray_Off_Time= dataPointPtr->valueSpray_Off_Time;

  113.             GIZWITS_LOG("Evt:EVENT_Spray_Off_Time %d\n",currentDataPoint.valueSpray_Off_Time);

  114.             Off_Time = currentDataPoint.valueSpray_Off_Time;//缓存设置关时间

  115.             STATE[6]=1;//flash存储状态

  116.             break;

复制代码

6. 接下来我们处理断电开机之后开关以及各项参数的初始化。主要是利用flash读取获取参数。数据状态存放在flash,后续教程及程序会有存储体现。初始化主要修改userInit函数。
  1. void ICACHE_FLASH_ATTR userInit(void)

  2. {

  3.     gizMemset((uint8_t *)¤tDataPoint, 0, sizeof(dataPoint_t));

  4.     //flash相关

  5.        uint32 value;

  6.        //定义数组addr_case1

  7.        uint8* addr_case1 = (uint8*)&value;//四字节对齐

  8.        uint8* addr_case2 = (uint8*)&value;//四字节对齐

  9.        //读取flash数据,sec*4*1024就是读取起始地址,就是具体的字节地址

  10.        spi_flash_read(sec*4*1024, (uint32*)addr_case1, sizeof(addr_case1));

  11.        spi_flash_read(sec1*4*1024, (uint32*)addr_case2, sizeof(addr_case2));

  12.        if(addr_case1[0]==1) STATE[0]=1;      //水循环

  13.               else STATE[0]=0;

  14.        if(addr_case1[1]==1) STATE[1]=1;      //灯光

  15.               else STATE[1]=0;

  16.        if(addr_case1[2]==1) STATE[2]=1;      //喷淋

  17.               else STATE[2]=0;

  18.        if(addr_case1[3]==1) STATE[3]=1;      //加热

  19.               else STATE[3]=0;

  20.        if(addr_case2[0]==1) STATE[4]=1;      //模式

  21.               else STATE[4]=0;

  22.        currentDataPoint.valueSet_Temperature = (uint32_t)addr_case2[1];

  23.        currentDataPoint.valueSpray_Open_Time = (uint32_t)addr_case2[2];

  24.        currentDataPoint.valueSpray_Off_Time = (uint32_t)addr_case2[3];

  25.        currentDataPoint.valueWater_Cycle = STATE[0];

  26.        currentDataPoint.valueSpray = STATE[2];

  27.        currentDataPoint.valueLamp = STATE[1];

  28.        currentDataPoint.valueHeating = STATE[3];

  29.        currentDataPoint.valuemode = STATE[4];

  30.        currentDataPoint.valueTemperature = 0;

  31.        Set_Temp = currentDataPoint.valueSet_Temperature;

  32.        Open_Time = currentDataPoint.valueSpray_Open_Time;

  33.        Off_Time = currentDataPoint.valueSpray_Off_Time;

  34.        GPIO_OUTPUT_SET(GPIO_ID_PIN(12),!STATE[0]);//水循环

  35.        GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//灯光

  36. }

复制代码

7.在gizwits_product.c新增DS18B20驱动函数。由于程序太长此处不再截图。
  1. /************************

  2. * 函 数 名         : Ds18b20Init

  3. * 函数功能            : 初始化

  4. * 输    入         : 无

  5. * 输    出         : 初始化成功返回1,失败返回0

  6. ************************/

  7. uint8 Ds18b20Init() {

  8.        int i;

  9.        PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);

  10.        GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0);            //将总线拉低480us~960us

  11.        os_delay_us(642);         //延时642us

  12.        GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1);     //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低

  13.        while (GPIO_INPUT_GET(GPIO_ID_PIN(4))) //等待DS18B20拉低总线

  14.        {

  15.               os_delay_us(500);

  16.               os_delay_us(500);

  17.               i++;

  18.               if (i > 5)   //等待>5MS

  19.                             {

  20.                      return 0;  //初始化失败

  21.               }

  22.        }

  23.        return 1;  //初始化成功

  24. }

  25. /************************

  26. * 函 数 名         : Ds18b20WriteByte

  27. * 函数功能            : 向18B20写入一个字节

  28. * 输    入         : dat

  29. * 输    出         : 无

  30. ************************/

  31. void Ds18b20WriteByte(uint8 dat) {

  32.        int i, j;

  33.        for (j = 0; j < 8; j++) {

  34.               GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0);                 //每写入一位数据之前先把总线拉低1us

  35.               i++;

  36.               GPIO_OUTPUT_SET(GPIO_ID_PIN(4), dat & 0x01);                //然后写入一个数据,从最低位开始

  37.               os_delay_us(70); //延时68us,持续时间最少60us

  38.               GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1);     //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值

  39.               dat >>= 1;

  40.        }

  41. }

  42. /************************

  43. * 函 数 名         : Ds18b20ReadByte

  44. * 函数功能            : 读取一个字节

  45. * 输    入         : 无

  46. * 输    出         : byte

  47. ************************/

  48. uint8 Ds18b20ReadByte() {

  49.        uint8 byte, bi;

  50.        int i, j;

  51.        for (j = 8; j > 0; j--) {

  52.               GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0);     //先将总线拉低1us

  53.               i++;

  54.               GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1);       //然后释放总线

  55.               i++;

  56.               i++;   //延时6us等待数据稳定

  57.               bi = GPIO_INPUT_GET(GPIO_ID_PIN(4));    //读取数据,从最低位开始读取

  58.               /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/

  59.               byte = (byte >> 1) | (bi << 7);

  60.               os_delay_us(48); //读取完之后等待48us再接着读取下一个数

  61.        }

  62.        return byte;

  63. }

  64. /************************

  65. * 函 数 名         : Ds18b20ChangTemp

  66. * 函数功能            : 让18b20开始转换温度

  67. * 输    入         : 无

  68. * 输    出         : 无

  69. ************************/

  70. void Ds18b20ChangTemp() {

  71.        Ds18b20Init();

  72.        os_delay_us(500);

  73.        os_delay_us(500);

  74.        Ds18b20WriteByte(0xcc);             //跳过ROM操作命令

  75.        Ds18b20WriteByte(0x44);         //温度转换命令

  76. //     延时100ms 等待转换成功,而如果你是一直刷着的话,就不用这个延时了

  77. }

  78. /************************

  79. * 函 数 名         : Ds18b20ReadTempCom

  80. * 函数功能            : 发送读取温度命令

  81. * 输    入         : 无

  82. * 输    出         : 无

  83. ************************/

  84. void Ds18b20ReadTempCom() {

  85.        Ds18b20Init();

  86.        os_delay_us(500);

  87.        os_delay_us(500);

  88.        Ds18b20WriteByte(0xcc);      //跳过ROM操作命令

  89.        Ds18b20WriteByte(0xbe);     //发送读取温度命令

  90. }

  91. /************************

  92. * 函 数 名         : Ds18b20ReadTemp

  93. * 函数功能            : 读取温度

  94. * 输    入         : 无

  95. * 输    出         : temp

  96. ************************/

  97. float Ds18b20ReadTemp() {

  98.        float temp = 0;

  99.        uint8 tmh, tml;

  100.        uint32_t temp1;

  101.        Ds18b20ChangTemp();                    //先写入转换命令

  102.        Ds18b20ReadTempCom();                 //然后等待转换完后发送读取温度命令

  103.        tml = Ds18b20ReadByte();          //读取温度值共16位,先读低字节

  104.        tmh = Ds18b20ReadByte();         //再读高字节

  105.        temp1 = tmh;

  106.        temp1 <<= 8;

  107.        temp1 |= tml;

  108.        temp = temp1*0.0625;

  109.        temp = ((temp+0.005)*100)/100;//保留2位小数,四舍五入

  110.        return temp;

  111. }

复制代码

在gizwits_product.c新增温度传感器的函数**。
  1. uint8 Ds18b20Init();

  2. void Ds18b20WriteByte(uint8 dat);

  3. uint8 Ds18b20ReadByte();

  4. void Ds18b20ChangTemp();

  5. void Ds18b20ReadTempCom();

  6. float Ds18b20ReadTemp();

复制代码

       8.在gizwits_product.c的userHandle函数里面对GPIO输出点,温度采集,flash存储以及逻辑控制进行编写。此处不在截图。
  1. void ICACHE_FLASH_ATTR userHandle(void)

  2. {

  3.        //flash相关

  4.        uint32 value;

  5.        //定义数组addr_case1

  6.        uint8* addr_case1 = (uint8*)&value;

  7.        uint8* addr_case2 = (uint8*)&value;

  8.        LOCAL float tempvalue;//采集温度

  9.        LOCAL uint32_t opentime=0;//开计时

  10.        LOCAL uint32_t offtime=0;//关计时

  11.        LOCAL bool onoff=0;//开关状态,0关,1开

  12.        os_delay_us(642);

  13.        LOCAL uint8_t temp_time=0;//温度采集间隔时间

  14.        if(temp_time<=1)temp_time++;

  15.        else

  16.        {

  17.               temp_time=0;

  18.               tempvalue = Ds18b20ReadTemp();

  19.               currentDataPoint.valueTemperature = tempvalue;

  20.        }

  21.        if(STATE[4])//自动模式下喷淋和加热控制

  22.        {

  23.               //加热温度控制

  24.               if(tempvalue<(float)Set_Temp) STATE[3]=1;

  25.                      else STATE[3]=0;

  26.               //喷淋控制

  27.               if(onoff)//开状态

  28.               {

  29.                      if(opentime>0) opentime--;

  30.                      else

  31.                      {

  32.                             onoff=0;//切换关状态

  33.                             offtime=Off_Time*60;//赋值关闭时间

  34.                             STATE[2]=0;

  35.                      }

  36.               }

  37.               else if(onoff==0)//关状态

  38.               {

  39.                      if(offtime>0) offtime--;

  40.                      else

  41.                      {

  42.                             onoff=1;//切换开状态

  43.                             opentime=Open_Time*60;//赋值打开时间

  44.                             STATE[2]=1;

  45.                      }

  46.               }

  47.               gpio16_output_set(!STATE[2]);//喷淋

  48.               GPIO_OUTPUT_SET(GPIO_ID_PIN(13),!STATE[3]);//加热

  49.               currentDataPoint.valueSpray = STATE[2];

  50.               currentDataPoint.valueHeating = STATE[3];

  51.        }

  52.        else //手动模式

  53.        {

  54.               GPIO_OUTPUT_SET(GPIO_ID_PIN(13),!STATE[3]);//加热

  55.               gpio16_output_set(!STATE[2]);//喷淋

  56.        }

  57.        if(STATE[6]==1)     //状态改变

  58.        {

  59.               STATE[6]=0;//清除状态

  60.               GPIO_OUTPUT_SET(GPIO_ID_PIN(12),!STATE[0]);//水循环

  61.               GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//灯光

  62.               //flash存储数据前转换数据

  63.               addr_case1[0] = (uint8)STATE[0];

  64.               addr_case1[1] = (uint8)STATE[1];

  65.               addr_case1[2] = (uint8)STATE[2];

  66.               addr_case1[3] = (uint8)STATE[3];

  67.               addr_case2[0] = (uint8)STATE[4];

  68.               addr_case2[1] = (uint8)currentDataPoint.valueSet_Temperature;

  69.               addr_case2[2] = (uint8)currentDataPoint.valueSpray_Open_Time ;

  70.               addr_case2[3] = (uint8)currentDataPoint.valueSpray_Off_Time;

  71.               //擦除要写入的Flash扇区

  72.               spi_flash_erase_sector(sec);

  73.               //写入数据,sec*4*1024就是写入起始地址,就是具体的字节地址

  74.               spi_flash_write(sec*4*1024, (uint32*)addr_case1, sizeof(addr_case1));

  75.               //擦除要写入的Flash扇区

  76.               spi_flash_erase_sector(sec1);

  77.               //写入数据,sec*4*1024就是写入起始地址,就是具体的字节地址

  78.               spi_flash_write(sec1*4*1024, (uint32*)addr_case2, sizeof(addr_case2));

  79.        }

  80.     system_os_post(USER_TASK_PRIO_2, SIG_UPGRADE_DATA, 0);

  81. }     

复制代码

9.修改完代码之后ctrl+B进行编译固件编译。
10.利用乐鑫烧录软件将生成的固件烧录到ESP8266里面。参数参考下图,注意参数不能有错。下载硬件接线如下表下载模式。记住通电瞬间就要保持这个状态才是下载模式。
11.程序烧录完成之后通过按键长按触发airlink配网(或短按触发softap配网),在APP选择对应的配网进行网络配置及绑定设备。绑定后进入设备即可进行采集和控制
12.实物展示展示

https://v.youku.com/v_show/id_XNTgzNTI0NzIzMg==.html?spm=a2hbt.13141534.0.13141534


专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词: 雨林鱼缸 智能鱼缸 物联网

相关推荐

纳米电力将nPZero集成电路推向超低功耗物联网的量产

2026-04-09

Taoglas 针对多无线天线系列的紧凑型物联网设计

嵌入式系统的一些新理念

视频 2012-10-31

​SmartDV展示完整的边缘与连接IP解决方案,以高速和低功耗特性赋能移动、物联网和媒体处理设备创新

芯科科技驱动和重塑智能门锁行业格局

3.许居衍_从信息化进程视野理解物联网的发展_2010物联网峰会

RFID技术在移动电子商务中的应用

边缘计算与人工智能(Edge AI)如何引领新一轮技术革命

1.工信部领导致辞_2010物联网峰会

RFID中间件关键技术研究

物联网与RFID芯片

视频 2009-12-21

基于物联网的电池组均衡充电与监控系统

物联网的输电高压线路智能驱鸟系统

智能家居系统

低代码利器!MIT 可视化编程赋能 AI + 物联网移动端开发

2.无锡市领导致辞_2010物联网峰会

Kwikset:超低功耗Wi-Fi解锁无缝体验

嵌入式系统与物联网

被收购后的芯科实验室:物联网与人工智能的未来走向

TDK 发布 SensorStage 传感器评估平台,大幅加速 IMU 开发进程

更多 培训课堂
更多 焦点
更多 视频

技术专区