【STM32】基于MQTT协议实时监控项目


一、MQTT与源码库

MQTT协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛,相关具体内容以及MQTT.fx软件的相关操作可见上一篇:MQTT协议与使用

MQTT是基于TCP/IP协议、与编程语言无关的标准物联网通信协议,正因为其在物联网系统中有非常广泛的应用,所以各种编程语言都有其开源实现,都可以找到。

由于我们用的单片机的Flash、内存容量有限,所以我们不能在上面跑很多其它开源的库,而应该采用适合单片机使用的MQTT库,这里选用Paho EmbeddedC库,Paho是 MOTT的官方开源库,其有很多版本,最新版Paho MQTT库项目地址: Paho MQTT,不过github访问不稳定,大家也可以搜索搜索其他资源进行下载。

二、Paho MQTT 移植

需要注意的是,这个官方的源码拿来并不能直接使用,我们需要将其针对ESP8266 WiFi模块做Paho MQTT的移植。

1.Paho源码分析

下载好Paho源码并解压缩后打开文件夹,可以看见三个主要源码文件夹:

  • MQTTClient,这里有arduino、linux、mbed等系统移植相关的c++参考代码;
  • MQTTClient-C,这里有cc3200、linux、FreeRTOS等系统移植相关的c参考代码;
  • MQTTPacket,这里面提供了MQTT协议数据报文打包、解析的相关代码。
    在这里插入图片描述

2.Paho源码移植

在我们单片机的项目路径的Core/Src文件夹下,新建一个mqtt文件夹:
在这里插入图片描述
然后,把Paho中MQTTPacket\Src文件夹中的所有.c和.h文件都拷贝到单片机的项目路径Core/Src/mqtt下,并刷新IDE:
在这里插入图片描述
然后在Core的属性中,添加mqtt的路径到include包含头文件的路径下:
在这里插入图片描述


三、MQTT发布实现温湿度实时上报

Paho MQTT库主要是提供了MQTT协议数据报文打包和报文解析的相关函数。因为不同的硬件和通信方式不一样,其底层的收发接口也不一样,这样底层的MQTT消息发送的代码和上层MQTT订阅、发布功能代码都需要用户在移植的时候自己实现。

1.MQTT的底层源文件transport.c/h

在之前基础上代码如下:
之前相关文件可见:ESP8266 WiFi模块实时上报温湿度及控制LED灯项目笔记或私信作者

/*
 * transport.h
 *
 *  Created on: 2023年2月28日
 *      Author: ASUS
 */

#ifndef SRC_MQTT_TRANSPORT_H_
#define SRC_MQTT_TRANSPORT_H_

/*使用ESP8266创建socket连接到MQTT服务器的函数*/
extern int transport_open(char * host, int port);

/*ESP8266关闭socket连接的函数*/
extern int transport_sendPacketBuffer(unsigned char* buf, int buflen);

/*使用ESP8266发送一个MQTT数据报文的函数*/
extern int transport_sendPacketBuffer(unsigned char* buf, int buflen);

/*使用ESP8266接收MQTT数据报文的函数*/
extern int transport_getdata(unsigned char* buf, int count);

/*清除ESP8266接收MQTT数据的socket buffer的函数*/
extern int transport_clearBuf(void);

#endif /* SRC_MQTT_TRANSPORT_H_ */

/*
 * transport.c
 *
 *  Created on: 2023年2月28日
 *      Author: ASUS
 */
#include <string.h>
#include "transport.h"
#include "esp8266.h"

static unsigned char			s_sock_buf[256];
static int						s_rx_bytes;

int transport_open(char * addr, int port)
{
	return esp8266_sock_connect(addr, port) ? -1 : 0 ;
}

int transport_close(void)
{
	return esp8266_sock_disconnect();
}

int transport_sendPacketBuffer(unsigned char* buf, int buflen)
{
	return esp8266_sock_send(buf, buflen);
}

int transport_getdata(unsigned char* buf, int count)
{
	int							rv = 0;

	if( !s_rx_bytes )
	{
		rv = esp8266_sock_recv(s_sock_buf, sizeof(s_sock_buf));
		if(!rv)
		{
			return 0;
		}
		s_rx_bytes = rv;
	}

	rv = count>s_rx_bytes ? s_rx_bytes : count;

	memcpy(buf, s_sock_buf, rv);
	s_rx_bytes -= rv;

	if(s_rx_bytes > 0)
	{
		memmove(s_sock_buf, &s_sock_buf[rv], s_rx_bytes);
	}

	return rv;
}

void transport_clearbuf(void)
{
	memset(s_sock_buf, 0, sizeof(s_sock_buf));
	s_rx_bytes = 0;
}

2.MQTT上层调用功能函数

core_mqtt.c/h代码如下:

/*
 * core_mqtt.h
 *
 *  Created on: 2023年2月28日
 *      Author: ASUS
 */

#ifndef SRC_MQTT_CORE_MQTT_H_
#define SRC_MQTT_CORE_MQTT_H_

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

#define MQTT_KEEP_ALIVE_TIMEOUT_SECONDS		( 60U )

enum
{
	Qos0=0,
	Qos1,
	Qos2,
};

/*MQTT连接Broker的函数*/
extern int mqtt_connect(char*host, int port, char *clentid, char *username, char *passwd);

/*MQTT断开Broker连接的函数*/
extern int mqtt_disconnect(void);

/*MQTT订阅主体函数*/
extern int mqtt_subscribe_topic(char *topic, int qos, int msgid);

/*MQTT取消主体订阅函数*/
extern int mqtt_unsubscribe_topic(char *topic, int msgid);

/*MQTT发布消息函数*/
extern int mqtt_publish(char *topic, int qos, char *payload);

/*MQTT保持连接心跳包函数*/
extern int mqtt_pingreq(void);

#endif /* SRC_MQTT_CORE_MQTT_H_ */

/*
 * core_mqtt.c
 *
 *  Created on: 2023年2月28日
 *      Author: ASUS
 */
#include <stdio.h>
#include <string.h>

#include "stm32l4xx_hal.h"
#include "core_mqtt.h"

int mqtt_connect(char *host, int port, char *clientid, char *username, char *passwd)
{
	MQTTPacket_connectData			data = MQTTPacket_connectData_initializer;
	int								rv;
	unsigned char					buf[256];
	unsigned char					sessionPresent;
	unsigned char					connack_rc;

	if( !host || port<=0 || !clientid )
	{
		printf("ERROR:Invalid input arguments\r\n");
		return -1;
	}

	if( (rv=transport_open( host, port)) < 0 )
	{
		printf( "socket connect[%s:%d] failure, rv=%d\r\n", host, port, rv);
		return rv;
	}
	printf("socket connect [ %s:%d ] ok\r\n", host,  port);

	data.clientID.cstring = clientid;
	data.keepAliveInterval = MQTT_KEEP_ALIVE_TIMEOUT_SECONDS;
	data.cleansession = 1;

	if( username && passwd )
	{
		data.username.cstring = username;
		data.password.cstring = passwd;
	}

	rv=MQTTSerialize_connect(buf, sizeof(buf), &data);

	if(rv != transport_sendPacketBuffer(buf,rv))
	{
		printf("transport_sendPacketBuffer for mqtt_connect failure, rv=%d\n", rv);
	}

	HAL_Delay(800);

	memset(buf, 0, sizeof(buf));
	rv = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
	if( CONNACK != rv )
	{
		printf( "MQTTPacket_read for MQTT CONNACK failure, rv=%d\n", rv);
		return -3;
	}

	if((rv=MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, sizeof(buf)))!= 1 || connack_rc!=0)
	{
		printf("MQTTDeserialize_connack failure, rv=%d\n", rv);
		return -4;
	}

	return 0;
}

int mqtt_disconnect(void)
{
	int								rv;
	unsigned char					buf[256];

	rv = MQTTSerialize_disconnect( buf, sizeof(buf) );
	if( rv < 0 )
	{
		printf("MQTTSerialize_disconnect failure, rv=%d\n", rv);
		return -1;
	}

	if ( rv != transport_sendPacketBuffer(buf,rv) )
	{
		printf( "transport_sendPacketBuffer for mqtt_disconnect failure, rv=%d\n", rv);
		return -2;
	}

	return 0;
}

int mqtt_subscribe_topic(char *topic, int qos, int msgid)
{
	MQTTString						topicString = MQTTString_initializer;
	unsigned short					submsgid;
	int								subcount, granted_qos;
	int								rv;
	unsigned char					buf[256];

	topicString.cstring = topic;

	rv = MQTTSerialize_subscribe(buf, sizeof(buf), 0, msgid, 1,&topicString, &qos);
	if( rv < 0 )
	{
		printf("MQTTSerialize_subscribe failure, rv=%d\n", rv);
		return -1;
	}

	if ( rv != transport_sendPacketBuffer(buf,rv) )
	{
		printf( "transport_sendPacketBuffer for mqtt_subscribe_topic failure, rv=%d\n", rv);
		return -2;
	}

	HAL_Delay(800);

	memset(buf, 0, sizeof(buf));
	rv = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
	if(SUBACK != rv)
	{
		printf("MQTTPacket_read for MQTT SUBACK failure, rv=%d\n", rv);
		return -3;
	}

	rv = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, sizeof(buf));
	if( !rv || submsgid!=msgid || granted_qos==0x80)
	{
		printf( "MQTTDeserialize_suback failure, rv=%d\n", rv);
		return -4;
	}

	return 0;
}

int mqtt__unsubscribe_topic(char *topic, int msgid)
{
		MQTTString						topicString = MQTTString_initializer;
		unsigned short					submsgid;
		int								rv;
		unsigned char					buf[256];

		topicString.cstring = topic;
		rv = MQTTSerialize_unsubscribe(buf, sizeof(buf), 0, msgid, 1, &topicString);
		if( rv < 0 )
		{
			printf("MQTTSerialize_subscribe failure,rv=%d\n", rv);
			return -1;
		}

		if ( rv != transport_sendPacketBuffer(buf, rv) )
		{
			printf("transport_sendPacketBuffer for mqtt_unsubscribe_topic failure, rv=%d\n", rv);
			return -2;
		}

		HAL_Delay(800);

		memset(buf, 0, sizeof(buf));
		rv = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
		if( UNSUBACK != rv )
		{
			printf("MQTTPacket_read for MQTT UNSUBACK failure, rv=%d\n", rv);
			return -3;
		}

		rv = MQTTDeserialize_unsuback(&submsgid, buf, sizeof(buf));
		if( !rv || submsgid!=msgid )
		{
			printf("MQTTDeserialize_unsuback failure,rv=%d\n", rv);
			return -4;
		}

		return 0;
}

int mqtt_publish(char *topic, int qos, char *payload)
{
		MQTTString						topicString = MQTTString_initializer;
		int								rv;
		unsigned char					buf[256];
		unsigned char					dup = 0;
		unsigned char					retained = 0;
		unsigned short					packetid = 0;

		topicString.cstring = topic;

		rv =MQTTSerialize_publish(buf, sizeof(buf), dup, qos, retained, packetid, topicString, (unsigned char*)payload, strlen(payload));
		if( rv < 0 )
		{
			printf( "MQTTSerialize_publish failure, rv=%d \n", rv);
			return -1;
		}

		if ( rv != transport_sendPacketBuffer(buf, rv) )
		{
			printf("transport_sendPacketBuffer for MQTTSerialize_publish failure,rv=%d \n", rv);
			return -2;
		}

		HAL_Delay(800);

		memset(buf, 0, sizeof(buf));
		rv = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
		if( PUBLISH!=rv && -1!=rv )
		{
			printf("MQTTPacket_read for MQTT PUBLISH failure,rv=%d\n", rv);
			return -3;
		}

		return 0;
}

int mqtt_pingreq(void)
{
	int								rv;
	unsigned char					buf[256];

	rv = MQTTSerialize_pingreq(buf, sizeof(buf));
	if( rv < 0 )
	{
		printf("MQTTSerialize_pingreq failure, rv=%d\n", rv);
		return -1;
	}

	if (rv != transport_sendPacketBuffer(buf, rv) )
	{
		printf("transport_sendPacketBuffer for MQTTSerialize_pingreq failure,rv=%d\n", rv);
		return -2;
	}

	HAL_Delay(800);

	memset(buf, 0, sizeof(buf));
	rv = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
	if(PINGRESP != rv)
	{
		printf("MQTTPacket_read for MQTT PINGRESP failure,rv=%d\n", rv);
		return -3;
	}

	return 0;
}

3.MQTT实现温湿度实时上报与LED灯远程控制

main.c代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "dht11.h"
#include "sht30.h"
#include "core_json.h"
#include "oled.h"
#include "esp8266.h"
#include "core_mqtt.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
#define FLAG_WIFI_CONNECTED		(1<<0)	/* WiFi连接路由器标志位*/
#define FLAG_SOCK_CONNECTED 	(1<<1)  /* Socket连接服务器标志位*/

#define DEF_ROUTER_SSID			"***"//填入自己WiFi的SSID
#define	DEF_ROUTER_PWD			"***"//填入密码

#define MQTT_BROKER_HOSTNAME	"***"		//设置对应的MQTT Broker服务器
#define MQTT_BROKER_PORT		****				//设置MQTT Broker监听发端口

//Broker没有用户名和密码则不用设置
#define MQTT_BROKER_USERNAME	"***"//填入用户名
#define MQTT_BROKER_PASSWORD	"***"//填入密码

#define	MQTT_CLIENT_ID			"BearKE-dengyonghao" 		//设置客户端ID
#define	MQTT_PUB_TOPIC			"$Sys/studio/Uplink/"MQTT_CLIENT_ID
#define	MQTT_SUB_TOPIC			"$Sys/studio/Downlink/"MQTT_CLIENT_ID

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static int report_tempRH_json(void);
static int parser_led_json(char *json_string, int bytes);
//static void proc_uart1_recv(void);
void	mqtt_subscribe_proc(void);
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

//  uint32_t		lux,noisy;
//  uint32_t		start = 0;
//  uint32_t		light_status = 0;
//  float temperature, humidity;

	uint32_t		last_time = 0; /*每隔3s上报一次,上一次上报的时间*/
//	unsigned char	buf[256]; /*WiFi模块socket接收的buffer MQTT中没有用到*/
	int				rv;

	char			ipaddr[16];
	char			gateway[16];
	unsigned char	wifi_flag = 0;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM6_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();
  MX_USART2_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */

  //sysled_hearbeat();
  //beep_start(3,300);
  printf("Start BearKE1 5G NB_IoT Board Example Program v1.0\r\n");
  printf("Welcome Mr.deng!\r\n");

  OLED_Init();
  OLED_ShowBanner(TIME_1S*2);

  esp8266_module_init();

  while(1)
  {
	  /*wiFi没有连接上无线路由器的话,开始连接无线路由器并ping测试*/
	  if(!(wifi_flag&FLAG_WIFI_CONNECTED))
	  {
		  if(esp8266_join_network(DEF_ROUTER_SSID, DEF_ROUTER_PWD))
		  {
			  esp8266_module_init();
			  HAL_Delay(2000);
			  continue;
		  }
		  if(esp8266_get_ipaddr(ipaddr, gateway, sizeof(ipaddr)))
		  {
			  HAL_Delay(1000);
			  continue;
		  }
		  if(esp8266_ping_test(gateway))
		  {
			  HAL_Delay(1000);
			  continue;
		  }
		  wifi_flag |= FLAG_WIFI_CONNECTED; /* set wifi connected flag */
	  }

	  /*网络socket没有连接上Socket服务器的话就开始连接Socket服务器 */
//	  if(!(wifi_flag&FLAG_SOCK_CONNECTED))
//	  {
//		  if(esp8266_sock_connect("192.168.0.120", 12345))
//		  {
//			  HAL_Delay(1000);
//			  continue;
//		  }
//		  wifi_flag |= FLAG_SOCK_CONNECTED; /* set wifi connected flag */
//	  }

	  /*这里使用MQTT Broker服务器所以判断没有连接的时候就开始连接对应MQTT Broker服务器*/
	  if(!(wifi_flag&FLAG_SOCK_CONNECTED))
	  {
		  rv = mqtt_connect(MQTT_BROKER_HOSTNAME, MQTT_BROKER_PORT, MQTT_CLIENT_ID, MQTT_BROKER_USERNAME, MQTT_BROKER_PASSWORD);
		  if( rv )
		  {
			  HAL_Delay(1000);
			  continue;
		  }

		  /* 连上MQTT Broker后订阅下发三色Led控制命令的主题*/
		  mqtt_subscribe_topic(MQTT_SUB_TOPIC, Qos0, 1);

		  wifi_flag |= FLAG_SOCK_CONNECTED; /* set wifi connected flag */
	  }

	  /*处理MQTT订阅收到的消息*/
	  mqtt_subscribe_proc();

	  /*接收并且打印Socket服务器发送过来的数据*/
//	  rv = esp8266_sock_recv(buf, sizeof(buf));
//	  printf(("%d\n"), rv);
//	  if( (rv=esp8266_sock_recv(buf, sizeof(buf))) > 0 )
//	  {
//		  parser_led_json((char *)buf, rv);
//		  printf("ESP8266 socket receive %d bytes data: %s\n", rv, buf);
//	  }

	  /*定时发数据到Socket服务器*/
//	  if(time_after(HAL_GetTick(), last_time+3000))
//	  {
//		  rv = report_tempRH_json();
//		  if( rv == 0 )
//		  {
//			  printf("ESP8266 socket send message ok\n");
//		  }
//		  else
//		  {
//			  printf("ESP8266 socket send message failure, rv=%d\n", rv);
//			  wifi_flag &= ~FLAG_SOCK_CONNECTED;/* clear socket connected flag */
//
//			  if(esp8266_ping_test(gateway))
//			  {
//				  wifi_flag &= ~FLAG_WIFI_CONNECTED;/* clear wifi connected flag */
//			  }
//		  }
//
//		  last_time = HAL_GetTick();/*update last report time */
//	  }

	  /*定时发布采样温度值到MQTT Broker,修改为30s上报一次*/
	  if(time_after(HAL_GetTick(), last_time+30000))
	  {
		  rv = report_tempRH_json();
		  if( rv == 0 )
		  {
			  printf("ESP8266 MQTT publish message ok\n");
		  }
		  else
		  {
			  printf("ESP8266 MQTT publish message failure, rv=%d\n", rv);
			  wifi_flag &= ~FLAG_SOCK_CONNECTED;/* clear socket connected flag */

			  if(esp8266_ping_test(gateway))
			  {
				  wifi_flag &= ~FLAG_WIFI_CONNECTED;/* clear wifi connected flag */
			  }
		  }

		  last_time = HAL_GetTick();/*update last report time */
	  }

//	  uart_forward();//后面使用无线通讯时只需要用Socket通信,不在需要此转发程序,如果没有注释掉会报错,并不会执行PC发的JOSN指令
#if 0
	  /*sht30*/
	  report_tempRH_json();
	  HAL_Delay(3000);

	  /*json上报*/
	  proc_uart1_recv();
	  if( report_tempRH_json() < 0 )
	  {
		  printf("ERROR: UART report temperature and relative humidity failure\r\n");
	  }
	  HAL_Delay(3000);

//	  if( DHT11_SampleData(&temperature, &humidity) < 0 )
//	  {
//		  printf("ERROR: DHT11 Sample Data failure\r\n");
//	  }
//	  else
//	  {
//		  printf("DHT11 Sample Temperature: %.3f Relative Humidity: %.3f\r\n", temperature, humidity);
//	  }
//
//
//	  HAL_Delay(1000);

//Tag:灯光
//	if( OFF == light_status )
//	{
//		adc_sample_lux_noisy(&lux, &noisy);
//		printf("Lux[%lu] Noisy[%lu]\r\n", lux, noisy);
//		if( lux<400 && noisy>800 )
//		{
//			printf("Turn Light on\r\n");
//			turn_relay(Relay2,ON);
//			turn_led(GreenLed,ON);//还得写turn_Led()
//			light_status = ON;
//
//			start = HAL_GetTick();
//		}
			HAL_Delay(5000);
//	}
//
//	else
//	{
//		if( time_after(HAL_GetTick(), start+15000) )
//		{
//			printf("Turn Light off\r\n");
//			turn_relay(Relay2,OFF);
//			turn_led(GreenLed,OFF);
//			turn_led(RedLed,ON);
//
//			HAL_Delay(1000);
//			turn_led(RedLed,OFF);
//
//			light_status = OFF;
//		}
//
//	}
//
//	HAL_Delay(10);
#endif
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 20;
  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();
  }
  /** Initializes the CPU, AHB and APB buses 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();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_USART2
                              |RCC_PERIPHCLK_ADC;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
  PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_PLLSAI1;
  PeriphClkInit.PLLSAI1.PLLSAI1Source = RCC_PLLSOURCE_HSE;
  PeriphClkInit.PLLSAI1.PLLSAI1M = 1;
  PeriphClkInit.PLLSAI1.PLLSAI1N = 9;
  PeriphClkInit.PLLSAI1.PLLSAI1P = RCC_PLLP_DIV7;
  PeriphClkInit.PLLSAI1.PLLSAI1Q = RCC_PLLQ_DIV2;
  PeriphClkInit.PLLSAI1.PLLSAI1R = RCC_PLLR_DIV6;
  PeriphClkInit.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_ADC1CLK;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
/*处理单片机通过ESP8266和MQTT订阅收到的消息*/
void mqtt_subscribe_proc(void)
{
	unsigned char					buf[256];
	int								packet_type;
	MQTTString						topicName;
	unsigned char					dup;
	int								qos;
	unsigned char					retained;
	unsigned short					msgid;
	unsigned char					*payload = NULL;;
	int								payloadlen = 0;
	int								rv;

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

	packet_type = MQTTPacket_read(buf, sizeof(buf), transport_getdata);
	if( packet_type < 0 )
	{
		return ;
	}

	switch( packet_type )
	{
		case 0:
		break;

		case PUBLISH:
		{
			rv = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &topicName, &payload, &payloadlen, buf, sizeof(buf));
			if( rv==1 )
			{
				printf("MQTT Payload: %s\n", payload);
				parser_led_json((char *)payload, payloadlen);
			}
			else
			{
				printf("ERROR: MQTTDeserialize_publish() failure, rv=%d\r\n", rv);
			}
			break;
		}
		case CONNACK:
		case PUBACK:
		case SUBACK:
		case UNSUBACK:
		case PUBREC:
		case PUBREL:
		case PUBCOMP:
			break;
	}
}

int parser_led_json(char *json_string, int bytes)
{
	JSONStatus_t result;
	char save;
	char *value;
	size_t valen;
	int i;

	printf("DBUG: Start parser JSON string: %s\r\n", json_string);
	result = JSON_Validate(json_string, bytes);
	/* JSON document is valid so far but incomplete */
	if( JSONPartial == result )
	{
		printf("WARN: JSON document is valid so far but incomplete!\r\n");
		return 0;
	}

	/* JSON document is not valid JSON */
	if( JSONSuccess != result )
	{
		printf("ERROR: JSON document is not valid JSON!\r\n");
		return -1;
	}
	/* Parser and set LED status */
	for(i=0; i<LedMax; i++)
	{
		result = JSON_Search( json_string, bytes, leds[i].name, strlen(leds[i].name), &value, &valen);
		if( JSONSuccess == result )
		{
			save = value[valen];
			value[valen] = '\0';

			if( !strncasecmp(value, "on", 2) )
			{
				printf("DBUG: turn %s on\r\n", leds[i].name);
				turn_led(i, ON);
			}
			else if( !strncasecmp(value, "off", 3) )
			{
				printf("DBUG: turn %s off\r\n", leds[i].name);
				turn_led(i, OFF);
			}

			value[valen] = save;
		}
	}
	return 1;
}

//void proc_uart1_recv(void)
//{
//	if( g_uart1_bytes > 0 )
//	{
//		HAL_Delay(200);
//		if( 0 != parser_led_json(g_uart1_rxbuf, g_uart1_bytes) )
//		{
//			clear_uart1_rxbuf();
//		}
//	}
//}

/*json上报*/
//int report_tempRH_json(void)
//{
//	char buf[128];
//	float temperature, humidity;
//
//
//	if ( DHT11_SampleData(&temperature, &humidity) < 0 )
//	{
//		printf("ERROR: DHT11 Sample data failure\n");
//		return -1;
//	}
//
//
//	memset(buf, 0, sizeof(buf));
//	snprintf(buf, sizeof(buf), "{\"Temperature\":\"%.2f\", \"Humidity\":\"%.2f\"}", temperature, humidity);
//
//	HAL_UART_Transmit(&huart1 , (uint8_t *)buf, strlen(buf), 0xFFFF);
//
//	return 0;
//}

/*sht30采样*/
int report_tempRH_json(void)
{
	char buf[128];
	float temperature, humidity;
	uint32_t temp, humd;
	int	rv;

	if ( SHT30_SampleData(&temperature, &humidity) < 0 )
	{
		printf("ERROR: SHT30 Sample data failure\n");
		return -1;
	}


	memset(buf, 0, sizeof(buf));
	snprintf(buf, sizeof(buf), "{\"Temperature\":\"%.2f\", \"Humidity\":\"%.2f\"}", temperature, humidity);

	temp = (int)(temperature*100);
	humd = (int)(humidity*100);
	OLED_ShowTempHumdity(temp, humd, TIME_1S*2);

	rv = mqtt_publish(MQTT_PUB_TOPIC, Qos0, buf);
	printf("MQTT publish topic[%s] with msg '%s' %s, rv=%d\r\n", MQTT_PUB_TOPIC, buf, rv ? "failure":"ok", rv);

	return rv;

	/*esp8266测试*/
//	rv = esp8266_sock_send((uint8_t *)buf, strlen(buf));
//	HAL_UART_Transmit(&huart1 , (uint8_t *)buf, strlen(buf), 0xFFFF);
//	return rv>0 ? 0 : -2;
}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  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,
     ex: 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****/

在这里插入图片描述

测试结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、总结

本文是基于MQTT协议的实时监控项目,通过MQTT协议结合无线通讯模块实现了对温湿度的无线监控和LED灯的远程控制。

别忘了点赞 关注 收藏呀!

  • 11
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: STM32 HAL MQTT是针对STM32系列微控制器的一种HAL库(Hardware Abstraction Layer hardware,硬件抽象层),它为MCU和MQTT协议之间的通信提供了一个简化的接口和函数。 MQTT(Message Queuing Telemetry Transport)是一种轻量级的、基于发布/订阅模式的消息通信协议。它广泛应用于物联网领域,特别适合在网络带宽有限的情况下进行消息传递。 使用STM32 HAL MQTT,我们可以方便地在STM32微控制器上实现MQTT协议的通信功能。这个库提供了一系列API,包括连接到MQTT代理服务器、发布消息、订阅主题等。通过这些API,我们可以简化开发过程,快速实现STM32与其他MQTT设备的通信。 STM32 HAL MQTT库内部是基于STM32 HAL库开发的,因此可以充分利用STM32 HAL库的特性,如GPIO、UART、SPI、I2C等外设的使用。通过HAL库的抽象层,我们可以屏蔽底层硬件的差异,提高了代码的可移植性和可维护性。 总而言之,STM32 HAL MQTT库使得在STM32微控制器上实现MQTT协议变得更加简单和高效。它为STM32系列提供了一个集成的解决方案,有助于开发者快速构建物联网应用程序。 ### 回答2: STM32 HAL MQTT是一种用于STM32微控制器的MQTT协议的HAL库。MQTT(Message Queue Telemetry Transport)是一种轻量级的发布/订阅消息传输协议,通常用于物联网设备之间的通信。 STM32 HAL MQTT库为开发人员提供了使用MQTT协议进行通信的简化工具。它通过封装底层的网络通信细节,使得开发人员能够更便捷地实现基于MQTT的通信功能。HAL(Hardware Abstraction Layer)层则提供了一组API,用于在各种STM32微控制器上进行底层硬件操作。 使用STM32 HAL MQTT库,开发人员可以轻松地实现MQTT客户端功能。它提供了连接到MQTT代理、发布和订阅主题、接收和处理消息等常见的MQTT操作。开发人员只需使用库提供的API,而不需要关注底层的网络通信细节。 使用STM32 HAL MQTT进行开发,可以加速物联网应用的开发过程。开发人员可以利用STM32微控制器的强大功能,结合MQTT协议的优势,快速构建出高效可靠的物联网设备。无论是在家庭自动化、工业控制、智能城市等领域,都可以借助STM32 HAL MQTT来实现灵活、可扩展的物联网解决方案。 总而言之,STM32 HAL MQTT是一种方便实用的库,可以帮助开发人员快速实现基于MQTT协议的通信功能。它简化了底层网络通信的复杂性,提供了一组易于使用的API,使得开发人员能够快速构建出高效可靠的物联网应用。 ### 回答3: STM32 HAL MQTT是一种基于STM32单片机和HAL库的MQTT协议的实现。MQTT是一种轻量级的消息传输协议,特点是简单、开销小和易于实现,适用于物联网设备之间的通信。 STM32是意法半导体公司推出的一系列32位低功耗微控制器,具有强大的性能和丰富的外设资源。HAL库是意法半导体公司提供的一套硬件抽象层库,简化了STM32的底层驱动程序编程。 STM32 HAL MQTT提供了一系列的API函数,用于在STM32上实现MQTT协议通信。它通过封装MQTT协议的相关函数,提供了一个简单易用的编程接口。 使用STM32 HAL MQTT可以实现以下功能: 1. 连接到MQTT服务器:通过提供服务器的IP地址和端口号,可以与服务器建立连接。 2. 发布消息:可以通过指定主题和消息内容,将消息发布到MQTT服务器上。 3. 订阅主题:可以订阅感兴趣的主题,一旦有相关消息发布,就会收到相应的消息。 4. 断开连接:可以断开与MQTT服务器的连接。 STM32 HAL MQTT的实现可以让我们在STM32上轻松地实现与其他设备之间的通信。无论是在物联网设备中实现数据传输,还是实现远程控制和监控STM32 HAL MQTT都是一种很强大的工具。它简化了开发者的任务,提供了高效、可靠的通信方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓永豪

打赏一下,好运来敲门!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值