通过mqtt 发布温湿度

article/2025/6/19 6:01:15

参考 用HAL库改写江科大的stm32入门例子-补充DHT11_江科大stm32安装hal库-CSDN博客

老夫上课的时候 ,这部份讲的比较多 ,出发点是 安利 “单总线”的具体使用。

这里无非是引入dht11 库,

使用前初始化 

然后通话dht11库的方法 读取数据 ,通过mqtt发布。

不多解释:

见代码:

#include "system.h"
#include "SysTick.h"
#include "led.h"         // 添加LED函数声明头文件
#include "usart.h"
#include "wifi_config.h"
#include "wifi_function.h"
#include <string.h>
#include "cJSON.h"
#include "dht11.h"// 声明外部变量
extern struct STRUCT_USARTx_Fram strEsp8266_Fram_Record;// 函数声明
void ProcessWiFiData(uint8_t *data, uint16_t length);
void HandleMQTTMessage(const char *topic, const char *message, const char *message_le);// 全局变量
char topic_id[20] = "topic911";
char sub_topic_id[20] = "topic108";
uint8_t wifi_rx_buffer[RX_BUF_MAX_LEN]; // 用于暂存接收数据的缓冲区
//delcare global variable for if opening and closing read data
bool read_data_flag = true; // 用于控制是否读取数据
// ========== 设备处理结构体定义 ==========
typedef enum {DEVICE_LED,DEVICE_MOTOR,DEVICE_UNKNOWN
} DeviceType;typedef struct {const char *device_name;        // 设备名称(JSON键名)DeviceType device_type;         // 设备类型枚举void (*handler)(const char *state); // 处理函数指针
} DeviceHandler;void data_pros()	//数据处理函数
{u8 temp;  	    u8 humi;u8 temp_buf[3],humi_buf[3];DHT11_Read_Data(&temp,&humi);temp_buf[0]=temp/10+0x30;	temp_buf[1]=temp%10+0x30;temp_buf[2]='\0';//LCD_ShowString(55,100,tftlcd_data.width,tftlcd_data.height,16,temp_buf);humi_buf[0]=humi/10+0x30;	humi_buf[1]=humi%10+0x30;humi_buf[2]='\0';//LCD_ShowString(55,130,tftlcd_data.width,tftlcd_data.height,16,humi_buf);printf("temperature=%d°C  humidity=%d%%RH\r\n",temp,humi);// publish data to MQTT topicif (ESP8266_MQTT_Public_key_Value(topic_id, "temperature", temp_buf)) {printf("Published temperature successfully!\r\n");} else {printf("Failed to publish temperature!\r\n");}if (ESP8266_MQTT_Public_key_Value(topic_id, "humidity", humi_buf)) {printf("Published humidity successfully!\r\n");} else {printf("Failed to publish humidity!\r\n");}}// ========== 设备处理函数实现 ==========
// LED处理函数(假设LED_Init()已在led.h中声明)
void LedHandler(const char *state) {if (strcmp(state, "on") == 0) {LED_ON(); // 假设LED_ON()在led.c中实现printf("Led turned on\r\n");} else if (strcmp(state, "off") == 0) {LED_OFF(); // 假设LED_OFF()在led.c中实现printf("Led turned off\r\n");} else {printf("Invalid state for LED: %s\r\n", state);}
}// Motor处理函数(需根据实际硬件实现)
void MotorHandler(const char *state) {if (strcmp(state, "on") == 0) {// 这里添加电机启动代码printf("Motor started\r\n");} else if (strcmp(state, "off") == 0) {// 这里添加电机关闭代码printf("Motor stopped\r\n");} else {printf("Invalid state for Motor: %s\r\n", state);}
}// 设备处理注册表(可扩展)
DeviceHandler device_handlers[] = {{"Led", DEVICE_LED, LedHandler},{"Motor", DEVICE_MOTOR, MotorHandler},{NULL, DEVICE_UNKNOWN, NULL} // 结束标志
};// ========== JSON解析函数扩展 ==========
void parse_json_message(const char *message) {cJSON *root;cJSON *item; // 修正变量名,避免未使用警告if (message == NULL) {printf("错误:传入的JSON字符串为空\n");return;}root = cJSON_Parse(message);if (!root) {printf("JSON格式错误:%s\n", cJSON_GetErrorPtr());return;}// 遍历JSON对象中的键值对(修正变量声明位置)item = root->child; // 变量声明已在代码块开头,此处直接使用while (item) {const char *device_name = item->string;const char *state = item->valuestring;// 查找设备处理器DeviceHandler *handler = device_handlers;while (handler->device_name) {if (strcmp(device_name, handler->device_name) == 0) {handler->handler(state);break;}handler++;}if (!handler->device_name) { // 未找到处理器printf("Unknown device: %s\r\n", device_name);}item = item->next;}cJSON_Delete(root); // 释放内存
}int main() {// 初始化部分保持不变...SysTick_Init(72);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);USART1_Init(9600);LED_Init(); // 假设LED初始化函数在led.c中// Motor_Init(); // 如有电机初始化需添加WiFi_Config();printf("Hello, world!\r\n");printf("\r\n====================================\r\n");printf("STM32 + ESP8266 JSON Command Handler\r\n");printf("Supported devices: Led, Motor\r\n");printf("====================================\r\n");// 初始化WiFi和MQTTESP8266_STA_TCP_Client_MQTT();if (ESP8266_Set_MQTT_Sub(sub_topic_id, "0")) {printf("\r\nSubscribed to MQTT topic successfully!\r\n");} else {printf("\r\nFailed to subscribe to MQTT topic!\r\n");}if (ESP8266_MQTT_Public_key_Value(topic_id, "aa", "01")) {printf("\r\nPublished MQTT message successfully!\r\n");} else {printf("\r\nFailed to publish MQTT message!\r\n");}while(DHT11_Init())	//检测DS18B20是否纯在{//LCD_ShowString(130,50,tftlcd_data.width,tftlcd_data.height,16,"Error   ");printf("DHT11 Check Error!\r\n");delay_ms(500);		}//LCD_ShowString(130,50,tftlcd_data.width,tftlcd_data.height,16,"Success");printf("DHT11 Check OK!\r\n");while (1) {// 处理WiFi数据if (strEsp8266_Fram_Record.InfBit.FramFinishFlag) {uint16_t data_len; // 声明在代码块开头__disable_irq();   // 进入临界区data_len = strEsp8266_Fram_Record.InfBit.FramLength;// 复制数据到本地缓冲区memcpy(wifi_rx_buffer, strEsp8266_Fram_Record.Data_RX_BUF, data_len);wifi_rx_buffer[data_len] = '\0'; // 添加字符串结束符// 清除标志和计数器strEsp8266_Fram_Record.InfBit.FramFinishFlag = 0;strEsp8266_Fram_Record.InfBit.FramLength = 0;__enable_irq(); // 退出临界区// 处理接收到的数据ProcessWiFiData(wifi_rx_buffer, data_len);}// 其他业务逻辑...//温湿度if(read_data_flag) { // 如果开启读取数据标志printf("\r\nReading DHT11 data...\r\n");data_pros();  	 //读取一次DHT11数据最少要大于100m} delay_ms(200);}// 添加换行符避免警告printf("\n");
}// 处理WiFi数据的函数
void ProcessWiFiData(uint8_t *data, uint16_t length) {// 示例:直接打印原始数据printf("[RAW DATA] %s\r\n", data);// 检查是否是MQTT消息if (strstr((char *)data, "+MQTTSUBRECV:") != NULL) {// 解析MQTT消息char *topic_start = strchr((char *)data, ',') + 1;char *msg_length_start = strchr(topic_start, ',') + 1;char *msg_start = strchr(msg_length_start, ',') + 1;// 提取主题和消息char topic[32] = {0};char msg_length[32] = {0};char message[128] = {0};sscanf(topic_start, "%[^,]", topic);sscanf(msg_length_start, "%[^,]", msg_length);sscanf(msg_start, "%[^,]", message);HandleMQTTMessage(topic, message, msg_length);}// 可以添加其他协议处理...
}// 处理MQTT消息
void HandleMQTTMessage(const char *topic, const char *message, const char *message_length) {printf("Received MQTT message:\r\n");printf("Topic: %s\r\n", topic);         // topic_idprintf("Message: %s\r\n\r\n", message); // json 字符串// todo: 根据实际需求处理消息parse_json_message(message); // 解析JSON消息
}
// 添加换行符避免警告

运行效果:

完整代码


http://www.hkcw.cn/article/HUpHbdTfni.shtml

相关文章

ApiHug 1.3.9 支持 Spring 3.5.0 + Plugin 0.7.4 内置小插件升级!儿童节快乐!!!

有用内置小插件 - ApiHug小插件&#xff0c;大用途https://apihug.github.io/zhCN-docs/how/005_helpful_inner_plugin SDK: [1.3.9-RELEASE] - 2025-06-01 Move the router auto-processing to an internal plugin for enhanced flexibility.Translate the OAS to json sch…

CTFHub-RCE 命令注入-无过滤

观察源代码 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 发现除了index.php文件外&#xff0c;还存在一个可疑的文件 打开flag文件 我们尝试打开这个文件 127.0.0.1|cat 19492844826916.php 可是发现 文本内容显示不出来&…

Mysql库的操作和表的操作

Mysql库和表的操作 库的操作1.查看数据库列表2.创建数据库3.使用数据库4.查看当前在那个数据库中5.显示数据库的创建语句6.修改数据库7.删除数据库8.备份和恢复数据库9.查看数据的连接情况(简单来说就是查看有多少人使用你的数据库) 表的操作1.创建表2.查看表结构3.修改表本身(…

Excel如何分开查看工作表方便数据撰写

首先我这里有2class和3class两个工作表 接下来我们点击视图 按照顺序分别点击新建窗口和全部重排 ### 然后就是这样 接下来就OK了

C++23 已弃用特性

文章目录 1. std::aligned_storage 与 std::aligned_union1.1 特性介绍1.2 被弃用的原因1.3 替代方案 2. std::numeric_limits::has_denorm2.1 特性介绍2.2 被弃用的原因 3. 总结 C23 已弃用特性包括&#xff1a;std::aligned_storage、std::aligned_union 与 std::numeric_lim…

MySQL事务和索引原理

目录 1. MySQL事务原理 1.1. 事务的基本概念 1.2. 事务隔离的实现机制 1.3. 事务的启动方式 2. 索引的原理 2.1. 索引的作用 2.2. 索引常用模型及适用场景 2.3. InnoDB中的索引结构 2.4. 索引维护 2.5. 覆盖索引 2.6. 联合索引和最左缀原则 2.7. 索引下推 1. MySQL事…

第十一章 Java基础-继承

文章目录 1.继承来源2.继承特点3.子类能继承父类中哪些内容1.继承来源 是为了解决代码的重复冗余。

【11408学习记录】考研英语写作提分秘籍:2013真题邀请信精讲+万能模板套用技巧

邀请信 英语写作2013年考研英语&#xff08;一&#xff09;真题小作文题目分析写作思路第一段&#xff1a;第二段&#xff1a;锦囊妙句1&#xff1a;锦囊妙句2&#xff1a;锦囊妙句3&#xff1a;锦囊妙句5&#xff1a;锦囊妙句6&#xff1a;锦囊妙句9&#xff1a;锦囊妙句14&am…

汽车电子笔记之:有关汽车电子AUTOSAR的一些名词解释

目录 1、概述 2、基础概念 2.1、SPEM 2.2、SPEC 2.3、SIP包 2.4、SLP 2.5、HLP 2.6 、AUTOSAR方法论 2.6.1、ECU Extruct 2.6.2、ECU Configuration Values&#xff08;EcuC&#xff09; 2.6.3、Software Component Deion 2.6.4、Measurement and Calibration S…

ASP.NET Core OData 实践——Lesson8增删改查原始类型Property(C#)

大纲 支持的接口主要模型设计控制器设计数据源查询(GET)查询基础类型的原始类型属性查询基类类型Entity的基础类型属性的值查询基类类型Entity的派生类型属性的原始值 查询派生类型Entity的基础类型属性查询派生类型Entity的属性值查询派生类型Entity的派生类型属性的原始值 新…

PCIE之Lane Reserval通道out of oder调换顺序

参考&#xff1a;测量小百科 | PCIe通道位置翻转(Lane Reversal)技术 参考&#xff1a;PCIe学习笔记&#xff08;3&#xff09;链路初始化和训练_pcie 有序集 lane-CSDN博客 案例上都是按照x4或者x8交叉&#xff0c;对于x2也是有办法交叉的&#xff0c;如果4lane的顺序并不是…

LXQt修改开始菜单高亮

开始菜单红色高亮很难看 mkdir -p ~/.local/share/lxqt/palettes/ mkdir -p ~/.local/share/lxqt/themes/ cp /usr/share/lxqt/palettes/Dark ~/.local/share/lxqt/palettes/Darker cp -p /usr/share/lxqt/themes/dark ~/.local/share/lxqt/themes/darker lxqt-panel.qss L…

MIT 6.S081 2020 Lab6 Copy-on-Write Fork for xv6 个人全流程

文章目录 零、写在前面一、Implement copy-on write1.1 说明1.2 实现1.2.1 延迟复制与释放1.2.2 写时复制 零、写在前面 可以阅读下 《xv6 book》 的第五章中断和设备驱动。 问题 在 xv6 中&#xff0c;fork() 系统调用会将父进程的整个用户空间内存复制到子进程中。**如果父…

使用langchain实现RAG(检索增强生成)

概述 本文将从零开始实现一个langchain应用程序, 该应用支持读取pdf文档并embedding编码到Chroma数据库, 当用户提问时, 可以从网络搜索结果和本地向量数据库中收集数据, 传递给第三方LLM大模型, 所有使用到的工具完全免费 将使用如下技术或工具: python3.9langchainChroma …

力扣HOT100之动态规划:139. 单词拆分

这道题之前刷代码随想录的时候已经做过了&#xff0c;但是现在再做一遍还是不会&#xff0c;直接去看视频了。感觉这道题的dp数组很难想到&#xff0c;感觉做不出来也是情有可原吧。这道题目也是一个完全背包问题&#xff0c;字典里的单词就相当于物品&#xff0c;而字符串相当…

趋势直线指标

趋势直线副图和主图指标&#xff0c;旨在通过技术分析工具帮助交易者识别市场趋势和潜在的买卖点。 副图指标&#xff1a;基于KDJ指标的交易策略 1. RSV值计算&#xff1a; - RSV&#xff08;未成熟随机值&#xff09;反映了当前收盘价在过去一段时间内的相对位置。通过计算当前…

应急响应靶机-web3-知攻善防实验室

题目&#xff1a; 1.攻击者的两个IP地址 2.攻击者隐藏用户名称 3.三个攻击者留下的flag 密码&#xff1a;yj123456 解题&#xff1a; 1.攻击者的两个IP地址 一个可能是远程&#xff0c;D盾&#xff0c;404.php,192.168.75.129 找到远程连接相关的英文,1149代表远程连接成功…

前端-不对用户显示

这是steam的商店偏好设置界面&#xff0c;在没有被锁在国区的steam账号会有5个选项&#xff0c;而被锁在国区的账号只有3个选项&#xff0c;这里使用的技术手段仅仅在前端隐藏了这个其他两个按钮。 单击F12打开开发者模式 单击1处&#xff0c;找到这一行代码&#xff0c;可以看…

C++单调栈(递增、递减)

定义 先说单调栈的定义 单调栈&#xff0c;是指栈内数据逐步上升&#xff08;一个比一个大&#xff09;&#xff0c;或逐步下降&#xff08;一个比一个小&#xff09;的栈&#xff0c;其并没有独立的代码&#xff0c;而是在stack的基础上加以限制及条件形成的。 比如&#x…

WIN11+CUDA11.8+VS2019配置BundleFusion

参考&#xff1a; BundleFusion:VS2019 2017 ,CUDA11.5,win11&#xff0c;Realsense D435i离线数据包跑通&#xff0c;环境搭建 - 知乎 Win10VS2017CUDA10.1环境下配置BundleFusion - 知乎 BundleFusionWIN11VS2019 CUDA11.7环境配置-CSDN博客 我的环境&#xff1a;Win 11…