基于STM32L431设计的云端绿化管理系统(ESP8266+腾讯物联网云平台)

简介: 基于STM32L431设计的云端绿化管理系统(ESP8266+腾讯物联网云平台)

一、环境介绍

MCU: 采用意法半导体低功耗芯片 STM32L431RCT6


编译软件:  Keil5 + CubeMX


云平台: 采用腾讯物联网云平台


工程完整源代码与配套资料下载地址:https://download.csdn.net/download/xiaolong1126626497/19246016

image.png

image.png

二、功能与硬件介绍

2.1 功能介绍

这是采用STM32L431 + ES8266设计的云端绿化管理系统,可以通过ESP8266 WIFI连接腾讯云物联网平台,使用微信小程序远程进行绿化管理,比如:实时获取光照强度、温度、湿度、远程控制水泵进行浇水灌溉,在任何地方都可以给自己种的花花草草浇水,了解周边环境情况。


腾讯物联网平台支持微信小程序+WIFI一键配网,想学习如何配网的请看这里:https://blog.csdn.net/xiaolong1126626497/article/details/117339434


2.2 硬件介绍

开发板采用的是小熊开发板,包括完成绿化管理系统的所有功能都是采用小熊派开发板的配套套件完成。


小熊开发板板载了一个stlink调试器(就是STM32F103C8T6实现的),程序下载非常方便。串口1用来调试打印数据,ESP8266是接在串口LPUART1上的。

image.png

小熊派开发板本身自带的例子程序也比较丰富,自带例子里采用的云平台是华为的物联网云平台,工程比较庞大使用了LiteOS操作系统。本文里的工程是重新编写的代码,使用裸机完成项目功能,没有跑操作系统,MQTT协议和ESP8266驱动代码都是重新编写,框架、逻辑比较清晰,代码量也较少,适合初学者入门学习。


相关传感器模块型号: (采用的是小熊开发板配套的E53_IA1扩展板)


image.png

WIFI采用:ESP8266

温湿度检测传感器采用:SHT30

光照强度检测传感器采用:BH1750

电机采用:微型直流电机

image.png

image.png

三、腾讯物联网云平台

关于腾讯物联网平台的创建已经介绍很多篇了,如果之前没有使用过腾讯物联网云平台,先参考这里学习了解一下:https://blog.csdn.net/xiaolong1126626497/article/details/116902653


下面就截图介绍一下云端绿化管理系统用到的产品功能。


用到的功能属性:

image.png

小程序面板配置:

image.png

手机微信小程序运行效果:

image.png

串口打印的提示:

image.png

四、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生成的。

image.png

4.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 "6142CX41XESmartAgriculture"
#define MQTT_UserName "6142CX41XESmartAgriculture;12010126;HUA2G;1624271589"
#define MQTT_PassWord "a8aadebe9721f70e6f9e14fe56ff1d2b5cac9625fa1f96af2f0e0098597fe78b;hmacsha256"
//订阅与发布的主题
#define SET_TOPIC  "$thing/down/property/6142CX41XE/SmartAgriculture"  //订阅
#define POST_TOPIC "$thing/up/property/6142CX41XE/SmartAgriculture"  //发布
//保存温湿度、光照强度
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_cnt<MAX_RECV_CNT-1)
        {
            ESP8266_RecvBuf[ESP8266_Recv_cnt++] = (uint8_t)(at_usart.Instance->RDR & 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;i<len;i++)
    {
        while((LPUART1->ISR & 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(0, 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(0, 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,"106.55.124.154",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("光照强度:%d %%\r\n", (int)E53_IA1_Data.Lux);
            printf("湿度:%d %%\r\n",(int)E53_IA1_Data.Humidity);
            printf("温度:%d ℃\r\n", (int)E53_IA1_Data.Temperature);
            sprintf(lcd_text_str,"L: %d %%",(int)E53_IA1_Data.Lux);
            LCD_ShowString(40, 50+10+32*1, 240, 32, 32,lcd_text_str);
            sprintf(lcd_text_str,"H: %d %%",(int)E53_IA1_Data.Humidity);
            LCD_ShowString(40, 50+10+32*2, 240, 32, 32,lcd_text_str);
            sprintf(lcd_text_str,"T: %d C",(int)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\":\"report\",\"clientToken\":\"123\",\"params\":{\"temperature\":%d,\"humidity\":%d,\"machine\":%d,\"illumination\":%d}}",
            (int)E53_IA1_Data.Temperature,(int)E53_IA1_Data.Humidity,motor_state,(int)E53_IA1_Data.Lux);
            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<ESP8266_Recv_cnt;i++)printf("%c",ESP8266_RecvBuf[i]);
                    ESP8266_Recv_cnt=0;    
                }
                ESP8266_Recv_flag=0;
          }
      }
}
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInit;
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = 0;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 40;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_I2C1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.I2c1ClockSelection = RCC_I2C1CLKSOURCE_HSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
    /**Configure the main internal regulator output voltage 
    */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/**
  * @}
  */
/**
  * @}
  */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

4.2  mqtt.c : MQTT协议代码

#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<ESP8266_Recv_cnt;i++)printf("%#x ",ESP8266_RecvBuf[i]);
    //CONNECT
    if(mqtt_rxbuf[0]==parket_connetAck[0] && mqtt_rxbuf[1]==parket_connetAck[1]) //连接成功        
    {
        return 0;//连接成功
    }
  return 1;
}
/*
函数功能: MQTT订阅/取消订阅数据打包函数
函数参数:
    topic       主题   
    qos         消息等级 0:最多分发一次  1: 至少分发一次  2: 仅分发一次
    whether     订阅/取消订阅请求包 (1表示订阅,0表示取消订阅)
返回值: 0表示成功 1表示失败
*/
u8 MQTT_SubscribeTopic(char *topic,u8 qos,u8 whether)
{    
    u8 i,j;
  mqtt_txlen=0;
    int topiclen = strlen(topic);
  int DataLen = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度
  //固定报头
  //控制报文类型
    if(whether)mqtt_txbuf[mqtt_txlen++] = 0x82; //消息类型和标志订阅
    else  mqtt_txbuf[mqtt_txlen++] = 0xA2;    //取消订阅
  //剩余长度
  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;     //消息标识符 MSB
    mqtt_txbuf[mqtt_txlen++] = 0x0A;        //消息标识符 LSB
  //有效载荷
    mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);//主题长度 MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);//主题长度 LSB   
  memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen);
    mqtt_txlen += topiclen;
    if(whether)
    {
       mqtt_txbuf[mqtt_txlen++] = qos;//QoS级别
    }
    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<ESP8266_Recv_cnt;i++)printf("%#x ",ESP8266_RecvBuf[i]);
    if(mqtt_rxbuf[0]==parket_subAck[0] && mqtt_rxbuf[1]==parket_subAck[1]) //订阅成功        
    {
        return 0;//订阅成功
    }
  return 1; //失败
}
//MQTT发布数据打包函数
//topic   主题 
//message 消息
//qos     消息等级 
u8 MQTT_PublishData(char *topic, char *message, u8 qos)
{  
    int topicLength = strlen(topic);    
    int messageLength = strlen(message);     
    static u16 id=0;
  int DataLen;
  mqtt_txlen=0;
  //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
  //QOS为0时没有标识符
  //数据长度             主题名   报文标识符   有效载荷
    if(qos) DataLen = (2+topicLength) + 2 + messageLength;       
    else  DataLen = (2+topicLength) + messageLength;   
    //固定报头
  //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x30;    // MQTT Message Type PUBLISH  
  //剩余长度
  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++] = BYTE1(topicLength);//主题长度MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//主题长度LSB 
  memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//拷贝主题
    mqtt_txlen += topicLength;
  //报文标识符
    if(qos)
    {
        mqtt_txbuf[mqtt_txlen++] = BYTE1(id);
        mqtt_txbuf[mqtt_txlen++] = BYTE0(id);
        id++;
    }
  memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength);
    mqtt_txlen += messageLength;
  MQTT_SendBuf(mqtt_txbuf,mqtt_txlen);
    return mqtt_txlen;
}
void MQTT_SentHeart(void)
{
  MQTT_SendBuf((u8 *)parket_heart,sizeof(parket_heart));
}
void MQTT_Disconnect(void)
{
  MQTT_SendBuf((u8 *)parket_disconnet,sizeof(parket_disconnet));
}
void MQTT_SendBuf(u8 *buf,u16 len)
{
     AT_SendData(buf,len);
} 
相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
2月前
|
人工智能 监控 物联网
深度探索人工智能与物联网的融合:构建未来智能生态系统###
在当今这个数据驱动的时代,人工智能(AI)与物联网(IoT)的深度融合正引领着一场前所未有的技术革命。本文旨在深入剖析这一融合背后的技术原理、探讨其在不同领域的应用实例及面临的挑战与机遇,为读者描绘一幅关于未来智能生态系统的宏伟蓝图。通过技术创新的视角,我们不仅揭示了AI与IoT结合的强大潜力,也展望了它们如何共同塑造一个更加高效、可持续且互联的世界。 ###
|
3月前
|
传感器 监控 物联网
基于STM32+微波雷达设计的非接触式睡眠监控系统
本项目开发一种非接触式的睡眠监控系统,该系统利用先进的60GHz毫米波雷达技术和STM32微控制器,实现了对人体在睡眠过程中的存在感知、运动感知以及生理指标如呼吸频率、心率的实时监测。系统能够自动评估睡眠质量,并在用户睡眠周期结束时提供睡眠评分。为了确保用户能够在任何地点了解自己的睡眠状况,系统集成了Wi-Fi模块,可以将收集到的数据上传至华为云物联网平台,并通过专门设计的移动应用程序供用户远程访问。此外,系统还具备超阈值报警功能,当检测到异常的生理指标时会发出警报提醒。本地1.44寸TFT LCD显示屏用于实时显示监测到的信息,包括生理指标和环境数据。为了全面监测用户的健康状况,系统还加入了
390 0
基于STM32+微波雷达设计的非接触式睡眠监控系统
|
3月前
|
传感器 机器学习/深度学习 存储
物联网设备精细化管理系统解决方案
随着科技的进步,物联网技术作为新一代信息技术的核心部分,正在深刻改变各行业的生产和管理方式。其在资产管理、智慧城市、能源管理和智慧医疗等多个领域的广泛应用,不仅提高了运营效率,还促进了资源优化配置和精细化管理。本文详细介绍了物联网的基础概念及其在设备精细化管理系统中的具体应用方案,展示了如何通过智能感知层建设、数据处理分析平台以及精细化管理应用,实现设备的实时监控、预测性维护和能耗管理等功能,从而帮助企业提升竞争力,降低成本,并推动社会向更智能化、绿色化的方向发展。
112 2
物联网设备精细化管理系统解决方案
|
3月前
|
存储 监控 物联网
医疗物联网设备精细化管理系统解决方案
华汇数据智慧医院物联网管理系统解决方案是一种集物联网、云计算、大数据和人工智能等先进技术于一体的综合性解决方案,旨在提升医院的运营效率、医疗质量和患者满意度。
97 3
|
3月前
|
Cloud Native 持续交付 云计算
云端新纪元:探索云原生技术的奥秘在当今数字化时代,云计算已成为推动企业创新和增长的关键动力。随着云平台的不断成熟,云原生技术应运而生,以其独特的优势引领着一场新的技术革命。本文将深入探讨云原生的核心概念、主要特点以及它如何改变现代软件开发和部署的方式,为您揭开云原生这一神秘面纱。
云原生是一种构建和运行应用程序的方法,充分利用了云平台的弹性、分布式本质以及声明式基础设施。本文将解析云原生的十二要素,微服务架构的优势,以及容器化、持续集成与持续部署(CI/CD)等核心技术的实践应用。通过深入浅出的方式,让读者理解云原生不仅是一种技术,更是一种文化和方法论,它正在重塑软件开发流程,提高资源利用率和应用系统的可扩展性与容错性。
|
3月前
|
存储 机器学习/深度学习 编解码
基于STM32的车牌识别系统
基于STM32的车牌识别系统
158 0
|
3月前
|
传感器 网络协议 物联网
基于STM32的环境监测系统 (esp8267)(下)
基于STM32的环境监测系统 (esp8267)(下)
188 0
|
3月前
|
传感器 测试技术 芯片
基于STM32的环境监测系统 (esp8266)(上)
基于STM32的环境监测系统 (esp8266)(上)
584 0
|
3月前
|
SQL 缓存 Java
揭秘物联网性能优化的终极攻略!提升系统效率的七大法宝
小米在物联网项目中遇到了性能优化问题,他从数据库、集群、硬件、代码、并行处理、JVM及操作系统等多个层面分享了优化经验。包括SQL优化、分库分表、缓存使用、水平扩容、分布式调度、硬件升级、代码分析、并行处理、GC调优及操作系统参数调整等。小米强调性能优化需结合实际情况,逐步提升系统响应速度与稳定性。欢迎留言交流,共同进步。关注他的微信公众号“软件求生”,获取更多技术干货。
85 0
|
5月前
|
传感器 监控 安全
智能家居系统:物联网技术的应用与挑战
在这篇文章中,我们将深入探讨智能家居系统背后的技术原理、实际应用以及面临的主要挑战。通过分析物联网技术如何实现家居自动化,并结合具体案例,本文旨在提供对智能家居发展现状和未来趋势的全面理解。

热门文章

最新文章

相关产品

  • 物联网平台