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

基于MQTT协议实时监控项目

  • 一、MQTT与源码库
  • 二、Paho MQTT 移植
    • 1.Paho源码分析
    • 2.Paho源码移植
  • 三、MQTT发布实现温湿度实时上报
    • 1.MQTT的底层源文件transport.c/h
    • 2.MQTT上层调用功能函数
    • 3.MQTT实现温湿度实时上报与LED灯远程控制
  • 四、总结


一、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协议数据报文打包、解析的相关代码。
    【STM32】基于MQTT协议实时监控项目_第1张图片

2.Paho源码移植

在我们单片机的项目路径的Core/Src文件夹下,新建一个mqtt文件夹:
【STM32】基于MQTT协议实时监控项目_第2张图片
然后,把Paho中MQTTPacket\Src文件夹中的所有.c和.h文件都拷贝到单片机的项目路径Core/Src/mqtt下,并刷新IDE:
【STM32】基于MQTT协议实时监控项目_第3张图片
然后在Core的属性中,添加mqtt的路径到include包含头文件的路径下:
【STM32】基于MQTT协议实时监控项目_第4张图片


三、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 
#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 
#include 

#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
  *
  * 

© Copyright (c) 2022 STMicroelectronics. * All rights reserved.

* * 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 #include #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****/

【STM32】基于MQTT协议实时监控项目_第5张图片

测试结果:
【STM32】基于MQTT协议实时监控项目_第6张图片
【STM32】基于MQTT协议实时监控项目_第7张图片
【STM32】基于MQTT协议实时监控项目_第8张图片

四、总结

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

别忘了点赞 关注 收藏呀!

你可能感兴趣的:(STM32,计算机网络,stm32,单片机,嵌入式硬件)