一、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>© 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灯的远程控制。文章来源:https://www.toymoban.com/news/detail-691007.html
别忘了点赞 关注 收藏呀!文章来源地址https://www.toymoban.com/news/detail-691007.html
到了这里,关于【STM32】基于MQTT协议实时监控项目的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!