?
一、環境介紹
MCU:采用意法半導體低功耗芯片 STM32L431RCT6
編譯軟件:Keil5 +CubeMX
云平臺:采用阿里云物聯網云平臺
?
?
二、功能與硬件介紹
2.1 功能介紹
前面的一篇文章是同樣的環境,云平臺采用的是騰訊物聯網云平臺(基于STM32L431設計的云端綠化管理系統(ESP8266+騰訊物聯網云平臺)_DS小龍哥的專欄-CSDN博客_stm32l431)
這篇文章將云平臺換成了阿里云物聯網平臺,其他硬件功能都是一樣的。
再次介紹一下功能:
這是采用STM32L431 + ES8266設計的云端綠化管理系統,可以通過ESP8266 WIFI連接阿里云物聯網平臺,使用網頁和阿里云的APP遠程進行綠化管理,比如:實時獲取光照強度、溫度、濕度、遠程控制水泵進行澆水灌溉,在任何地方都可以給自己種的花花草草澆水,了解周邊環境情況。
2.2 硬件介紹
開發板采用的是小熊開發板,包括完成綠化管理系統的所有功能都是采用小熊派開發板的配套套件完成。
小熊開發板板載了一個stlink調試器(就是STM32F103C8T6實現的),程序下載非常方便。串口1用來調試打印數據,ESP8266是接在串口LPUART1上的。
?
小熊派開發板本身自帶的例子程序也比較豐富,自帶例子里采用的云平臺是華為的物聯網云平臺,工程比較龐大使用了LiteOS操作系統。本文里的工程是重新編寫的代碼,使用裸機完成項目功能,沒有跑操作系統,云平臺采用阿里云平臺服務器,MQTT協議和ESP8266驅動代碼都是重新編寫,框架、邏輯比較清晰,代碼量也較少,適合初學者入門學習。
相關傳感器模塊型號:(采用的是小熊開發板配套的E53_IA1擴展板)
?
WIFI采用:ESP8266
溫濕度檢測傳感器采用:SHT30
光照強度檢測傳感器采用:BH1750
電機采用:微型直流電機
?
?
三、阿里云物聯網云平臺
關于阿里云物聯網平臺的創建與使用之前也介紹過一篇,只不過MCU采用的是STM32F103C8T6,這篇文章MCU采用的是STM32L431RCT6,屬于低功耗系列,更加適合物聯網領域;如果之前沒有使用過阿里云物聯網云平臺,先參考這里學習了解一下:STM32+ESP8266+MQTT協議連接阿里云物聯網平臺_DS小龍哥的專欄-CSDN博客_stm32連接阿里云
3.1 在阿里云物聯網平臺創建產品
官網地址:阿里云登錄 - 歡迎登錄阿里云,安全穩定的云計算服務平臺
?
創建產品:
?
配置產品模型參數:頁面最后加密方式這些選擇默認
?
添加設備:
?
?
設備添加之后,可以一鍵將設備證書復制下來保存到記事本,方便后面使用;不復制也沒關系,后面也可以設備信息中查看的:
?
{
"ProductKey": "a1ukQj2EnEJ",
"DeviceName": "GreeningManagement",
"DeviceSecret": "a5268d71d363f1bd68e708c9097fa3d2"
}
設備添加完成:
?
在設備信息的頁面也可以查看設備證書:
?
?
添加功能屬性字段:
?
?
?
根據自己產品交互使用的數據類型進行定義:(綠化管理系統使用了溫度、濕度、電機、光照強度一共4個數據字段。其中電機是讀寫類型,其他都是只讀類型)
?
?
?
?
自定義功能屬性添加完畢之后就發布上線:
?
查看物模型數據格式:后面通過MQTT協議向服務器上報數據就是這個格式
?
可以選擇導出模型文件,導出是一個json格式文件,方便設備端開發參考。
?
3.2 通過IoT Studio創建web可視化界面
地址:阿里云登錄 - 歡迎登錄阿里云,安全穩定的云計算服務平臺
之前舊版本的IoT Studio 選項是在產品頁面里,現在移到控制臺首頁了。
新建項目:
?
?
?
新建web應用:
?
?
設計WEB頁面之前 先關聯產品和設備:
?
選擇對應的產品進行關聯:
?
選擇對應的設備進行關聯:
?
關聯成功:
?
下面繼續編輯web頁面:
?
可以更改頁面名稱:
?
添加組件,設計頁面: 阿里云的web頁面控件非常豐富,可以根據自己需求設計好看的頁面。
?
接下來就要給每個控件配置數據源:
?
?
調整儀表盤的屬性:刻度字號
?
配置完畢:
?
?
有域名的可以綁定到域名:
?
這里可以預覽頁面:
?
四、登錄阿里云平臺測試
4.1 MQTT協議登錄的域名與端口號
關于MQTT協議登錄所需要的參數官方說明文檔:使用MQTT.fx接入物聯網平臺 - 阿里云物聯網平臺 - 阿里云
MQTT登錄域名的格式:
${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com
其中:
${YourProductKey}:請替換為設備所屬產品的ProductKey
${YourRegionId}:請替換為物聯網平臺設備所在地域代碼。
下面是阿里云國內的服務器地域和可用區詳情:
地域名稱 所在城市 Region ID 可用區數量
華北 1 青島 cn-qingdao 2
華北 2 北京 cn-beijing 10
華北 3 張家口 cn-zhangjiakou 3
華北 5 呼和浩特 cn-huhehaote 2
華北 6 烏蘭察布 cn-wulanchabu 3
華東 1 杭州 cn-hangzhou 8
華東 2 上海 cn-shanghai 8
華南 1 深圳 cn-shenzhen 6
華南 2 河源 cn-heyuan 2
華南 3 廣州 cn-guangzhou 2
西南 1 成都 cn-chengdu 2
端口號是:1883
經過上面的格式解釋,我的阿里云服務器登錄的域名就是(選擇的是上海服務器):a1ukQj2EnEJ.iot-as-mqtt.cn-shanghai.aliyuncs.com
域名對應的IP地址(動態解析出來的): 106.14.207.159
在線解析域名網站:ip地址查詢 ip查詢 查ip 公網ip地址歸屬地查詢 網站ip查詢 同ip網站查詢 iP反查域名 iP查域名 同ip域名
4.2 MQTT協議登錄的ID、用戶名、密碼
4.2.1MQTT_ClientID
固定格式:${ClientID}|securemode=${Mode},signmethod=${SignMethod}|。
參數說明:
${ClientId}: 設備ID,一般填設備的硬件編號。我這里就直接填當前的設備名稱,后面的密碼里也要填這個ID,必須一樣就行。(設備名稱就是創建設備的時候復制出來3個參數里的設備名稱)
securemode=3:TCP直連模式,無需設置SSL/TLS信息。
securemode=2:TLS直連模式,需要設置SSL/TLS信息。
${SignMethod}:算法類型,支持hmacmd5和hmacsha1。
示例:
當前我的綠化管理系統設備名稱是:GreeningManagement ,選擇TCP直連模式,選擇hmacsha1算法類型。
那么我的ClientID就是:
GreeningManagement|securemode=3,signmethod=hmacsha1|
4.2.2MQTT_UserName
固定格式:${DeviceName}&${ProductKey}
參數解釋:
${DeviceName} 是設備的名稱(就是創建設備的時候復制出來3個參數里的設備名稱)
${ProductKey} 是設備的ProductKey(就是創建設備的時候復制出來3個參數里的ProductKey)
示例:
當前我的綠化管理系統設備名稱是:GreeningManagement ,我的ProductKey是:a1ukQj2EnEJ
那么我的UserName就是:
GreeningManagement&a1ukQj2EnEJ
4.2.3MQTT_PassWord
下載密碼生成小工具:使用MQTT.fx接入物聯網平臺 - 阿里云物聯網平臺 - 阿里云
?
下載工具,運行:
?
根據說明填充參數:
?
說明:productKey、deviceName、deviceSecret:是設備證書信息,可在控制臺設備詳情頁查看。clientID在4.2.1小節里已經說過了。時間戳可以省略不填。
點擊Generate生成密碼。
經過小工具生成后的密碼是:
9E580B36EE7E001980AF61EA09EAF85F0211C146
4.3 使用MQTT客戶端工具登錄阿里云服務器
MQTT客戶端工具下載地址:QT應用編程: 編寫MQTT客戶端登錄OnetNet服務器完成主題訂閱與發布_DS小龍哥的專欄-CSDN博客_onenet topic訂閱與發布
根據前面獲取的參數填入,登錄測試: (為了保證不會斷開連接,可以勾選MQTT客戶端右下角的心跳包選項,保活)
?
如果登錄成功,在阿里云控制臺頁面上可以看到設備已經在線:
?
?
如果設備能成功上線,那么就說明MQTT所需要的參數都已經填正確了,接下來就可以正常訂閱、發布主題了。
4.4 主題訂閱、發布測試
屬性上報主題與屬性設置主題格式:
?
發布主題:
/sys/a1ukQj2EnEJ/GreeningManagement/thing/event/property/post
上報屬性消息的格式(精簡格式):
{"method":"thing.event.property.post","params":{"temperature":11.1,"humidity":12.1,"illumination":13,"machine":1}}
上報屬性消息的格式詳細格式(可以帶上ID和版本號):
{"method":"thing.event.property.post","id":"1234567890","params":{"temperature":66.1,"humidity":22.1,"illumination":88,,"machine":1},"version":"1.1.1"}
訂閱主題:
/sys/a1ukQj2EnEJ/GreeningManagement/thing/service/property/set
通過MQTT客戶端訂閱主題、上報屬性數據:
?
把相關的參數填正確,然后登陸,訂閱、發布測試:
?
阿里云物聯網平臺云端收到的數據:
地址:阿里云登錄 - 歡迎登錄阿里云,安全穩定的云計算服務平臺
?
?
點擊頁面上的的按鈕,MQTT客戶端可以收到下發的消息(要先訂閱才能收到消息):
?
注意: 阿里云按鈕點擊下發消息之后,客戶端收到后要重新上報一次按鈕的狀態回去,不然阿里云按鈕會恢復之前的狀態。
五、STM32代碼測試
STM32的代碼主要分為以下幾個部分:
1.ESP8266底層驅動代碼:完成ESP8266模式配置、數據發送,應答檢測等底層網絡接口。
2.MQTT協議代碼:這是參考標準MQTT編寫C語言版本MQTT協議框架代碼,實現了重要的幾個接口(主題訂閱、主題發布、心跳包、登錄MQTT服務器),底層采用ESP8266發送數據。 這個MQTT協議不是使用ESP8266本身的SDK,是根據MQTT協議自己實現的,所以如果使用其他的網卡,移植也很方便,不挑網卡設備。
3.傳感器初始化代碼: 完成溫濕度傳感器、光照強度傳感器的驅動代碼編寫。
4.LCD屏代碼:LCD是SPI接口的,可以顯示溫濕度、光照強度數據。
5.main函數:完成整個邏輯代碼編寫,檢測阿里云平臺是否有下發的指令,進行分析,完成水泵的開關控制;當溫室和濕度到達某個閥值,自動控制水泵澆水,并上報給阿里云平臺;主程序里1秒檢測一次溫濕度、光照強度、電機狀態主動上報給阿里云平臺;在設備端按下按鍵(模擬現場實體開關)也可以控制水泵澆水或者關閉,這些狀態都會實時上報給云平臺。
程序的模板是使用CubeMX生成的。
?
5.1 main.c代碼
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2019 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32l4xx_hal.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"
#include "E53_IA1.h"
#include "lcd.h"
#include "spi.h"
#include "mqtt.h"
#include "esp8266.h"
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
void SystemClock_Config(void);
#define ESP8266_WIFI_AP_SSID "CMCC-Cqvn" //將要連接的路由器名稱 --不要出現中文、空格等特殊字符
#define ESP8266_AP_PASSWORD "99pu58cb" //將要連接的路由器密碼
//阿里云物聯網服務器的設備信息
#define MQTT_ClientID "GreeningManagement|securemode=3,signmethod=hmacsha1|"
#define MQTT_UserName "GreeningManagement&a1ukQj2EnEJ"
#define MQTT_PassWord "9E580B36EE7E001980AF61EA09EAF85F0211C146"
//訂閱與發布的主題
#define SET_TOPIC "/sys/a1ukQj2EnEJ/GreeningManagement/thing/service/property/set" //訂閱
#define POST_TOPIC "/sys/a1ukQj2EnEJ/GreeningManagement/thing/event/property/post" //發布
//保存溫濕度、光照強度
E53_IA1_Data_TypeDef E53_IA1_Data;
//顯示文本
char lcd_text_str[50];
UART_HandleTypeDef at_usart;
//低功耗串口初始化
int32_t at_usart_init(void)
{
at_usart.Instance = LPUART1;
at_usart.Init.BaudRate = 115200;
at_usart.Init.WordLength = UART_WORDLENGTH_8B;
at_usart.Init.StopBits = UART_STOPBITS_1;
at_usart.Init.Parity = UART_PARITY_NONE;
at_usart.Init.HwFlowCtl = UART_HWCONTROL_NONE;
at_usart.Init.Mode = UART_MODE_RX | UART_MODE_TX;
if(HAL_UART_Init(&at_usart) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
// __HAL_UART_CLEAR_FLAG(usart, UART_FLAG_TC);
__HAL_UART_ENABLE_IT(&at_usart, UART_IT_IDLE);
__HAL_UART_ENABLE_IT(&at_usart, UART_IT_RXNE);
HAL_NVIC_EnableIRQ(LPUART1_IRQn); //使能USART1中斷通道
HAL_NVIC_SetPriority(LPUART1_IRQn, 3, 3); //搶占優先級3,子優先級3
return 0;
}
unsigned char ESP8266_RecvBuf[MAX_RECV_CNT];
unsigned int ESP8266_Recv_cnt=0;
unsigned int ESP8266_Recv_flag=0;
void LPUART1_IRQHandler()
{
//接收到數據
if(__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_RXNE) != RESET)
{
if(ESP8266_Recv_cntRDR & 0x00FF);
}
else
{
ESP8266_Recv_flag=1;
}
}
else if (__HAL_UART_GET_FLAG(&at_usart, UART_FLAG_IDLE) != RESET)
{
__HAL_UART_CLEAR_IDLEFLAG(&at_usart);
ESP8266_Recv_flag=1;
}
}
void AT_SendData(unsigned char *p,unsigned int len)
{
int i=0;
for(i=0;iISR & 0X40) == 0); //循環發送,直到發送完畢
LPUART1->TDR = p[i];
}
}
char mqtt_message[200];
int main(void)
{
int i=0;
int cnt=0;
int motor_state=0;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI2_Init();
MX_USART1_UART_Init();
at_usart_init();
//初始化硬件 STM32L431RC_BearPiBH1750_I2C1\STM32L431RC_BearPiBH1750_I2C1.axf: Error: L6218E: Undefined symbol printf (referred from main.o).
Init_E53_IA1();
LCD_Init();
LCD_Clear(BLACK);//清屏為黑色
LCD_ShowString(20, 00, 240, 32, 32, "Init ESP8266");//顯示字符串,字體大小32*32
if(ESP8266_Init())
{
printf("ESP8266硬件檢測錯誤.\n");
LCD_Clear(BLACK);//清屏為黑色
LCD_ShowString(0, 00, 240, 32, 32, "ESP8266 ERROR");//顯示字符串,字體大小32*32
}
else
{
LCD_Clear(BLACK);//清屏為黑色
LCD_ShowString(20, 00, 240, 32, 32, "ESP8266 OK");//顯示字符串,字體大小32*32
printf("準備連接到指定的服務器.\n");
//非加密端口
printf("WIFI:%d\r\n",ESP8266_STA_TCP_Client_Mode(ESP8266_WIFI_AP_SSID,ESP8266_AP_PASSWORD,"a1ukQj2EnEJ.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883,1));
}
//2. MQTT協議初始化
MQTT_Init();
//3. 連接阿里云IOT服務器
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
printf("服務器連接失敗,正在重試...\n");
HAL_Delay(500);
}
printf("服務器連接成功.\n");
//3. 訂閱主題
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
printf("主題訂閱失敗.\n");
}
else
{
printf("主題訂閱成功.\n");
}
while (1)
{
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查詢按鍵KEY1低電平
{
HAL_Delay(10);//消抖
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)//查詢按鍵KEY1低電平
{
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);//亮
//補光燈亮
HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_SET);
//電機轉
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
motor_state=1;
}
}
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查詢按鍵KEY2低電平
{
HAL_Delay(10);//消抖
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)//查詢按鍵KEY2低電平
{
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);//滅
//補光燈滅
HAL_GPIO_WritePin(IA1_Light_GPIO_Port, IA1_Light_Pin, GPIO_PIN_RESET);
//電機停
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_RESET);
motor_state=0;
}
}
cnt++;
HAL_Delay(10);
if(cnt>=100)
{
cnt=0;
E53_IA1_Read_Data();
printf("光照強度:%.1f %%\r\n", E53_IA1_Data.Lux);
printf("濕度:%.1f %%\r\n",E53_IA1_Data.Humidity);
printf("溫度:%.1f ℃\r\n", E53_IA1_Data.Temperature);
sprintf(lcd_text_str,"L: %0.1f %%",E53_IA1_Data.Lux);
LCD_ShowString(40, 50+10+32*1, 240, 32, 32,lcd_text_str);
sprintf(lcd_text_str,"H: %.1f %%",E53_IA1_Data.Humidity);
LCD_ShowString(40, 50+10+32*2, 240, 32, 32,lcd_text_str);
sprintf(lcd_text_str,"T: %.1f C",E53_IA1_Data.Temperature);
LCD_ShowString(40, 50+10+32*3, 240, 32, 32,lcd_text_str);
//切換引腳的狀態
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
//上傳數據
sprintf(mqtt_message,"{"method":"thing.event.property.post","id":"1234567890","params":{"temperature":%f,"humidity":%f,"illumination":%f,"machine":%d},"version":"1.1.1"}",
E53_IA1_Data.Temperature,E53_IA1_Data.Humidity,E53_IA1_Data.Lux,motor_state);
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
//根據濕度自動灌溉
if((int)E53_IA1_Data.Humidity<50) //小于50自動灌溉
{
printf("自動灌溉....\n");
motor_state=1; //電機狀態更新
//電機轉
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
}
}
//接收到數據
if(ESP8266_Recv_flag)
{
//如果是下發了屬性,判斷是開鎖還是關鎖
if(ESP8266_Recv_cnt>5)
{
ESP8266_RecvBuf[ESP8266_Recv_cnt]='\0';
//使用字符串查找函數
if(strstr((char*)&ESP8266_RecvBuf[5],""machine":1"))
{
motor_state=1; //電機狀態更新
//電機轉
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_SET);
printf("開啟電機...\n");
}
else if(strstr((char*)&ESP8266_RecvBuf[5],""machine":0"))
{
//電機停
HAL_GPIO_WritePin(IA1_Motor_GPIO_Port, IA1_Motor_Pin, GPIO_PIN_RESET);
motor_state=0;
printf("關閉電機...\n");
}
for(i=0;i;i++)printf("%c",esp8266_recvbuf[i]);>;i++)>)>
5.2 mqtt.c代碼
#include "mqtt.h"
u8 *mqtt_rxbuf;
u8 *mqtt_txbuf;
u16 mqtt_rxlen;
u16 mqtt_txlen;
u8 _mqtt_txbuf[256];//發送數據緩存區
u8 _mqtt_rxbuf[256];//接收數據緩存區
typedef enum
{
//名字 值 報文流動方向 描述
M_RESERVED1 =0 , // 禁止 保留
M_CONNECT , // 客戶端到服務端 客戶端請求連接服務端
M_CONNACK , // 服務端到客戶端 連接報文確認
M_PUBLISH , // 兩個方向都允許 發布消息
M_PUBACK , // 兩個方向都允許 QoS 1消息發布收到確認
M_PUBREC , // 兩個方向都允許 發布收到(保證交付第一步)
M_PUBREL , // 兩個方向都允許 發布釋放(保證交付第二步)
M_PUBCOMP , // 兩個方向都允許 QoS 2消息發布完成(保證交互第三步)
M_SUBSCRIBE , // 客戶端到服務端 客戶端訂閱請求
M_SUBACK , // 服務端到客戶端 訂閱請求報文確認
M_UNSUBSCRIBE , // 客戶端到服務端 客戶端取消訂閱請求
M_UNSUBACK , // 服務端到客戶端 取消訂閱報文確認
M_PINGREQ , // 客戶端到服務端 心跳請求
M_PINGRESP , // 服務端到客戶端 心跳響應
M_DISCONNECT , // 客戶端到服務端 客戶端斷開連接
M_RESERVED2 , // 禁止 保留
}_typdef_mqtt_message;
//連接成功服務器回應 20 02 00 00
//客戶端主動斷開連接 e0 00
const u8 parket_connetAck[] = {0x20,0x02,0x00,0x00};
const u8 parket_disconnet[] = {0xe0,0x00};
const u8 parket_heart[] = {0xc0,0x00};
const u8 parket_heart_reply[] = {0xc0,0x00};
const u8 parket_subAck[] = {0x90,0x03};
void MQTT_Init(void)
{
//緩沖區賦值
mqtt_rxbuf = _mqtt_rxbuf;
mqtt_rxlen = sizeof(_mqtt_rxbuf);
mqtt_txbuf = _mqtt_txbuf;
mqtt_txlen = sizeof(_mqtt_txbuf);
memset(mqtt_rxbuf,0,mqtt_rxlen);
memset(mqtt_txbuf,0,mqtt_txlen);
// //無條件先主動斷開
// MQTT_Disconnect();
// HAL_Delay(100);
// MQTT_Disconnect();
// HAL_Delay(100);
}
/*
函數功能: 登錄服務器
函數返回值: 0表示成功 1表示失敗
*/
u8 MQTT_Connect(char *ClientID,char *Username,char *Password)
{
u8 i,j;
int ClientIDLen = strlen(ClientID);
int UsernameLen = strlen(Username);
int PasswordLen = strlen(Password);
int DataLen;
mqtt_txlen=0;
//可變報頭+Payload 每個字段包含兩個字節的長度標識
DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
//固定報頭
//控制報文類型
mqtt_txbuf[mqtt_txlen++] = 0x10; //MQTT Message Type CONNECT
//剩余長度(不包括固定頭部)
do
{
u8 encodedByte = DataLen % 128;
DataLen = DataLen / 128;
// if there are more data to encode, set the top bit of this byte
if ( DataLen > 0 )
encodedByte = encodedByte | 128;
mqtt_txbuf[mqtt_txlen++] = encodedByte;
}while ( DataLen > 0 );
//可變報頭
//協議名
mqtt_txbuf[mqtt_txlen++] = 0; // Protocol Name Length MSB
mqtt_txbuf[mqtt_txlen++] = 4; // Protocol Name Length LSB
mqtt_txbuf[mqtt_txlen++] = 'M'; // ASCII Code for M
mqtt_txbuf[mqtt_txlen++] = 'Q'; // ASCII Code for Q
mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T
mqtt_txbuf[mqtt_txlen++] = 'T'; // ASCII Code for T
//協議級別
mqtt_txbuf[mqtt_txlen++] = 4; // MQTT Protocol version = 4 對于 3.1.1 版協議,協議級別字段的值是 4(0x04)
//連接標志
mqtt_txbuf[mqtt_txlen++] = 0xc2; // conn flags
mqtt_txbuf[mqtt_txlen++] = 0; // Keep-alive Time Length MSB
mqtt_txbuf[mqtt_txlen++] = 100; // Keep-alive Time Length LSB 100S心跳包 保活時間
mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen);
mqtt_txlen += ClientIDLen;
if(UsernameLen > 0)
{
mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen); //username length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen); //username length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen);
mqtt_txlen += UsernameLen;
}
if(PasswordLen > 0)
{
mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen); //password length MSB
mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen); //password length LSB
memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen);
mqtt_txlen += PasswordLen;
}
memset(mqtt_rxbuf,0,mqtt_rxlen);
ESP8266_Recv_flag=0;
ESP8266_Recv_cnt=0;
MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
HAL_Delay(200);
memcpy((char *)mqtt_rxbuf,ESP8266_RecvBuf,ESP8266_Recv_cnt);
for(i=0;i;i++)printf("%#x>
5.3 設備運行效果
串口打印調試數據: 連接成功
?
?
?
六、阿里云生活物聯網平臺
官網首頁:生活物聯網平臺 - 幫助中心 - 阿里云
生活物聯網平臺是阿里云IoT針對生活領域推出的物聯網平臺,以解決家電智能化的問題。
?
生活物聯網平臺提供了設備接入能力,有公版APP可以直接開發使用;下篇文章再講解生活物聯網平臺使用示例。
完整項目源代碼下載地址(不懂可以私信問):https://download.csdn.net/download/xiaolong1126626497/19272620
審核編輯:符乾江
-
物聯網
+關注
關注
2909文章
44713瀏覽量
374276 -
STM32
+關注
關注
2270文章
10906瀏覽量
356479 -
STM32L431CB
+關注
關注
0文章
1瀏覽量
472
發布評論請先 登錄
相關推薦
評論