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行的内容。(注意:本教程代码不可以在网页上进行复制粘贴,由于编码不一致可能会导致程序不能编译,无法编译需要重新解压代码从头再来。代码需要自己手打。每次输入代码过后需要保存以后编译才会生效。)
BOOT?=new
APP?=1
SPI_SPEED?=40
SPI_MODE?=QIO
SPI_SIZE_MAP?=6
复制代码 3.按键部分无需修改,因为自动生成的代码就是gpio14按键长按短按进行网络配置。继电器引脚的初始化我们写在按键函数的初始化里面, 初始化为输出模式。
GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1);//灯光
GPIO_OUTPUT_SET(GPIO_ID_PIN(13),1);//加热管
GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);//循环电机
gpio16_output_conf();//喷淋电机
复制代码4.在gizwits_product.c和gizwits_product.h增加全局变量。
//flash相关
#define sec 137 //137扇区,程序小于480K flash存储的安全区域的起始地址137-1024扇区
#define sec1 138 //138扇区,程序小于480K flash存储的安全区域的起始地址137-1024扇区
bool STATE[6] = {0,0,0,0,0,0};//开机各个开关状态标识
uint32_t Set_Temp=0; //温度自动控制
uint32_t Open_Time=0; //喷淋开时间
uint32_t Off_Time=0; //喷淋关时间
extern bool STATE[6]; //开机各个开关状态标识
extern uint32_t Set_Temp; //温度自动控制
extern uint32_t Open_Time; //喷淋开时间
extern uint32_t Off_Time; //喷淋关时间
复制代码 5.在gizwits_product.c的gizwitsEventProcess函数里面对开关状态进行缓存。程序带有注释,此处不做截图,具体参考下面的程序更改。(注意:此函数的是数据点下发过后,可写类型的数据处理,会根据数据点的不同而不同。程序不能再网页复制,会导致编码不一致程序出错)
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)
{
case EVENT_Water_Cycle :
currentDataPoint.valueWater_Cycle = dataPointPtr->valueWater_Cycle;
GIZWITS_LOG("Evt: EVENT_Water_Cycle %d \n", currentDataPoint.valueWater_Cycle);
if(0x01 == currentDataPoint.valueWater_Cycle)
{
STATE[0]=1; //水循环打开
}
else
{
STATE[0]=0; //水循环关闭
}
STATE[6]=1;//flash存储状态
break;
case EVENT_Spray :
currentDataPoint.valueSpray = dataPointPtr->valueSpray;
GIZWITS_LOG("Evt: EVENT_Spray %d \n", currentDataPoint.valueSpray);
if(0x01 == currentDataPoint.valueSpray)
{
if(STATE[4]==0)
{
STATE[2]=1; //如果为手动模式,喷淋开关打开,否则不动作
STATE[6]=1;//flash存储状态
}
}
else
{
if(STATE[4]==0)
{
STATE[2]=0; //如果为手动模式,喷淋开关关闭,否则不动作
STATE[6]=1;//flash存储状态
}
}
currentDataPoint.valueSpray = STATE[2];//更新数据点,APP更新
break;
case EVENT_Lamp :
currentDataPoint.valueLamp = dataPointPtr->valueLamp;
GIZWITS_LOG("Evt: EVENT_Lamp %d \n", currentDataPoint.valueLamp);
if(0x01 == currentDataPoint.valueLamp)
{
STATE[1]=1; //灯光打开
}
else
{
STATE[1]=0; //灯光关闭
}
STATE[6]=1;//flash存储状态
break;
case EVENT_Heating :
currentDataPoint.valueHeating = dataPointPtr->valueHeating;
GIZWITS_LOG("Evt: EVENT_Heating %d \n", currentDataPoint.valueHeating);
if(0x01 == currentDataPoint.valueHeating)
{
if(STATE[4]==0)
{
STATE[3]=1; //如果为手动模式,加热开关打开,否则不动作
STATE[6]=1;//flash存储状态
}
}
else
{
if(STATE[4]==0)
{
STATE[3]=0; //如果为手动模式,加热开关关闭,否则不动作
STATE[6]=1;//flash存储状态
}
}
currentDataPoint.valueHeating = STATE[3];//更新数据点,APP更新
break;
case EVENT_mode:
currentDataPoint.valuemode = dataPointPtr->valuemode;
GIZWITS_LOG("Evt: EVENT_mode %d\n", currentDataPoint.valuemode);
switch(currentDataPoint.valuemode)
{
case mode_VALUE0:
STATE[4]=0; //手动模式
break;
case mode_VALUE1:
STATE[4]=1; //自动模式
break;
default:
break;
}
STATE[6]=1;//flash存储状态
break;
case EVENT_Set_Temperature:
currentDataPoint.valueSet_Temperature= dataPointPtr->valueSet_Temperature;
GIZWITS_LOG("Evt:EVENT_Set_Temperature %d\n",currentDataPoint.valueSet_Temperature);
Set_Temp = currentDataPoint.valueSet_Temperature; //缓存设置温度
STATE[6]=1;//flash存储状态
break;
case EVENT_Spray_Open_Time:
currentDataPoint.valueSpray_Open_Time= dataPointPtr->valueSpray_Open_Time;
GIZWITS_LOG("Evt:EVENT_Spray_Open_Time %d\n",currentDataPoint.valueSpray_Open_Time);
Open_Time = currentDataPoint.valueSpray_Open_Time;//缓存设置开时间
STATE[6]=1;//flash存储状态
break;
case EVENT_Spray_Off_Time:
currentDataPoint.valueSpray_Off_Time= dataPointPtr->valueSpray_Off_Time;
GIZWITS_LOG("Evt:EVENT_Spray_Off_Time %d\n",currentDataPoint.valueSpray_Off_Time);
Off_Time = currentDataPoint.valueSpray_Off_Time;//缓存设置关时间
STATE[6]=1;//flash存储状态
break;
复制代码6. 接下来我们处理断电开机之后开关以及各项参数的初始化。主要是利用flash读取获取参数。数据状态存放在flash,后续教程及程序会有存储体现。初始化主要修改userInit函数。
void ICACHE_FLASH_ATTR userInit(void)
{
gizMemset((uint8_t *)¤tDataPoint, 0, sizeof(dataPoint_t));
//flash相关
uint32 value;
//定义数组addr_case1
uint8* addr_case1 = (uint8*)&value;//四字节对齐
uint8* addr_case2 = (uint8*)&value;//四字节对齐
//读取flash数据,sec*4*1024就是读取起始地址,就是具体的字节地址
spi_flash_read(sec*4*1024, (uint32*)addr_case1, sizeof(addr_case1));
spi_flash_read(sec1*4*1024, (uint32*)addr_case2, sizeof(addr_case2));
if(addr_case1[0]==1) STATE[0]=1; //水循环
else STATE[0]=0;
if(addr_case1[1]==1) STATE[1]=1; //灯光
else STATE[1]=0;
if(addr_case1[2]==1) STATE[2]=1; //喷淋
else STATE[2]=0;
if(addr_case1[3]==1) STATE[3]=1; //加热
else STATE[3]=0;
if(addr_case2[0]==1) STATE[4]=1; //模式
else STATE[4]=0;
currentDataPoint.valueSet_Temperature = (uint32_t)addr_case2[1];
currentDataPoint.valueSpray_Open_Time = (uint32_t)addr_case2[2];
currentDataPoint.valueSpray_Off_Time = (uint32_t)addr_case2[3];
currentDataPoint.valueWater_Cycle = STATE[0];
currentDataPoint.valueSpray = STATE[2];
currentDataPoint.valueLamp = STATE[1];
currentDataPoint.valueHeating = STATE[3];
currentDataPoint.valuemode = STATE[4];
currentDataPoint.valueTemperature = 0;
Set_Temp = currentDataPoint.valueSet_Temperature;
Open_Time = currentDataPoint.valueSpray_Open_Time;
Off_Time = currentDataPoint.valueSpray_Off_Time;
GPIO_OUTPUT_SET(GPIO_ID_PIN(12),!STATE[0]);//水循环
GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//灯光
}
复制代码
7.在gizwits_product.c新增DS18B20驱动函数。由于程序太长此处不再截图。
/************************
* 函 数 名 : Ds18b20Init
* 函数功能 : 初始化
* 输 入 : 无
* 输 出 : 初始化成功返回1,失败返回0
************************/
uint8 Ds18b20Init() {
int i;
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0); //将总线拉低480us~960us
os_delay_us(642); //延时642us
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
while (GPIO_INPUT_GET(GPIO_ID_PIN(4))) //等待DS18B20拉低总线
{
os_delay_us(500);
os_delay_us(500);
i++;
if (i > 5) //等待>5MS
{
return 0; //初始化失败
}
}
return 1; //初始化成功
}
/************************
* 函 数 名 : Ds18b20WriteByte
* 函数功能 : 向18B20写入一个字节
* 输 入 : dat
* 输 出 : 无
************************/
void Ds18b20WriteByte(uint8 dat) {
int i, j;
for (j = 0; j < 8; j++) {
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0); //每写入一位数据之前先把总线拉低1us
i++;
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), dat & 0x01); //然后写入一个数据,从最低位开始
os_delay_us(70); //延时68us,持续时间最少60us
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
dat >>= 1;
}
}
/************************
* 函 数 名 : Ds18b20ReadByte
* 函数功能 : 读取一个字节
* 输 入 : 无
* 输 出 : byte
************************/
uint8 Ds18b20ReadByte() {
uint8 byte, bi;
int i, j;
for (j = 8; j > 0; j--) {
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0); //先将总线拉低1us
i++;
GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); //然后释放总线
i++;
i++; //延时6us等待数据稳定
bi = GPIO_INPUT_GET(GPIO_ID_PIN(4)); //读取数据,从最低位开始读取
/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
byte = (byte >> 1) | (bi << 7);
os_delay_us(48); //读取完之后等待48us再接着读取下一个数
}
return byte;
}
/************************
* 函 数 名 : Ds18b20ChangTemp
* 函数功能 : 让18b20开始转换温度
* 输 入 : 无
* 输 出 : 无
************************/
void Ds18b20ChangTemp() {
Ds18b20Init();
os_delay_us(500);
os_delay_us(500);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令
Ds18b20WriteByte(0x44); //温度转换命令
// 延时100ms 等待转换成功,而如果你是一直刷着的话,就不用这个延时了
}
/************************
* 函 数 名 : Ds18b20ReadTempCom
* 函数功能 : 发送读取温度命令
* 输 入 : 无
* 输 出 : 无
************************/
void Ds18b20ReadTempCom() {
Ds18b20Init();
os_delay_us(500);
os_delay_us(500);
Ds18b20WriteByte(0xcc); //跳过ROM操作命令
Ds18b20WriteByte(0xbe); //发送读取温度命令
}
/************************
* 函 数 名 : Ds18b20ReadTemp
* 函数功能 : 读取温度
* 输 入 : 无
* 输 出 : temp
************************/
float Ds18b20ReadTemp() {
float temp = 0;
uint8 tmh, tml;
uint32_t temp1;
Ds18b20ChangTemp(); //先写入转换命令
Ds18b20ReadTempCom(); //然后等待转换完后发送读取温度命令
tml = Ds18b20ReadByte(); //读取温度值共16位,先读低字节
tmh = Ds18b20ReadByte(); //再读高字节
temp1 = tmh;
temp1 <<= 8;
temp1 |= tml;
temp = temp1*0.0625;
temp = ((temp+0.005)*100)/100;//保留2位小数,四舍五入
return temp;
}
复制代码在gizwits_product.c新增温度传感器的函数**。
uint8 Ds18b20Init();
void Ds18b20WriteByte(uint8 dat);
uint8 Ds18b20ReadByte();
void Ds18b20ChangTemp();
void Ds18b20ReadTempCom();
float Ds18b20ReadTemp();
复制代码 8.在gizwits_product.c的userHandle函数里面对GPIO输出点,温度采集,flash存储以及逻辑控制进行编写。此处不在截图。
void ICACHE_FLASH_ATTR userHandle(void)
{
//flash相关
uint32 value;
//定义数组addr_case1
uint8* addr_case1 = (uint8*)&value;
uint8* addr_case2 = (uint8*)&value;
LOCAL float tempvalue;//采集温度
LOCAL uint32_t opentime=0;//开计时
LOCAL uint32_t offtime=0;//关计时
LOCAL bool onoff=0;//开关状态,0关,1开
os_delay_us(642);
LOCAL uint8_t temp_time=0;//温度采集间隔时间
if(temp_time<=1)temp_time++;
else
{
temp_time=0;
tempvalue = Ds18b20ReadTemp();
currentDataPoint.valueTemperature = tempvalue;
}
if(STATE[4])//自动模式下喷淋和加热控制
{
//加热温度控制
if(tempvalue<(float)Set_Temp) STATE[3]=1;
else STATE[3]=0;
//喷淋控制
if(onoff)//开状态
{
if(opentime>0) opentime--;
else
{
onoff=0;//切换关状态
offtime=Off_Time*60;//赋值关闭时间
STATE[2]=0;
}
}
else if(onoff==0)//关状态
{
if(offtime>0) offtime--;
else
{
onoff=1;//切换开状态
opentime=Open_Time*60;//赋值打开时间
STATE[2]=1;
}
}
gpio16_output_set(!STATE[2]);//喷淋
GPIO_OUTPUT_SET(GPIO_ID_PIN(13),!STATE[3]);//加热
currentDataPoint.valueSpray = STATE[2];
currentDataPoint.valueHeating = STATE[3];
}
else //手动模式
{
GPIO_OUTPUT_SET(GPIO_ID_PIN(13),!STATE[3]);//加热
gpio16_output_set(!STATE[2]);//喷淋
}
if(STATE[6]==1) //状态改变
{
STATE[6]=0;//清除状态
GPIO_OUTPUT_SET(GPIO_ID_PIN(12),!STATE[0]);//水循环
GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//灯光
//flash存储数据前转换数据
addr_case1[0] = (uint8)STATE[0];
addr_case1[1] = (uint8)STATE[1];
addr_case1[2] = (uint8)STATE[2];
addr_case1[3] = (uint8)STATE[3];
addr_case2[0] = (uint8)STATE[4];
addr_case2[1] = (uint8)currentDataPoint.valueSet_Temperature;
addr_case2[2] = (uint8)currentDataPoint.valueSpray_Open_Time ;
addr_case2[3] = (uint8)currentDataPoint.valueSpray_Off_Time;
//擦除要写入的Flash扇区
spi_flash_erase_sector(sec);
//写入数据,sec*4*1024就是写入起始地址,就是具体的字节地址
spi_flash_write(sec*4*1024, (uint32*)addr_case1, sizeof(addr_case1));
//擦除要写入的Flash扇区
spi_flash_erase_sector(sec1);
//写入数据,sec*4*1024就是写入起始地址,就是具体的字节地址
spi_flash_write(sec1*4*1024, (uint32*)addr_case2, sizeof(addr_case2));
}
system_os_post(USER_TASK_PRIO_2, SIG_UPGRADE_DATA, 0);
}
复制代码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集成电路推向超低功耗物联网的量产
Taoglas 针对多无线天线系列的紧凑型物联网设计
嵌入式系统的一些新理念
SmartDV展示完整的边缘与连接IP解决方案,以高速和低功耗特性赋能移动、物联网和媒体处理设备创新
芯科科技驱动和重塑智能门锁行业格局
3.许居衍_从信息化进程视野理解物联网的发展_2010物联网峰会
RFID技术在移动电子商务中的应用
边缘计算与人工智能(Edge AI)如何引领新一轮技术革命
智慧城市IPv6互联参考设计
物联网无线系统+Xilinx Zynq 开发板申请
基于K60的物联网数据采集器
“智慧的地球”与“物联网”(转)
1.工信部领导致辞_2010物联网峰会
RFID中间件关键技术研究
基于ANDROID4.X的智能电视电脑一体机的设计方案
基于K60的webserver图像监控系统
物联网与RFID芯片
基于物联网的电池组均衡充电与监控系统
ZedBoard开发板申请
物联网的输电高压线路智能驱鸟系统
求物联网和嵌入式的大神指教
智能家居系统
低代码利器!MIT 可视化编程赋能 AI + 物联网移动端开发
2.无锡市领导致辞_2010物联网峰会
Kwikset:超低功耗Wi-Fi解锁无缝体验
嵌入式系统与物联网
被收购后的芯科实验室:物联网与人工智能的未来走向
ARM首席技术官谈物联网的过去、现在和未来
基于蓝牙的汽车物联网应用与开发
TDK 发布 SensorStage 传感器评估平台,大幅加速 IMU 开发进程