0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32L431设计的云端绿化管理系统

DS小龙哥-嵌入式威廉希尔官方网站 来源:DS小龙哥-嵌入式威廉希尔官方网站 作者:DS小龙哥-嵌入式技 2022-02-28 13:51 次阅读

一、环境介绍

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

编译软件:Keil5 +CubeMX

云平台:采用阿里云物联网云平台

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

二、功能与硬件介绍

2.1 功能介绍

前面的一篇文章是同样的环境,云平台采用的是腾讯物联网云平台(基于STM32L431设计的云端绿化管理系统(ESP8266+腾讯物联网云平台)_DS小龙哥的专栏-CSDN博客_stm32l431)

这篇文章将云平台换成了阿里云物联网平台,其他硬件功能都是一样的。

再次介绍一下功能:

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

2.2 硬件介绍

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

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

WIFI采用:ESP8266

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

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

电机采用:微型直流电机

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

三、阿里云物联网云平台

关于阿里云物联网平台的创建与使用之前也介绍过一篇,只不过MCU采用的是STM32F103C8T6,这篇文章MCU采用的是STM32L431RCT6,属于低功耗系列,更加适合物联网领域;如果之前没有使用过阿里云物联网云平台,先参考这里学习了解一下:STM32+ESP8266+MQTT协议连接阿里云物联网平台_DS小龙哥的专栏-CSDN博客_stm32连接阿里云

3.1 在阿里云物联网平台创建产品

官网地址:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

创建产品:

配置产品模型参数页面最后加密方式这些选择默认

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

添加设备:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

设备添加之后,可以一键将设备证书复制下来保存到记事本,方便后面使用;不复制也没关系,后面也可以设备信息中查看的:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

{
  "ProductKey": "a1ukQj2EnEJ",
  "DeviceName": "GreeningManagement",
  "DeviceSecret": "a5268d71d363f1bd68e708c9097fa3d2"
}
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

设备添加完成:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

在设备信息的页面也可以查看设备证书:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

添加功能属性字段:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

根据自己产品交互使用的数据类型进行定义:(绿化管理系统使用了温度、湿度、电机、光照强度一共4个数据字段。其中电机是读写类型,其他都是只读类型)

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

自定义功能属性添加完毕之后就发布上线:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

查看物模型数据格式:后面通过MQTT协议向服务器上报数据就是这个格式

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

可以选择导出模型文件,导出是一个json格式文件,方便设备端开发参考。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

3.2 通过IoT Studio创建web可视化界面

地址:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

之前旧版本的IoT Studio 选项是在产品页面里,现在移到控制台首页了。

新建项目:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

新建web应用:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

设计WEB页面之前 先关联产品和设备:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

选择对应的产品进行关联:

选择对应的设备进行关联:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

关联成功:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

下面继续编辑web页面:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

可以更改页面名称:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

添加组件,设计页面: 阿里云的web页面控件非常丰富,可以根据自己需求设计好看的页面。

接下来就要给每个控件配置数据源:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

调整仪表盘的属性:刻度字号

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

配置完毕:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

有域名的可以绑定到域名:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

这里可以预览页面:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

四、登录阿里云平台测试

4.1 MQTT协议登录的域名与端口

关于MQTT协议登录所需要的参数官方说明文档:使用MQTT.fx接入物联网平台 - 阿里云物联网平台 - 阿里云

MQTT登录域名的格式:

${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

其中:
${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
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

端口号是: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|
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

4.2.2MQTT_UserName

固定格式:${DeviceName}&${ProductKey}
参数解释:
${DeviceName} 是设备的名称(就是创建设备的时候复制出来3个参数里的设备名称)
${ProductKey} 是设备的ProductKey(就是创建设备的时候复制出来3个参数里的ProductKey)

示例:

当前我的绿化管理系统设备名称是:GreeningManagement ,我的ProductKey是:a1ukQj2EnEJ

那么我的UserName就是:

GreeningManagement&a1ukQj2EnEJ
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

4.2.3MQTT_PassWord

下载密码生成小工具:使用MQTT.fx接入物联网平台 - 阿里云物联网平台 - 阿里云

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

下载工具,运行:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

根据说明填充参数:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

说明:productKey、deviceName、deviceSecret:是设备证书信息,可在控制台设备详情页查看。clientID在4.2.1小节里已经说过了。时间戳可以省略不填。

点击Generate生成密码。

经过小工具生成后的密码是:

9E580B36EE7E001980AF61EA09EAF85F0211C146
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

4.3 使用MQTT客户端工具登录阿里云服务器

MQTT客户端工具下载地址:QT应用编程: 编写MQTT客户端登录OnetNet服务器完成主题订阅与发布_DS小龙哥的专栏-CSDN博客_onenet topic订阅与发布

根据前面获取的参数填入,登录测试: (为了保证不会断开连接,可以勾选MQTT客户端右下角的心跳包选项,保活)

如果登录成功,在阿里云控制台页面上可以看到设备已经在线:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

如果设备能成功上线,那么就说明MQTT所需要的参数都已经填正确了,接下来就可以正常订阅、发布主题了。

4.4 主题订阅、发布测试

属性上报主题与属性设置主题格式:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

发布主题:

/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客户端订阅主题、上报属性数据:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

把相关的参数填正确,然后登陆,订阅、发布测试:

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

阿里云物联网平台云端收到的数据:

地址:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

点击页面上的的按钮,MQTT客户端可以收到下发的消息(要先订阅才能收到消息):

poYBAGDYdXCAWkKMAAAAK8RNs4s030.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秒检测一次温湿度、光照强度、电机状态主动上报给阿里云平台;在设备端按下按键(interwetten与威廉的赔率体系 现场实体开关)也可以控制水泵浇水或者关闭,这些状态都会实时上报给云平台。

程序的模板是使用CubeMX生成的。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

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++)>)>
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

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>
poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

5.3 设备运行效果

串口打印调试数据: 连接成功

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

六、阿里云生活物联网平台

官网首页:生活物联网平台 - 帮助中心 - 阿里云

生活物联网平台是阿里云IoT针对生活领域推出的物联网平台,以解决家电智能化的问题。

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

生活物联网平台提供了设备接入能力,有公版APP可以直接开发使用;下篇文章再讲解生活物联网平台使用示例。

完整项目源代码下载地址(不懂可以私信问):https://download.csdn.net/download/xiaolong1126626497/19272620

审核编辑:符乾江

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 物联网
    +关注

    关注

    2909

    文章

    44616

    浏览量

    373158
  • STM32
    +关注

    关注

    2270

    文章

    10900

    浏览量

    355889
  • STM32L431CB
    +关注

    关注

    0

    文章

    1

    浏览量

    470
收藏 人收藏

    评论

    相关推荐

    绿化智能灌溉控制系统

    绿化智能灌溉系统作为现代园艺与农业威廉希尔官方网站 的融合典范,正逐步改变着植物养护的传统认知。提高水资源利用效率,通过智能化管理,对植物生长环境的精准调控,促进生态环境的可持续发展。 系统概述
    的头像 发表于 10-30 16:38 142次阅读

    STM32L431RCT6关机模式使用Wakeup唤醒遇到的疑问求解

    根据STM32L431手册,“具有从待机/关机唤醒能力的I/O为:PA0,PC13,PE6,PA2,PC5。” L431没有PE端口,那么就有PA0,PC13,PA2,PC5,想把这四个脚都配置成
    发表于 07-03 07:11

    STM32L431在下载程序时模拟电压VDDA可不可以不上电?

    STM32L431在下载程序时模拟电压VDDA可不可以不上电?
    发表于 04-17 06:45

    请问STM32L431 STOP2模式DEBUG如何才能好用?

    STM32L431 STOP2模式 DEBUG如何才能好用?跪求帮助谢谢!! STM32L431 进入STOP2模式,已经开启HAL_DBGMCU_EnableDBGStopMode(); 并且使
    发表于 04-15 08:15

    STM32L431低功耗进入异常的原因?

    各位大佬好,小弟在使用STM32L431单片机的时候遇到一个奇怪的问题,我用的是HAL库,当我下载完程序后如果不完全断电,单片机进不了低功耗,即使通过硬件复位现象也是一样,但是只要我断开电源重新上电
    发表于 04-09 07:03

    STM32L431反向初始化TIM导致FLASH-&gt;SR寄存器的PGSERR位置1了,擦除失败怎么解决?

    项目要求使用STM32L431内部FLASH存储一些调电保存参数,调试发现第一次将参数写入内部FLASH没有问题,当时当我再次写入时,报错,写入不成功,我调试发现在我写入之前FLASH-&
    发表于 04-09 06:33

    STM32L431出现LSE CSS后RTC的ALARM无法进入中断是怎么回事啊?

    STM32L431的RTC配置使用LSE时钟,配置ALARMA中断,可以正常进入中断,但是出现LSE CSS后重新配置RTC使用LSI做为系统时钟,但配置后RTC的ALARMA无法进入中断,这是怎么回事啊?
    发表于 04-08 06:58

    STM32L431x用usart1打印会乱码的原因?

    STM32L431x用usart1打印会乱码的原因?
    发表于 04-08 06:12

    STM32L431RCT6从用户代码区跳转使用内置system memory bootloader无效怎么解决?

    STM32L431RCT6 系统BootLoader地址也是 0x1FFF0000;也不是双BANK芯片。麻烦是否有接触过个芯片 从用户代码区直接跳转到内置BOOTLOADER的 成功过的 帮忙看看,谢谢
    发表于 03-26 07:54

    STM32L431 ADC to DAC时间久了时钟不同步是哪里的问题?

    我在用STM32L431做一个音频相关的项目。 我是用Timer6 设置32Khz ADC 采样,然后把采样点降采样到4Khz后,然后输出到DAC同步输出。DAC用Timer7设置 4Khz
    发表于 03-26 06:32

    STM32L431 RTC时间混乱问题如何解决?

    我现在在用STM32L431做门锁,5号电池供电(有纽扣电池),五百台门锁生产时写入读出正常(2022年),从工厂运回公司,抽检发现某台门锁的RTC时间混乱了,变成了2073年,断电重启后还是
    发表于 03-22 07:41

    STM32L431RCT6进入STOP模式后,ADC注入通道不再触发是为什么?

    STM32L431RCT6 ADC注入通道是通过定时器触发的,调试发现定时器正常触发,但是不会触发注入通道了
    发表于 03-15 06:32

    STM32L431主频80MHZ,DAC输出2V左右,一直开着ADC或者一直开着DAC谁更耗电?

    STM32L431主频80MHZ,DAC输出2V左右。
    发表于 03-11 07:25

    STM32L431在进行ADC_DMA传输后,状态位一直处于忙的状态是怎么回事?

    STM32L431在进行ADC_DMA传输后,状态位一直处于忙,debug发现并没有进入ADC中断(已开启中断)
    发表于 03-11 06:37

    如何用我的cy8cmbr3110或3102 capsense控制stm32

    我在想怎么用 stm32l431 控制这个 cy8cmbre3110 或 3102,我找到了带有 arduino wire.h 的代码 库可以用 i2c 协议控制它但我不知道如何用我的 cy8cmbr3110 或 3102 capsense 控制 stm32
    发表于 01-25 08:17