項(xiàng)目內(nèi)容:
1.燈光控制
2.循環(huán)控制
3.溫度采集
4.溫度和噴淋自動(dòng)控制(手動(dòng)控制下加熱和噴淋可控,自動(dòng)模式下加熱和噴淋不可控)
5.狀態(tài)斷電記憶
云端部署:
本次設(shè)計(jì)以esp8266作為主控,SOC方案,利用賽博坦工具快速生成APP。
1.創(chuàng)建產(chǎn)品, 進(jìn)入開發(fā)者中心,點(diǎn)擊右上角,創(chuàng)建新產(chǎn)品,按照如圖所示創(chuàng)建新的產(chǎn)品。
2.創(chuàng)建數(shù)據(jù)點(diǎn)。
3.生成ESP8266_32M SOC代碼,下載到電腦備用。
4.由左上角的體驗(yàn)新版本切換到新版本開發(fā)者中心,點(diǎn)擊右上角+創(chuàng)建一個(gè)新的移動(dòng)應(yīng)用。
5.點(diǎn)開創(chuàng)建好的應(yīng)用,關(guān)聯(lián)設(shè)備到移動(dòng)應(yīng)用里面。其他參數(shù)根據(jù)自己需求進(jìn)行更改
6.回到新版本主頁,在左側(cè)選擇自己創(chuàng)建的產(chǎn)品,然后進(jìn)行模組配置。配置成樂鑫模組,注意只需要修改模組就行,熱點(diǎn)參數(shù)無需更改。
7.進(jìn)入應(yīng)用頁面,進(jìn)行控制頁面修改。
8.根據(jù)自己需求設(shè)置好控制模塊的大小以及圖標(biāo)。其余參數(shù)根據(jù)自己的需求修改。級的每個(gè)頁面都需要保存。
9.配置好所有參數(shù)過后,回到之前創(chuàng)建的移動(dòng)應(yīng)用里面,進(jìn)行應(yīng)用的構(gòu)建,構(gòu)建成功以后掃描后面的二維碼下載安裝到手機(jī),到此云端部署完成。
硬件接線:
此項(xiàng)目不公開PCB,可以自己購買4路繼電器,及防水溫度傳感器DS18B20探頭,ESP12S小系統(tǒng)板。
繼電器----GPIO13(加熱管)GPIO12(循環(huán)電機(jī))GPIO16(噴淋電機(jī))GPIO5(燈光)
配網(wǎng)按鍵----GPIO14(按下低電平)
程序修改:
1.本次采用IDE方式進(jìn)行開發(fā)編譯(開發(fā)環(huán)境鏈接:https://pan.baidu.com/s/1TTIU-74mBxo9UqxLbX7Grw 提取碼:0htq,解壓過后即可使用,路徑不能有中文),將前面下載的代碼進(jìn)行解壓,路徑不要含有中文。在IDE環(huán)境里面導(dǎo)入項(xiàng)目。導(dǎo)入步步驟易出錯(cuò),注意根據(jù)下圖中所示步驟進(jìn)行導(dǎo)入。
2.修改編譯參數(shù),打開根目錄下面的Makefile文件,然后修改23到27行的內(nèi)容。(注意:本教程代碼不可以在網(wǎng)頁上進(jìn)行復(fù)制粘貼,由于編碼不一致可能會導(dǎo)致程序不能編譯,無法編譯需要重新解壓代碼從頭再來。代碼需要自己手打。每次輸入代碼過后需要保存以后編譯才會生效。)
- BOOT?=new
- APP?=1
- SPI_SPEED?=40
- SPI_MODE?=QIO
- SPI_SIZE_MAP?=6
復(fù)制代碼
3.按鍵部分無需修改,因?yàn)樽詣?dòng)生成的代碼就是gpio14按鍵長按短按進(jìn)行網(wǎng)絡(luò)配置。繼電器引腳的初始化我們寫在按鍵函數(shù)的初始化里面, 初始化為輸出模式。
- GPIO_OUTPUT_SET(GPIO_ID_PIN(5),1);//燈光
- GPIO_OUTPUT_SET(GPIO_ID_PIN(13),1);//加熱管
- GPIO_OUTPUT_SET(GPIO_ID_PIN(12),1);//循環(huán)電機(jī)
- gpio16_output_conf();//噴淋電機(jī)
復(fù)制代碼
4.在gizwits_product.c和gizwits_product.h增加全局變量。
- //flash相關(guān)
- #define sec 137 //137扇區(qū),程序小于480K flash存儲的安全區(qū)域的起始地址137-1024扇區(qū)
- #define sec1 138 //138扇區(qū),程序小于480K flash存儲的安全區(qū)域的起始地址137-1024扇區(qū)
- bool STATE[6] = {0,0,0,0,0,0};//開機(jī)各個(gè)開關(guān)狀態(tài)標(biāo)識
- uint32_t Set_Temp=0; //溫度自動(dòng)控制
- uint32_t Open_Time=0; //噴淋開時(shí)間
- uint32_t Off_Time=0; //噴淋關(guān)時(shí)間
- extern bool STATE[6]; //開機(jī)各個(gè)開關(guān)狀態(tài)標(biāo)識
- extern uint32_t Set_Temp; //溫度自動(dòng)控制
- extern uint32_t Open_Time; //噴淋開時(shí)間
- extern uint32_t Off_Time; //噴淋關(guān)時(shí)間
復(fù)制代碼
\
5.在gizwits_product.c的gizwitsEventProcess函數(shù)里面對開關(guān)狀態(tài)進(jìn)行緩存。程序帶有注釋,此處不做截圖,具體參考下面的程序更改。(注意:此函數(shù)的是數(shù)據(jù)點(diǎn)下發(fā)過后,可寫類型的數(shù)據(jù)處理,會根據(jù)數(shù)據(jù)點(diǎn)的不同而不同。程序不能再網(wǎng)頁復(fù)制,會導(dǎo)致編碼不一致程序出錯(cuò))
- 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; //水循環(huán)打開
- }
- else
- {
- STATE[0]=0; //水循環(huán)關(guān)閉
- }
- STATE[6]=1;//flash存儲狀態(tài)
- 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; //如果為手動(dòng)模式,噴淋開關(guān)打開,否則不動(dòng)作
- STATE[6]=1;//flash存儲狀態(tài)
- }
- }
- else
- {
- if(STATE[4]==0)
- {
- STATE[2]=0; //如果為手動(dòng)模式,噴淋開關(guān)關(guān)閉,否則不動(dòng)作
- STATE[6]=1;//flash存儲狀態(tài)
- }
- }
- currentDataPoint.valueSpray = STATE[2];//更新數(shù)據(jù)點(diǎn),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; //燈光關(guān)閉
- }
- STATE[6]=1;//flash存儲狀態(tài)
- 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; //如果為手動(dòng)模式,加熱開關(guān)打開,否則不動(dòng)作
- STATE[6]=1;//flash存儲狀態(tài)
- }
- }
- else
- {
- if(STATE[4]==0)
- {
- STATE[3]=0; //如果為手動(dòng)模式,加熱開關(guān)關(guān)閉,否則不動(dòng)作
- STATE[6]=1;//flash存儲狀態(tài)
- }
- }
- currentDataPoint.valueHeating = STATE[3];//更新數(shù)據(jù)點(diǎn),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; //手動(dòng)模式
- break;
- case mode_VALUE1:
- STATE[4]=1; //自動(dòng)模式
- break;
- default:
- break;
- }
- STATE[6]=1;//flash存儲狀態(tài)
- 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; //緩存設(shè)置溫度
- STATE[6]=1;//flash存儲狀態(tài)
- 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;//緩存設(shè)置開時(shí)間
- STATE[6]=1;//flash存儲狀態(tài)
- 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;//緩存設(shè)置關(guān)時(shí)間
- STATE[6]=1;//flash存儲狀態(tài)
- break;
復(fù)制代碼
6. 接下來我們處理斷電開機(jī)之后開關(guān)以及各項(xiàng)參數(shù)的初始化。主要是利用flash讀取獲取參數(shù)。數(shù)據(jù)狀態(tài)存放在flash,后續(xù)教程及程序會有存儲體現(xiàn)。初始化主要修改userInit函數(shù)。
- void ICACHE_FLASH_ATTR userInit(void)
- {
- gizMemset((uint8_t *)¤tDataPoint, 0, sizeof(dataPoint_t));
- //flash相關(guān)
- uint32 value;
- //定義數(shù)組addr_case1
- uint8* addr_case1 = (uint8*)&value;//四字節(jié)對齊
- uint8* addr_case2 = (uint8*)&value;//四字節(jié)對齊
- //讀取flash數(shù)據(jù),sec*4*1024就是讀取起始地址,就是具體的字節(jié)地址
- 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; //水循環(huán)
- 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]);//水循環(huán)
- GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//燈光
- }
復(fù)制代碼
7.在gizwits_product.c新增DS18B20驅(qū)動(dòng)函數(shù)。由于程序太長此處不再截圖。
- /************************
- * 函 數(shù) 名 : Ds18b20Init
- * 函數(shù)功能 : 初始化
- * 輸 入 : 無
- * 輸 出 : 初始化成功返回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); //延時(shí)642us
- GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); //然后拉高總線,如果DS18B20做出反應(yīng)會將在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;//初始化成功
- }
- /************************
- * 函 數(shù) 名 : Ds18b20WriteByte
- * 函數(shù)功能 : 向18B20寫入一個(gè)字節(jié)
- * 輸 入 : dat
- * 輸 出 : 無
- ************************/
- void Ds18b20WriteByte(uint8 dat) {
- int i, j;
- for (j = 0; j < 8; j++) {
- GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 0); //每寫入一位數(shù)據(jù)之前先把總線拉低1us
- i++;
- GPIO_OUTPUT_SET(GPIO_ID_PIN(4), dat & 0x01); //然后寫入一個(gè)數(shù)據(jù),從最低位開始
- os_delay_us(70); //延時(shí)68us,持續(xù)時(shí)間最少60us
- GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); //然后釋放總線,至少1us給總線恢復(fù)時(shí)間才能接著寫入第二個(gè)數(shù)值
- dat >>= 1;
- }
- }
- /************************
- * 函 數(shù) 名 : Ds18b20ReadByte
- * 函數(shù)功能 : 讀取一個(gè)字節(jié)
- * 輸 入 : 無
- * 輸 出 : 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++; //延時(shí)6us等待數(shù)據(jù)穩(wěn)定
- bi = GPIO_INPUT_GET(GPIO_ID_PIN(4)); //讀取數(shù)據(jù),從最低位開始讀取
- /*將byte左移一位,然后與上右移7位后的bi,注意移動(dòng)之后移掉那位補(bǔ)0。*/
- byte = (byte >> 1) | (bi << 7);
- os_delay_us(48); //讀取完之后等待48us再接著讀取下一個(gè)數(shù)
- }
- return byte;
- }
- /************************
- * 函 數(shù) 名 : Ds18b20ChangTemp
- * 函數(shù)功能 : 讓18b20開始轉(zhuǎn)換溫度
- * 輸 入 : 無
- * 輸 出 : 無
- ************************/
- void Ds18b20ChangTemp() {
- Ds18b20Init();
- os_delay_us(500);
- os_delay_us(500);
- Ds18b20WriteByte(0xcc); //跳過ROM操作命令
- Ds18b20WriteByte(0x44); //溫度轉(zhuǎn)換命令
- // 延時(shí)100ms 等待轉(zhuǎn)換成功,而如果你是一直刷著的話,就不用這個(gè)延時(shí)了
- }
- /************************
- * 函 數(shù) 名 : Ds18b20ReadTempCom
- * 函數(shù)功能 : 發(fā)送讀取溫度命令
- * 輸 入 : 無
- * 輸 出 : 無
- ************************/
- void Ds18b20ReadTempCom() {
- Ds18b20Init();
- os_delay_us(500);
- os_delay_us(500);
- Ds18b20WriteByte(0xcc); //跳過ROM操作命令
- Ds18b20WriteByte(0xbe); //發(fā)送讀取溫度命令
- }
- /************************
- * 函 數(shù) 名 : Ds18b20ReadTemp
- * 函數(shù)功能 : 讀取溫度
- * 輸 入 : 無
- * 輸 出 : temp
- ************************/
- float Ds18b20ReadTemp() {
- float temp = 0;
- uint8 tmh, tml;
- uint32_t temp1;
- Ds18b20ChangTemp(); //先寫入轉(zhuǎn)換命令
- Ds18b20ReadTempCom(); //然后等待轉(zhuǎn)換完后發(fā)送讀取溫度命令
- tml = Ds18b20ReadByte(); //讀取溫度值共16位,先讀低字節(jié)
- tmh = Ds18b20ReadByte(); //再讀高字節(jié)
- temp1 = tmh;
- temp1 <<= 8;
- temp1 |= tml;
- temp = temp1*0.0625;
- temp = ((temp+0.005)*100)/100;//保留2位小數(shù),四舍五入
- return temp;
- }
復(fù)制代碼
在gizwits_product.c新增溫度傳感器的函數(shù)**。
- uint8 Ds18b20Init();
- void Ds18b20WriteByte(uint8 dat);
- uint8 Ds18b20ReadByte();
- void Ds18b20ChangTemp();
- void Ds18b20ReadTempCom();
- float Ds18b20ReadTemp();
復(fù)制代碼
8.在gizwits_product.c的userHandle函數(shù)里面對GPIO輸出點(diǎn),溫度采集,flash存儲以及邏輯控制進(jìn)行編寫。此處不在截圖。
- void ICACHE_FLASH_ATTR userHandle(void)
- {
- //flash相關(guān)
- uint32 value;
- //定義數(shù)組addr_case1
- uint8* addr_case1 = (uint8*)&value;
- uint8* addr_case2 = (uint8*)&value;
- LOCAL float tempvalue;//采集溫度
- LOCAL uint32_t opentime=0;//開計(jì)時(shí)
- LOCAL uint32_t offtime=0;//關(guān)計(jì)時(shí)
- LOCAL bool onoff=0;//開關(guān)狀態(tài),0關(guān),1開
- os_delay_us(642);
- LOCAL uint8_t temp_time=0;//溫度采集間隔時(shí)間
- if(temp_time<=1)temp_time++;
- else
- {
- temp_time=0;
- tempvalue = Ds18b20ReadTemp();
- currentDataPoint.valueTemperature = tempvalue;
- }
- if(STATE[4])//自動(dòng)模式下噴淋和加熱控制
- {
- //加熱溫度控制
- if(tempvalue<(float)Set_Temp) STATE[3]=1;
- else STATE[3]=0;
- //噴淋控制
- if(onoff)//開狀態(tài)
- {
- if(opentime>0) opentime--;
- else
- {
- onoff=0;//切換關(guān)狀態(tài)
- offtime=Off_Time*60;//賦值關(guān)閉時(shí)間
- STATE[2]=0;
- }
- }
- else if(onoff==0)//關(guān)狀態(tài)
- {
- if(offtime>0) offtime--;
- else
- {
- onoff=1;//切換開狀態(tài)
- opentime=Open_Time*60;//賦值打開時(shí)間
- 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 //手動(dòng)模式
- {
- GPIO_OUTPUT_SET(GPIO_ID_PIN(13),!STATE[3]);//加熱
- gpio16_output_set(!STATE[2]);//噴淋
- }
- if(STATE[6]==1) //狀態(tài)改變
- {
- STATE[6]=0;//清除狀態(tài)
- GPIO_OUTPUT_SET(GPIO_ID_PIN(12),!STATE[0]);//水循環(huán)
- GPIO_OUTPUT_SET(GPIO_ID_PIN(5),!STATE[1]);//燈光
- //flash存儲數(shù)據(jù)前轉(zhuǎn)換數(shù)據(jù)
- 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扇區(qū)
- spi_flash_erase_sector(sec);
- //寫入數(shù)據(jù),sec*4*1024就是寫入起始地址,就是具體的字節(jié)地址
- spi_flash_write(sec*4*1024, (uint32*)addr_case1, sizeof(addr_case1));
- //擦除要寫入的Flash扇區(qū)
- spi_flash_erase_sector(sec1);
- //寫入數(shù)據(jù),sec*4*1024就是寫入起始地址,就是具體的字節(jié)地址
- spi_flash_write(sec1*4*1024, (uint32*)addr_case2, sizeof(addr_case2));
- }
- system_os_post(USER_TASK_PRIO_2, SIG_UPGRADE_DATA, 0);
- }
復(fù)制代碼
9.修改完代碼之后ctrl+B進(jìn)行編譯固件編譯。
10.利用樂鑫燒錄軟件將生成的固件燒錄到ESP8266里面。參數(shù)參考下圖,注意參數(shù)不能有錯(cuò)。下載硬件接線如下表下載模式。記住通電瞬間就要保持這個(gè)狀態(tài)才是下載模式。
11.程序燒錄完成之后通過按鍵長按觸發(fā)airlink配網(wǎng)(或短按觸發(fā)softap配網(wǎng)),在APP選擇對應(yīng)的配網(wǎng)進(jìn)行網(wǎng)絡(luò)配置及綁定設(shè)備。綁定后進(jìn)入設(shè)備即可進(jìn)行采集和控制
12.實(shí)物展示展示
-
物聯(lián)網(wǎng)平臺
+關(guān)注
關(guān)注
7文章
97瀏覽量
20693
發(fā)布評論請先 登錄
相關(guān)推薦
評論