物联网项目设计 (五) Paho mqtt 库在STM32+esp8266 硬件平台上的移植和使用第一部分,连接阿里云IOT平台

原文连接:https://blog.csdn.net/weixin_42487906/article/details/104543760

概述

本文代码链接 https://github.com/FranHawk/ConnectTOAliIOTServer.git
之前一直准备使用百度云天工作为物联网云平台,但是百度云天工平台的文档写的确实不是很好,相关API的接口也和其他方案有不一样,安全性不够好,故准备使用阿里云IOT平台。后期估计还要涉及到前后端的实现,自己搭建云服务器,才能完成数据存储和小程序开发。阿里云也提供了相关的接口,使用起来比较方便。

这几天查阅了很多的MQTT相关的资料,结果发现查到了太多底层的东西。根本没有太大的作用,浪费了很多时间。在掌握基本的MQTT的概念后,我发现只用掌握连接服务器,订阅话题,发布话题这些操作就足以满足最基本的需要。

在物联网设计(三)中,完成了连接本地服务器的功能,通过MQTT连接云服务器的步骤有所改变。

1.在使用TCP连接服务器的阶段,我们需要把连接的域名和端口改成云服务器的端口。
2.连接成功后进入透传模式
3.使用paho mqtt提供的函数连接服务器

接下来就要讲述如何一步步的完成这些操作

硬件准备

stm32+esp8266硬件设备一套

软件准备

已经注册好阿里云帐号并创建好设备,创建过程和前面百度云的创建过程类似,这里还是给出文档链接

当创建好设备后,会生成一个设备三元组,后面我们连接IOT平台使用一机一密的方式,这个设备三元组后面会经常用,记得妥善保存

在这里插入图片描述

移植paho mqtt库至STM32工程中

1.从github上下载paho mqtt嵌入式版本开源库,代码链接。

2.解压并打开

找到paho.mqtt.embedded-c-master\MQTTPacket\src的所有文件和paho.mqtt.embedded-c-master\MQTTPacket\samples里面的transport.c和transport.h两个文件
在这里插入图片描述
在这里插入图片描述

3.在自己的工程中新建一个文件夹存放这些文件,我用的工程是物联网(三)中创建的工程

在这里插入图片描述
在这里插入图片描述

4.在工程中添加这些文件

在这里插入图片描述

5.找到transport.c ,对其进行更改,首先改掉上面用的include函数,改为自己的,下面的是我根据自己的软件环境更改的头文件如下

#include "stm32f1xx_hal.h"
#include "tim.h"
#include "usart.h"
#include "esp8266.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "transport.h"

  
    
    
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

除了上面的头文件之外。这个文件自己带的include和define都被我删了

6.重点:更改transport_sendPacketBuffertransport_getdatanb函数,这两个函数就是MQTT操作单片机发送和接受数据的主要函数,在这里我们用USART来改变里面的发送数据的函数,使用中断方式发送,中断方式接收

通过这样的方式,使硬件和上层MQTT应用层代码解耦合,如果之后使用不同的硬件,其他代码不需要更改,只需要更改transport中的代码。来适应当时使用的通讯模块就可以了。

int transport_sendPacketBuffer(int sock, unsigned char* buf, int buflen)
{
USART3_RX_STA = 0;
memset(USART3_RX_BUF,0,USART3_MAX_RECV_LEN);
HAL_UART_Transmit(&huart3, buf, buflen,1000);
return buflen;

}

int transport_getdata(unsigned char buf, int count)
{
uint8_t i=10;
memcpy(buf, (const char)USART3_RX_BUF, count);

USART3_RX_STA = 0;
memset(USART3_RX_BUF,0,USART3_MAX_RECV_LEN);
return count;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

7.剩下的三个函数让他们直接变为空

int transport_getdatanb(void *sck, unsigned char* buf, int count)
{
return 0;

}
int transport_open(char* addr, int port)
{

return 0;

}

int transport_close(int sock)
{
return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

8.在main函数中加入头文件,以检验移植是否成功

在这里插入图片描述

#include "esp8266.h"
#include "MQTTPacket.h"
#include "transport.h"

 
   
   
   
   
  • 1
  • 2
  • 3

9.编译工程,没有错误,移植成功

在这里插入图片描述

连接阿里云服务器

1.根据单步调试的原则,先测试用TCP连接阿里云IOT服务器是否成功

在这里插入图片描述
根据以上的域名,更改在AT指令连接TCP服务器处的域名和端口号

#define IOT_DOMAIN_NAME "a1w0XJbXwh0.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define IOT_PORTNUM 	"1883"
  • 1
  • 2
  • 3
uint8_t esp8266_Connect_Server()
{
	uint8_t i=10;
	char *p = (char*)malloc(50);
	sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",\%s",IOT_DOMAIN_NAME,IOT_PORTNUM);
	while(esp8266_send_cmd(p,"CONNECT",1000)&&i)
	{
		u1_printf("链接服务器失败,尝试重新连接\r\n");
		i--;
	}
	free(p);
	if(i)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

下面是esp8266初始化函数的代码片段,完整代码请看物联网项目设计(三)

u1_printf("设置为关闭多路连接\r\n");
	if(esp8266_send_cmd("AT+CIPMUX=0","OK",100))
	{
		u1_printf("关闭多路连接失败,准备重启\r\n");
		return 7;
	}else u1_printf("设置关闭多路连接成功\r\n");
u1_printf("准备链接服务器\r\n");
if(esp8266_Connect_Server())
{
	u1_printf("连接服务器失败,等待重启\r\n");
	return 8;
}else u1_printf("连接服务器成功\r\n");

u1_printf("准备退出透传模式\n");
if(esp8266_quit_trans())
{
	u1_printf("退出透传模式失败,准备重启\r\n");
	return 6;
}else u1_printf("退出透传模式成功\r\n");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

通过串口助手发现成功连接
在这里插入图片描述

2.参考开源代码和文档,寻找连接方法。

这里先使用ping的方法而不是直接的订阅或发布一个MQTT话题还是考虑到步子不要跨的太大,先测试是否能连接上。
paho mqtt的github代码包中有比较简单的测试代码,我们可以借鉴
在这里插入图片描述
研究了下他的步骤,先是创建一个结构体,然后对结构体中的参数进行赋值,最后使用MQTTSerialize_connect连接,使用MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK检测是否连接成功,然后定时,不停地ping,但是这些初始化参数如何设定呢,准备连接好后仔细研究下阿里云的文档,少走弯路。文档链接

以下是阿里云文档中对链接信息的描述
在这里插入图片描述
以下是Paho开源代码中的示例

MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
	data.clientID.cstring = "me";
	data.keepAliveInterval = KEEPALIVE_INTERVAL;
	data.cleansession = 1;
	data.username.cstring = "testuser";
	data.password.cstring = "testpassword";
len = MQTTSerialize_connect(buf, buflen, &data);
rc = transport_sendPacketBuffer(mysock, buf, len);

printf("Sent MQTT connect\n");
/* wait for connack */
if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)
{
	unsigned char sessionPresent, connack_rc;

	if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)
	{
		printf("Unable to connect, return code %d\n", connack_rc);
		goto exit;
	}
}
else
	goto exit;

printf("MQTT connected\n");
start_ping_timer();

while (!toStop)
{
	while(!time_to_ping());
	len = MQTTSerialize_pingreq(buf, buflen);
	transport_sendPacketBuffer(mysock, buf, len);
	printf("Ping...");
	if (MQTTPacket_read(buf, buflen, transport_getdata) == PINGRESP){
		printf("Pong\n");
		start_ping_timer();
	}
	else {
		printf("OOPS\n");
		goto exit;
	}
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

3.尝试编写MQTT协议连接阿里云IOT服务器并ping通。

1.为了保证高度松耦合,连接MQTT服务器部分的代码我重新建立一个文件夹,并建立两个文件如下在这里插入图片描述
在这里插入图片描述

因为最开始连的是百度服务器,所以名字起成上面的样子了。。。

2.头文件中按照之前的设备三元组构建宏定义

#define  PRODUCTKEY           "a1w0XJbXwh0"                                        
#define  PRODUCTKEY_LEN       strlen(PRODUCTKEY)                                   #define  DEVICENAME			 "SmartLED_01"                                              
#define  DEVICENAME_LEN       strlen(DEVICENAME)                                   
#define  DEVICESECRE          "uwMJYOGSoAPNdZBOi8hyDXXXXXXXXXXX"                  				 
#define  DEVICESECRE_LEN      strlen(DEVICESECRE)

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

3.按照开源例程的写法,并参照阿里云的文档,就能知道如何连接云服务器,编写相关代码,每三秒ping一次阿里云的服务器。

#include "IOT_baidu.h"
#include "utils_hmac.h"

uint16_t buflen=200;
unsigned char buf[200];

char ClientID[128];
uint8_t ClientID_len;

char Username[128];
uint8_t Username_len;

char Password[128];
uint8_t Password_len;

uint8_t IOT_baidu_connect()
{
uint32_t len;

	char temp[128];
	

	
	MQTTPacket_connectData data = MQTTPacket_connectData_initializer;//

	buflen = sizeof(buf);
	memset(buf,0,buflen);

	memset(ClientID,128,0);                                               
	sprintf(ClientID,"%s|securemode=3,signmethod=hmacsha1|",DEVICENAME);  

	memset(Username,128,0);                                               
	sprintf(Username,"%s&%s",DEVICENAME,PRODUCTKEY);                      

	Username_len = strlen(Username);

	memset(temp,128,0);                                                                      
	sprintf(temp,"clientId%sdeviceName%sproductKey%s",DEVICENAME,DEVICENAME,PRODUCTKEY);       
	utils_hmac_sha1(temp,strlen(temp),Password,DEVICESECRE,DEVICESECRE_LEN); //Password的生成我使用的是网上的开源代码,如果没有的话可以使用阿里云文档中提供的密码静态生成工具                
	Password_len = strlen(Password);                                                         	
	u1_printf("ClientId:%s\r\n",ClientID);
	u1_printf("Username:%s\r\n",Username);
	u1_printf("Password:%s\r\n",Password);
	
	data.MQTTVersion = 3;
	data.clientID.cstring = ClientID;						
	data.keepAliveInterval = 120;		//保活时间,单位为秒,也就是120秒内必须和服务器通讯一次,否则判定你下线,你就要重新连接					
	data.cleansession = 1;									
	data.username.cstring = Username;						
	data.password.cstring = Password;						
	
	len = MQTTSerialize_connect(buf, buflen, &data); 		
	
	transport_sendPacketBuffer(3,buf, len);				
	unsigned char sessionPresent, connack_rc;
    do
    {
        while(MQTTPacket_read(buf, buflen, transport_getdata) != CONNACK)//¶Ô½ÓÊÕµ½µÄ±¨ÎĽøÐнâÎö
        {
            ;
        }
    }
    while(MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0);
				if(connack_rc != 0)
				{
					u1_printf("connack_rc:%uc\r\n",connack_rc);
				}
				
				u1_printf("Connect Success!\r\n");
				
				while(1)
				{
					HAL_Delay(3000);
					len = MQTTSerialize_pingreq(buf, buflen);
					transport_sendPacketBuffer(3, buf, len);
					HAL_Delay(100);
					u1_printf("Ping...\r\n");
					if (MQTTPacket_read(buf, buflen, transport_getdata) == PINGRESP){
						u1_printf("Pong\r\n");
					
					}
					else {
						u1_printf("OOPS\r\n");
					
					}
				}
	return 0;

}

uint8_t IOT_baidu_ping(void)
{
uint32_t len;
len = MQTTSerialize_pingreq(buf, buflen);
transport_sendPacketBuffer(3, buf, len);
u1_printf(“Ping…\r\n”);
if (MQTTPacket_read(buf, buflen, transport_getdata) == PINGRESP){
u1_printf(“Pong\r\n”);
return 0;
}
else {
u1_printf(“OOPS\r\n”);
return 1;
}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

4.最后在main中编写测试代码,并通过串口观察现象,每三秒ping一次

u1_printf("开始配置");
	HAL_Delay(1000);
	HAL_Delay(1000);
	HAL_Delay(1000);

/* USER CODE END 2 */

/* Infinite loop /
/ USER CODE BEGIN WHILE /
while(esp8266_Connect_IOTServer());
while(IOT_baidu_connect());
while (1)
{
/ USER CODE END WHILE */

/* USER CODE BEGIN 3 */
  IOT_baidu_ping();
  HAL_Delay(3000);

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述
连接成功并ping通,同时在阿里云端发现设备在线,试验成功

总结

1.本次实验演示了如何使用Paho MQTT协议栈连接阿里云IOT平台,使用开源协议如MQTT的便利之处在于资料多,且多平台适用。
2.下一部分内容,使用stm32+esp8266订阅与发布阿里云平台的话题,并控制板子上LED的亮灭
3.研究了下阿里云整套开发流程,完成小程序的开发恐怕还要完成服务器的建立,工作量怕是要提升了
                                

你可能感兴趣的:(MQTT,8266,STM32)