實驗硬件:STM32F103ZET6;0.96寸OLED(128×64);ESP8266,DHT11;LED;KEY
硬件實物圖:

效果圖:



引腳連接:
OLED模塊引腳:
VCC --> 3.3V
GND --> GND
SCL --> PB10
SDA --> PB11
ESP8266模塊引腳:
VCC --> 3.3V
GND --> GND
RX--> PB10
TX --> PB11
RST --> PB9
EN --> PB7
DHT11傳感器引腳:
VCC --> 3.3V
GND --> GND
DATA-->PE0
一、物聯網
1.1 物聯網簡介
物聯網(Internet of Things,簡稱IoT)是指通過各種信息傳感器、射頻識別技術、全球定位系統、紅外感應器、激光掃描器等各種裝置與技術,實時采集任何需要監控、 連接、互動的物體或過程,采集其聲、光、熱、電、力學、化學、生物、位置等各種需要的信息,通過各類可能的網絡接入,實現物與物、物與人的泛在連接,實現對物品和過程的智能化感知、識別和管理。物聯網是一個基于互聯網、傳統電信網等的信息承載體,它讓所有能夠被獨立尋址的普通物理對象形成互聯互通的網絡 。
總而言之,物聯網就是利用現代互聯網技術實現端對端的數據互聯與控制。
1.2 物聯網開發
目前,物聯網開發的形式是多種多樣的。總的來說,一般都需借助特定的網絡服務平臺為基礎實現數據的上傳與下發(如果只考慮內網是可以不需要的,比如ESP32CAM)。
實力雄厚或者有一定背景的公司通常考慮可能自建網絡協議服務器,專屬服務自家的物聯網產品開發。當然,也有不少企業會選擇借助他人網絡服務平臺去實現自家的物聯網開發。
這里比較著名的網絡服務平臺有:中國移動旗下的OneNet、阿里巴巴旗下阿里云以及機智云平臺。
平臺分析:
機智云:機智云作為物聯網開發服務平臺的元老,一直致力于完善和搭建快速高效的服務機制,其有一套自己快速開發適配的物聯網實現流程。但是,在筆者使用的過程中也存在著一些弊端。比如:
(1)其需要給ESP8266等WIFI模塊刷上自家的固件才可使用;
(2)狀態極其不穩定,很容易斷聯或者死活連不上;
(3)受限于開發模式,對于產品自我開發有一定限制;
OneNet和阿里云平臺:這2大平臺背靠強大的資源和技術支持,其服務穩定。設定的開發框架也更多樣化,可以提供開發者更多的發揮空間。
二、OneNet平臺使用
從多元化和產品穩定性方面考慮,作者將以中國移動旗下的OneNet服務平臺為案例進行教學講解。(其實本來打算以機智云出一篇案例的,結果后來發現之前能正常聯動的MCU和APP動不動就宕機。后來,索性直接就以OneNet這個框架更開放的平臺為案例教學)
2.1 OneNet準備
1、注冊OneNet平臺賬號(網址:OneNET - 中國移動物聯網開放平臺 (10086.cn));

2、 登入后選擇控制臺,進入后點擊全部產品服務,選擇多協議接入;(我們使用MQTT,既可以上傳數據也可以下發數據控制,而且都是免費的)

3、選擇MQTT(舊版)之后添加產品,按照自己實際需求填寫產品內容;

4、點擊所創建的產品,添加幾個設備(免費版用戶上限10個設備)

5、注意設備ID,鑒權信息以及接入方式這3個屬性;

6、關于數據流模塊可以設置,可以不設置,反正最后通訊正常的情況下會收到需要的數據流;

2.2 OneNet調試
在設置好OneNet平臺設備后,其實可以借助該平臺自帶的API調試工具進行調試檢測(前提:下位機已經成果接通了)。
這里的調試使用API函數的介紹和使用可以參考文檔中心(一個合格的嵌入式工程師是一定需要學會自己去查看技術支持文檔,而且OneNet提供的文檔內容還是非常詳盡的)。
OneNet技術文檔網址:OneNET - 中國移動物聯網開放平臺 (10086.cn)

網絡協議通訊關鍵函數
服務器或上位機查詢讀取設備歷史數據:
API函數:
請求方式:GET
URL:
http://api.heclouds.com/devices/device_id/datapoints

服務器或上位機下發主題報文(控制下位機):
API函數:
請求方式:POST
URL: http://api.heclouds.com/mqtt?topic=xxx

以上2個網絡通訊的API函數至關重要,就是實現常規情況下OneNet物聯網開發的關鍵性技術支持。(情況允許的條件下,建議讀者朋友們去好好研讀一下技術文檔,將會為之后的開發大大助力)
三、下位機外設驅動
3.1 ESP8266模塊
作者采用的ESP8266模塊為ESP8266NodeMCU,是需要進行燒入AT固件,才能實現目標網絡通訊。作為常見的物聯網開發模塊,ESP8266的出現大大降低了物聯網開發的難度系數,也普及了物聯網的發展。
AT指令最早在藍牙模塊上接觸過,所謂AT指令實質上就是一些起控制作用的特殊字符串。模塊可以通過AT指令控制搭配使用源代碼API函數開發,總體開發速度快,難度較低。
不同廠商芯片的AT固件可能有所不同,但是指令基本一致(作者使用的是樂鑫的)。
說明:由于篇幅有限,這里就不和大家單獨詳細介紹AT指令。指令的詳細參數及使用說明請參考官方文檔:ESP8266 AT指令集。

3.2 OLED模塊
本項目中0.96寸OLED模塊的使用僅為顯示DHT11傳感器采集到的溫濕度信息,以此來對比是否和服務器端以及上位機APP端的數據一致性。對其使用有不是太了解的讀者朋友可以參考,作者另一篇基礎教學博客:(2條消息) 【強烈推薦】基于stm32的OLED各種顯示實現(含動態圖)_混分巨獸龍某某的博客-CSDN博客_oled顯示圖片程序
本項目的代碼都是基于作者以前基礎教學上的項目代碼搭建而成,保證讀者朋友可以實現快速復現。
3.3 DHT11模塊
本項目中DHT11為下位機MCU采集周圍環境溫度和濕度的傳感器,當然,條件允許的情況下還可以附加很多環境傳感器(比如:煙霧傳感器,環境光傳感器,二氧化碳傳感器等等)。當然得益于OneNet平臺的布局,本項目教學的底層邏輯支持讀者朋友的自我DIY,實現自主化的物聯網產品設計。
DHT11模塊驅動參考博客:基于stm32的太空人溫濕度時鐘項目——DHT11(HAL庫)_混分巨獸龍某某的博客-CSDN博客

3.4 KEY和LED
KEY和LED都是源于作者正點原子精英版開發板上自備的(如果和作者同款開發板移植開發將會特別簡單快速),屬于最基本的GPIO操作相信各位應該都是掌握的
特別注意:
(1)這里的KEY按鍵從設計邏輯上就可以看出應該是需要采用外部中斷的;
(2)KEY按下之后會改變LED的亮滅狀態,為了同步上位機此時的LED狀態,所以需要觸發串口通訊中斷(考慮嵌套中斷情況時候中斷優先級的安排)。
四、CubeMX配置
1、RCC配置外部高速晶振(精度更高)——HSE;

2、SYS配置:Debug設置成Serial Wire(否則可能導致芯片自鎖);

3、TIM2配置:由上面可知DHT11的使用需要us級的延遲函數,HAL庫自帶只有ms的,所以需要自己設計一個定時器;

4、I2C2配置:作為OLED的通訊方式;

5、UART1和UART3配置:MCU分別與電腦和ESP8266通訊(記得開啟串口通信中斷);



6、設置KEY0按鍵PE4為外部中斷(根據自己的開發板來確定)

7、GPIO配置:PE0設置為DHT11的DATA端,PE5為LED,并且設置ESP8266的EN和RST(PB7和PB9);

8、時鐘樹配置

五、代碼與解析
5.1 OLED與DHT11模塊代碼
受篇幅限制OLED與DHT11部分的代碼,這里就不展示了。如果有不懂這部分原理與代碼的讀者朋友可以參考本人的另一篇博客。博客地址:基于stm32的太空人溫濕度時鐘項目——DHT11(HAL庫)_混分巨獸龍某某的博客-CSDN博客
5.2 ESP8266模塊代碼
ESP8266部分的代碼主要是借助串口通訊AT指令與ESP8266模塊(刷入AT固件的)與OneNet平臺進行信息交互(包含ESP8266初始化、數據發送,指令發送和數據緩存清除等)。
esp8266.h代碼:
#ifndef _ESP8266_H_
#define _ESP8266_H_
#include "main.h"
#include "usart.h"
#include
#include
#include
#define ESP8266_WIFI_INFO "AT+CWJAP="NJUST","768541ly"\r\n" //連接上自己的wifi熱點:WiFi名和密碼
#define ESP8266_ONENET_INFO "AT+CIPSTART="TCP","183.230.40.39",6002\r\n" //連接上OneNet的MQTT
#define OK 0 //接收完成標志
#define OUTTIME 1 //接收未完成標志
void ESP8266_Clear(void); //清空緩存
void ESP8266_Init(void); //esp8266初始化
_Bool ESP8266_SendCmd(char *cmd, char *res);//發送數據
unsigned char *ESP8266_GetIPD(unsigned short timeOut);
void ESP8266_SendData(unsigned char *data, unsigned short len);
#endif
esp8266.c代碼:
#include "esp8266.h"
unsigned char ESP8266_Buf[128]; //定義一個數組作為esp8266的數據緩沖區
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0; //定義兩個計數值:此次和上一次
unsigned char a_esp8266_buf;
/**
* @brief esp8266初始化
* @param 無
* @retval 無
*/
void ESP8266_Init(void)
{
ESP8266_Clear();
printf("1. 測試AT啟動\r\n"); //AT:測試AT啟動
while(ESP8266_SendCmd("AT\r\n", "OK"))
HAL_Delay(500);
printf("2. 設置WiFi模式(CWMODE)\r\n"); //查詢/設置 Wi-Fi 模式:設置WiFi模式為Station模式
while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
HAL_Delay(500);
printf("3. AT+CWDHCP\r\n"); //啟用/禁用 DHCP
while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
HAL_Delay(500);
printf("4. 連接WiFi熱點(CWJAP)\r\n");
while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "GOT IP"))
HAL_Delay(500);
printf("5. 建立TCP連接(CIPSTART)\r\n");
while(ESP8266_SendCmd(ESP8266_ONENET_INFO, "CONNECT"))
HAL_Delay(500);
printf("6. ESP8266 Init OK\r\n");
}
/**
* @brief 清空緩存
* @param 無
* @retval 無
*/
void ESP8266_Clear(void)
{
memset(ESP8266_Buf, 0, sizeof(ESP8266_Buf)); //將數組中的元素全部初始化為0,
}
/**
* @brief 等待接收完成
* @param 無
* @retval OK:表示接收完成;OUTTIME:表示接收超時完成
* 進行循環調用,檢測接收是否完成
*/
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //如果當前接收計數為0 則說明沒有處于接收數據中,所以直接跳出,結束函數
return OUTTIME;
if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和這次相同,則說明接收完畢
{
esp8266_cnt = 0; //清0接收計數
return OK; //返回接收完成標志
}
else //如果不相同,則將此次賦值給上一次,并返回接收未完成標志
{
esp8266_cntPre = esp8266_cnt;
return OUTTIME;
}
}
/**
* @brief 發送命令
* @param cmd:表示命令;res:需要檢查的返回指令
* @retval 0:表示成功;1:表示失敗
*/
_Bool ESP8266_SendCmd(char *cmd, char *res)
{
unsigned char timeOut = 200;
HAL_UART_Transmit(&huart3, (unsigned char *)cmd, strlen((const char *)cmd),0xffff);
while(timeOut--)
{
if(ESP8266_WaitRecive() == OK) //如果收到數據
{
printf("%s",ESP8266_Buf);
if(strstr((const char *)ESP8266_Buf, res) != NULL) //如果檢索到關鍵詞,清空緩存
{
ESP8266_Clear();
return 0;
}
}
HAL_Delay(10);
}
return 1;
}
/**
* @brief 數據發送
* @param data:待發送的數據;len:待發送的數據長度
* @retval 無
*/
void ESP8266_SendData(unsigned char *data, unsigned short len)
{
char cmdBuf[32];
ESP8266_Clear(); //清空接收緩存
sprintf(cmdBuf, "AT+CIPSEND=%d\r\n", len); //發送命令,sprintf()函數用于將格式化的數據寫入字符串
if(!ESP8266_SendCmd(cmdBuf, ">")) //收到‘>’時可以發送數據
{
HAL_UART_Transmit(&huart3, data, len,0xffff); //發送設備連接請求數據
}
}
/**
* @brief 獲取平臺返回的數據
* @param 等待的時間
* @retval 平臺返回的數據,不同網絡設備返回的格式不同,需要進行調試,如:ESP8266的返回格式為:"+IPD,x:yyy",x表示數據長度,yyy表示數據內容
*/
unsigned char *ESP8266_GetIPD(unsigned short timeOut)
{
char *ptrIPD = NULL;
do
{
if(ESP8266_WaitRecive() == OK) //如果接收完成
{
ptrIPD = strstr((char *)ESP8266_Buf, "IPD,"); //搜索“IPD”頭
if(ptrIPD == NULL) //如果沒找到,可能是IPD頭的延遲,還是需要等待一會,但不會超過設定的時間
{
//UsartPrintf(USART_DEBUG, ""IPD" not found\r\n");
}
else
{
ptrIPD = strchr(ptrIPD, ':'); //找到':'
if(ptrIPD != NULL)
{
ptrIPD++;
return (unsigned char *)(ptrIPD);
}
else
return NULL;
}
}
HAL_Delay(5); //延時等待
} while(timeOut--);
return NULL; //超時還未找到,返回空指針
}
/**
* @brief 串口2收發中斷回調函數
* @param
* @retval
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(esp8266_cnt >= 255) //溢出判斷,超過一個字節
{
esp8266_cnt = 0;
memset(ESP8266_Buf,0x00,sizeof(ESP8266_Buf));
HAL_UART_Transmit(&huart3, (uint8_t *)"數據溢出", 10,0xFFFF);
}
else
{
ESP8266_Buf[esp8266_cnt++] = a_esp8266_buf; //接收數據轉存
}
HAL_UART_Receive_IT(&huart3, (uint8_t *)&a_esp8266_buf, 1); //再開啟接收中斷
}
代碼總結:
ESP8266模塊的代碼基于HAL庫實現,主要是利用AT指令去使下位機(STM32+ESP8266)連接上WIFI,并且與OneNet平臺進行MQTT協議通信(TCP連接IP地址和對應端口)。
特別注意:
使用ESP8266進行通訊時,當數據量較大的時候一定要編寫緩存清除代碼(否則,很有可能出現死機等情況)。當然,這個時候可以搭配SD NAND(貼片式TF卡)去存儲傳輸的數據流。同時,利用這些保存在SD卡中的數據,可以在下位機制作精美的數據歷史信息UI,極大的拓展了產品價值。
————————————————
【本文轉載自CSDN,作者:混分巨獸龍某某】
-
智能家居
+關注
關注
1933文章
9746瀏覽量
189586 -
SD
+關注
關注
1文章
167瀏覽量
34305
發布評論請先 登錄
手機APP遠程控制,智能家居監測、智能控制系統(STM32L4、服務器、安卓源碼)實例項目打包下載
手機APP遠程控制,智能家居監測、智能控制系統(STM32L4、服務器、安卓源碼)
Matter 智能家居的通用語言
明遠智睿SSD2351開發板:智能家居的智能核心
智能家居Mesh組網方案:實現智能化生活的無縫連接NRF52832
CS創世SD NAND【貼片式sd卡】的測試使用說明

CS創世SD NAND【貼片式sd卡】的測試使用說明
【貝啟科技BQ3568HM開源鴻蒙開發板深度試用報告】2 - 智能家居中控屏界面設計:打造便捷的家居控制體驗
LG全面開放ThinQ智能家居平臺API
STM32F407 MCU使用SD NAND?不斷電初始化失效解決方案

評論