@KongChar 佬,太强了吧
诗的结尾
-
MSPM0火焰 -
51单片机+ESP8266连接mqtt的智能火灾报警系统设计与实现<p>声明:本项目为自研,(前端是小伙伴帮忙做的)开发不易,大家点点赞支持一下主播吧(目前网上没有看到基于51的mqtt相关项目,感觉51搞这些太容易超内存了,并且大佬都在搞32)</p><p>本博客不包含emqx的搭建教程,不会搭建emqx的可以先看这个博主的视频: <span><a href="http:// https://b23.tv/fuq6wbk" target="_blank" rel="noopener noreferrer">https://b23.tv/fuq6wbk</a></span></p><p>结尾附网盘链接</p><h2>项目概述</h2><p>本项目基于STC89C52RC单片机,结合ESP8266 WiFi模块、DHT11温湿度传感器、MQ-2气体传感器等硬件,设计并实现了一个智能火灾报警系统。系统能够实时监测环境温湿度和可燃气体浓度,通过MQTT协议将数据上传到云平台,并支持远程报警和阈值设置。</p><p>
<span><img src="/assets/uploads/files/1785077888776-image.png" alt="image.png" data-size="large" /></span></p><h2>系统架构</h2><h3>硬件组成</h3><ul><li><p><strong>主控芯片</strong>:STC89C52RC单片机</p></li><li><p><strong>通信模块</strong>:ESP8266 WiFi模块(ESP-01S)</p></li><li><p><strong>传感器</strong>:</p><ul><li><p>DHT11温湿度传感器</p></li><li><p>MQ-2气体浓度传感器</p></li></ul></li><li><p><strong>AD/DA转换模块</strong>:PCF8591转换模块</p></li><li><p><strong>显示模块</strong>:LCD1602液晶显示屏</p></li><li><p><strong>报警模块</strong>:蜂鸣器、LED报警灯</p></li></ul><h3>软件架构</h3><ul><li><p><strong>开发环境</strong>:Keil C51</p></li><li><p><strong>通信协议</strong>:MQTT</p></li><li><p><strong>数据格式</strong>:JSON</p></li></ul><h2><strong>PCB设计</strong></h2><p><span></span></p><p>1.原理图</p><p><img src="/assets/uploads/files/1785077910964-image.png" alt="image.png" data-size="large" /></p><p>2.PCB</p><p><img src="/assets/uploads/files/1785078011677-image.png" alt="image.png" data-size="large" /></p><p><span></span></p><h2>核心功能实现</h2><h3>1. 传感器数据采集</h3><p>1.mq2烟雾传感器</p>
<blockquote><code><span></span></code><code><span><span></span></span></code><span>#include "mq2.h''<br /></span><p><span><strong>#include "i2c.h"</strong></span><strong><span></span></strong></p><p><strong><span>#define PCF8591_ADDR 0x90</span><span> </span><span>// PCF8591 I2C地址</span><span></span></strong></p><p><strong><span> </span></strong></p><p><strong><span>// 读取PCF8591指定通道的模拟值(MQ2接通道0)</span><span></span></strong></p><p><strong><span>unsigned char MQ2_ReadByte(unsigned char Channel)</span><span></span></strong></p><p><strong><span>{</span><span></span></strong></p><p><strong><span> </span><span>unsigned char Data;</span><span></span></strong></p><p><strong><span> </span><span>I2C_Start();</span><span></span></strong></p><p><strong><span> </span><span>I2C_SendByte(PCF8591_ADDR);</span><span> </span><span> </span></strong><span><strong>// </strong><strong>写地址</strong></span><span></span></p><p><span></span></p><p><span></span></p></blockquote><p><span></span><span></span><span></span></p>
<p><span></span></p><p>2.dht11温湿度传感器</p>
<pre><code><span>#<span>include</span> <span>"dht11.h"</span></span>
<span>#<span>include</span> <span><intrins.h></span></span><span>// 30us延时</span>
<span><span>void</span> <span>DHT11_Delay30us</span><span>(<span>void</span>)</span>
</span>{
<span>unsigned</span> <span>char</span> i;
i = <span>12</span>;
<span>while</span> (--i);
}<span>// 40us延时</span>
<span><span>void</span> <span>DHT11_Delay40us</span><span>(<span>void</span>)</span>
</span>{
<span>unsigned</span> <span>char</span> i;
i = <span>17</span>;
<span>while</span> (--i);
}<span><span>uint8_t</span> <span>DHT11_Init</span><span>(<span>void</span>)</span>
</span>{
DHT11_DQ = <span>1</span>;
DHT11_DQ = <span>0</span>;
<span>Delay_xms</span>(<span>20</span>); <span>// 至少给18ms</span>
DHT11_DQ = <span>1</span>;
<span>DHT11_Delay30us</span>();<span>if</span>(DHT11_DQ == <span>0</span>) { <span>while</span>(DHT11_DQ == <span>0</span>); <span>while</span>(DHT11_DQ == <span>1</span>); <span>return</span> <span>0</span>; } <span>return</span> <span>1</span>;}
<span><span>uint8_t</span> <span>DHT11_ReceiveByte</span><span>(<span>void</span>)</span>
</span>{
<span>uint8_t</span> i, Byte = <span>0x00</span>;
<span>for</span>(i=<span>0</span>; i<<span>8</span>; i++)
{
Byte <<= <span>1</span>;
<span>while</span>(DHT11_DQ == <span>0</span>);
<span>DHT11_Delay40us</span>();
<span>if</span>(DHT11_DQ == <span>1</span>) Byte |= <span>0x01</span>;
<span>while</span>(DHT11_DQ == <span>1</span>);
}
<span>return</span> Byte;
}<span><span>uint8_t</span> <span>DHT11_GetData</span><span>(<span>uint8_t</span> *Humi_H, <span>uint8_t</span> *Humi_L, <span>uint8_t</span> *Temp_H, <span>uint8_t</span> *Temp_L)</span>
</span>{
<span>uint8_t</span> i, Buffer[<span>5</span>];
<span>if</span>(<span>DHT11_Init</span>() == <span>0</span>)
{
<span>for</span>(i=<span>0</span>; i<<span>5</span>; i++) Buffer[i] = <span>DHT11_ReceiveByte</span>();<span>if</span>(Buffer[<span>0</span>] + Buffer[<span>1</span>] + Buffer[<span>2</span>] + Buffer[<span>3</span>] == Buffer[<span>4</span>]) { *Humi_H = Buffer[<span>0</span>]; *Humi_L = Buffer[<span>1</span>]; *Temp_H = Buffer[<span>2</span>]; *Temp_L = Buffer[<span>3</span>]; <span>return</span> <span>0</span>; } } <span>return</span> <span>1</span>;}
</code></pre>
<p><span></span>
</p><pre><code><span>#<span>ifndef</span> DHT11_H</span>
<span>#<span>define</span> DHT11_H</span><span>#<span>include</span> <span><reg52.h></span></span>
<span>#<span>include</span> <span>"delay.h"</span></span><span>typedef</span> <span>unsigned</span> <span>char</span> <span>uint8_t</span>;
sbit DHT11_DQ = P2^<span>0</span>; <span>// 引脚设置</span>
<span><span>uint8_t</span> <span>DHT11_Init</span><span>(<span>void</span>)</span></span>;
<span><span>uint8_t</span> <span>DHT11_ReceiveByte</span><span>(<span>void</span>)</span></span>;
<span><span>uint8_t</span> <span>DHT11_GetData</span><span>(<span>uint8_t</span> *Humi_H, <span>uint8_t</span> *Humi_L, <span>uint8_t</span> *Temp_H, <span>uint8_t</span> *Temp_L)</span></span>;<span>#<span>endif</span></span>
</code></pre>
<p><span></span></p><h3>2. ESP8266 MQTT通信</h3><p>注意:客户端ID随意但是必须唯一,用户名称和密码就是自己在emqx上设置的</p><p><span><img src="/assets/uploads/files/1785078045468-image.png" alt="image.png" data-size="large" /></span></p><p>注意:mqtt的IP地址用ipconfig查看不了,可以用网络调试助手等软件看,不知道是哪个可以先用串口调试ESP8266,发送AT指令连接尝试:(串口发送AT指令记得末尾加上换行)</p><blockquote><p>AT+CWMODE=1</p><p>AT+CWJAP="WiFi名","WiFi密码"</p><p>AT+MQTTUSERCFG=0,1,"客户端ID","用户名","密码",0,0,""</p><p>AT+MQTTCONN=0,"mqtt的IP地址",1883,0</p></blockquote><p><span></span></p><p>网络调试助手:</p><p><img src="/assets/uploads/files/1785078101073-image.png" alt="image.png" data-size="large" /></p><p><span></span></p><p>esp8266.c</p>
<pre><code><span>#<span>include</span> <span>"esp8266.h"</span></span>
<span>#<span>include</span> <span><reg52.h></span></span>
<span>#<span>include</span> <span>"lcd1602.h"</span></span>
<span>#<span>include</span> <span>"usart.h"</span></span>
<span>#<span>include</span> <span>"delay.h"</span></span>
<span>#<span>include</span> <span>"time.h"</span></span><span>// 硬件引脚定义</span>
sbit WIFI_RST = P1^<span>7</span>; <span>// ESP8266复位</span>
sbit Bee = P1^<span>6</span>; <span>// 蜂鸣器</span>
sbit ALARM_LED= P1^<span>5</span>; <span>// 报警灯</span><span>// 全局变量:传感器数据</span>
<span>unsigned</span> <span>char</span> Humi_H, Temp_H, Gas;
<span>unsigned</span> <span>char</span> Threshold = <span>29</span>; <span>// 温度报警阈值</span><span>// ESP8266初始化连接MQTT(使用AT指令)</span>
<span><span>void</span> <span>ESP_conect_sev</span><span>(<span>void</span>)</span>
</span>{
<span>// ESP8266复位</span>
WIFI_RST = <span>0</span>;
<span>Delay_xms</span>(<span>1000</span>);
WIFI_RST = <span>1</span>;
<span>Delay_xms</span>(<span>1000</span>);<span>// 本地MQTT AT指令配置</span> <span>uart1_sendstring</span>(<span>"AT+CWMODE=1\r\n"</span>); <span>Delay_xms</span>(<span>1000</span>); <span>uart1_sendstring</span>(<span>"AT+CWJAP=\"WiFi名\",\"密码\"\r\n"</span>); <span>// 连接WiFi</span> <span>Delay_xms</span>(<span>2000</span>); <span>uart1_sendstring</span>(<span>"AT+MQTTUSERCFG=0,1,\"客户端ID\",\"用户名\",\"密码\",0,0,\"\"\r\n"</span>); <span>// MQTT用户配置</span> <span>Delay_xms</span>(<span>1000</span>); <span>uart1_sendstring</span>(<span>"AT+MQTTCONN=0,\"IP地址\",1883,0\r\n"</span>); <span>// 连接MQTT服务器</span> <span>Delay_xms</span>(<span>2000</span>);}
<span>// 数字转字符串(发送数据用)</span>
<span><span>void</span> <span>num_to_str</span><span>(<span>unsigned</span> <span>char</span> num, <span>unsigned</span> <span>char</span> *num_str1)</span>
</span>{
<span>if</span>(num != <span>0</span>)
{
<span>unsigned</span> <span>int</span> num_temp = num;
<span>unsigned</span> <span>char</span> cnt = <span>0</span>;
<span>while</span>(num_temp)
{
cnt++;
num_temp /= <span>10</span>;
}
num_temp = num;
<span>while</span>(cnt)
{
cnt--;
num_str1[cnt] = (num_temp % <span>10</span>) + <span>48</span>;
num_temp /= <span>10</span>;
}
}
<span>else</span>
{
num_str1[<span>0</span>] = <span>'0'</span>;
}
}<span>// 发送第一个传感器数据(湿度)</span>
<span><span>void</span> <span>first_data</span><span>(<span>unsigned</span> <span>char</span> *str2, <span>unsigned</span> <span>char</span> num)</span>
</span>{
<span>unsigned</span> <span>char</span> str1[<span>3</span>] = {<span>0</span>};
<span>// MQTT发布主题:testtopic/1,保留JSON数据格式</span>
<span>uart1_sendstring</span>(<span>"AT+MQTTPUB=0,"testtopic/1","{\""</span>);
<span>uart1_sendstring</span>(str2);
<span>uart1_sendstring</span>(<span>"\":"</span>);
<span>num_to_str</span>(num, str1);
<span>uart1_sendstring</span>(str1);
}<span>// 追加传感器数据(温度、气体浓度)</span>
<span><span>void</span> <span>add_data</span><span>(<span>unsigned</span> <span>char</span> *str2, <span>unsigned</span> <span>char</span> num)</span>
</span>{
<span>unsigned</span> <span>char</span> str1[<span>3</span>] = {<span>0</span>};
<span>uart1_sendstring</span>(<span>"\,\""</span>);
<span>uart1_sendstring</span>(str2);
<span>uart1_sendstring</span>(<span>"\":"</span>);
<span>num_to_str</span>(num, str1);
<span>uart1_sendstring</span>(str1);
}<span>// 每秒发送传感器数据到MQTT</span>
<span><span>void</span> <span>ESP_send_data</span><span>(<span>void</span>)</span>
</span>{
<span>if</span>(time0_ms > <span>1000</span>) <span>// 1秒发送一次</span>
{
<span>first_data</span>(APP_Humi, Humi_H); <span>// 湿度</span>
<span>add_data</span>(APP_Temp, Temp_H); <span>// 温度</span>
<span>add_data</span>(APP_Gas, Gas); <span>// 气体浓度</span>
<span>uart1_sendstring</span>(<span>"}",0,0\r\n"</span>);
<span>Delay_xms</span>(<span>200</span>);
<span>uart1_sendstring</span>(<span>"AT+MQTTPUB=0,"订阅主题名",""</span>);
<span>if</span>(Gas > <span>50</span> || Temp_H > Threshold)
{
<span>uart1_sendstring</span>(<span>"fire"</span>); <span>// 报警发送fire</span>
}
<span>else</span>
{
<span>uart1_sendstring</span>(<span>"normal"</span>);<span>// 正常发送normal</span>
}
<span>uart1_sendstring</span>(<span>"",0,0\r\n"</span>);
<span>Delay_xms</span>(<span>200</span>);
time0_ms = <span>0</span>; <span>// 重置定时器</span>
}
}<span>// 字符串比较</span>
<span>bit <span>str_cmp</span><span>(<span>char</span> *str1, <span>char</span> *str2, <span>char</span> len)</span>
</span>{
<span>char</span> *str3 = str1;
<span>char</span> *str4 = str2;
<span>while</span>(len)
{
<span>if</span>(*str3 != *str4) <span>return</span> <span>0</span>;
len--;
str3++;
str4++;
}
<span>return</span> <span>1</span>;
}<span>// 字符串转数字</span>
<span><span>int</span> <span>str_to_num</span><span>(<span>char</span> *str1)</span>
</span>{
<span>unsigned</span> <span>char</span> num = <span>0</span>;
<span>while</span>(*str1 >= <span>'0'</span> && *str1 <= <span>'9'</span>)
{
num += (*str1) - <span>48</span>;
str1++;
<span>if</span>(!(*str1 >= <span>'0'</span> && *str1 <= <span>'9'</span>)) <span>break</span>;
num *= <span>10</span>;
}
<span>return</span> num;
}<span>// 处理本地MQTT下发指令</span>
<span>unsigned</span> <span>char</span> Deliver_num;
<span><span>void</span> <span>Proces_distribut_data</span><span>(<span>void</span>)</span>
</span>{
<span>unsigned</span> <span>char</span> i; <span>// C89:提前声明循环变量,修复语法错误</span>
<span>if</span>(RX_ok) <span>// 接收完成</span>
{
Deliver_num = <span>str_to_num</span>(Deliver_data); <span>// 解析指令数值</span>
<span>// 仅保留温度阈值修改逻辑(可扩展其他本地指令)</span>
<span>if</span>(<span>str_cmp</span>(Deliver_identifier, APP_Threshold, <span>8</span>))
{
Threshold = Deliver_num;
}<span>// 清空接收缓存</span> <span>for</span>(i=<span>0</span>; i<<span>6</span>; i++) { Deliver_identifier[i] = <span>0</span>; } <span>for</span>(i=<span>0</span>; i<<span>4</span>; i++) { Deliver_data[i] = <span>0</span>; } Deliver_cnt = <span>0</span>; Deliver_data_cnt = <span>0</span>; RX_ok = <span>0</span>; }}
<span>// 传感器报警逻辑(气体浓度/温度过高)</span>
<span><span>void</span> <span>Alarm_Check</span><span>(<span>void</span>)</span>
</span>{
<span>if</span>(Gas > <span>50</span> || Temp_H > Threshold) <span>// 气体浓度>阈值 或 温度>阈值</span>
{
<span>LCD_ShowString</span>(<span>2</span>, <span>7</span>, <span>"fire!"</span>);
Bee = <span>0</span>; <span>// 蜂鸣器响</span>
ALARM_LED = <span>1</span>; <span>// 报警灯亮</span>
}
<span>else</span>
{
<span>LCD_ShowString</span>(<span>2</span>, <span>7</span>, <span>" "</span>);
Bee = <span>1</span>; <span>// 蜂鸣器关</span>
ALARM_LED = <span>0</span>; <span>// 报警灯灭</span>
}
}
</code></pre>
<p><span></span></p><p>esp8266.h</p>
<pre><code><span>#<span>ifndef</span> ESP8266_H</span>
<span>#<span>define</span> ESP8266_H</span><span>#<span>include</span> <span><reg52.h></span></span>
<span>#<span>include</span> <span>"usart.h"</span></span>
<span>#<span>include</span> <span>"time.h"</span></span><span>// 传感器数据宏定义</span>
<span>#<span>define</span> APP_Humi <span>"Humi"</span> <span>// 湿度</span></span>
<span>#<span>define</span> APP_Temp <span>"Temp"</span> <span>// 温度</span></span>
<span>#<span>define</span> APP_Gas <span>"Gas"</span> <span>// 气体浓度</span></span>
<span>#<span>define</span> APP_Threshold <span>"Threshold"</span> <span>// 温度阈值</span></span><span>extern</span> <span>unsigned</span> <span>char</span> Humi_H, Temp_H, Gas;
<span>extern</span> <span>unsigned</span> <span>char</span> Threshold;<span><span>void</span> <span>ESP_conect_sev</span><span>(<span>void</span>)</span></span>;
<span><span>void</span> <span>ESP_send_data</span><span>(<span>void</span>)</span></span>;
<span><span>void</span> <span>num_to_str</span><span>(<span>unsigned</span> <span>char</span> num, <span>unsigned</span> <span>char</span> *num_str1)</span></span>;
<span>bit <span>str_cmp</span><span>(<span>char</span> *str1, <span>char</span> *str2, <span>char</span> len)</span></span>;
<span><span>int</span> <span>str_to_num</span><span>(<span>char</span> *str1)</span></span>;
<span><span>void</span> <span>Proces_distribut_data</span><span>(<span>void</span>)</span></span>;
<span><span>void</span> <span>Alarm_Check</span><span>(<span>void</span>)</span></span>;
<span><span>void</span> <span>first_data</span><span>(<span>unsigned</span> <span>char</span> *str2, <span>unsigned</span> <span>char</span> num)</span></span>;
<span><span>void</span> <span>add_data</span><span>(<span>unsigned</span> <span>char</span> *str2, <span>unsigned</span> <span>char</span> num)</span></span>;<span>#<span>endif</span></span>
</code></pre>
<p><span></span></p><h2>关键技术点</h2><h3>1. 数据格式转换</h3><p>由于51的时钟频率差异(11.0592MHz相比32性能相差数十倍,所以数字转换算法必须极度优化,我在这个问题上卡了两天,后面查到一种比较好的轻量级数字转换算法</p>
<pre><code><span><span>void</span> <span>num_to_str</span><span>(<span>unsigned</span> <span>char</span> num, <span>unsigned</span> <span>char</span> *num_str1)</span>
</span>{
<span>if</span>(num != <span>0</span>)
{
<span>unsigned</span> <span>int</span> num_temp = num;
<span>unsigned</span> <span>char</span> cnt = <span>0</span>;
<span>while</span>(num_temp)
{
cnt++;
num_temp /= <span>10</span>;
}
num_temp = num;
<span>while</span>(cnt)
{
cnt--;
num_str1[cnt] = (num_temp % <span>10</span>) + <span>48</span>;
num_temp /= <span>10</span>;
}
}
<span>else</span>
{
num_str1[<span>0</span>] = <span>'0'</span>;
}
}</code></pre>
<p><span></span></p><h3>2. JSON数据构造</h3><p>由于51单片机内存限制,无法使用标准库,需要采用手动构造JSON格式数据:</p>
<pre><code><span><span>void</span> <span>first_data</span><span>(<span>unsigned</span> <span>char</span> *str2, <span>unsigned</span> <span>char</span> num)</span>
</span>{
<span>unsigned</span> <span>char</span> str1[<span>3</span>] = {<span>0</span>};
<span>// MQTT发布主题:testtopic/1,保留JSON数据格式</span>
<span>uart1_sendstring</span>(<span>"AT+MQTTPUB=0,"testtopic/1","{\""</span>);
<span>uart1_sendstring</span>(str2);
<span>uart1_sendstring</span>(<span>"\":"</span>);
<span>num_to_str</span>(num, str1);
<span>uart1_sendstring</span>(str1);
}</code></pre>
<p><span></span></p><h3>3. 中断处理的能力限制</h3><p>51单片机中断向量少,响应慢。32则有着丰富的中断源,NVIC优先级管理</p>
<pre><code><span><span>void</span> <span>UART1_IRQ_Handle</span><span>(<span>void</span>)</span> interrupt 4 <span>using</span> 1
</span>{
<span>if</span> (TI) {
TI = <span>0</span>;
uart1_busy = <span>0</span>; <span>// 只做标志位操作</span>
}
<span>if</span> (RI) {
<span>Pro_deliver_data</span>(); <span>// 立即处理,不缓存</span>
RI = <span>0</span>;
}
}</code></pre>
<p><span></span></p><h2>系统特点</h2><ol>
<li>
<p><strong>实时监测</strong>:持续监控环境参数</p>
</li>
<li>
<p><strong>双重报警</strong>:本地声光报警 + 远程状态推送</p>
</li>
<li>
<p><strong>远程控制</strong>:支持通过MQTT修改报警阈值</p>
</li>
<li>
<p><strong>稳定可靠</strong>:采用工业级传感器和成熟的通信协议</p>
</li>
<li>
<p><strong>低成本</strong>:基于廉价硬件组件</p>
</li>
</ol><h2>应用场景</h2><ul>
<li>
<p>家庭火灾预警</p>
</li>
<li>
<p>仓库环境监控</p>
</li>
<li>
<p>实验室安全监测</p>
</li>
<li>
<p>工业生产环境监控</p>
</li>
</ul><h2>总结</h2><p>本系统成功实现了基于51单片机和ESP8266的智能火灾报警功能,展示了如何将传统单片机与现代物联网技术相结合。系统具有良好的实用性和扩展性,为小型化、低成本的智能安防系统开发提供了参考方案。</p><hr /><p><strong>网盘链接:</strong> <span><a href="https://pan.baidu.com/s/1cfd2bHt5SNVlaVzUCct9XQ " target="_blank" rel="noopener noreferrer">https://pan.baidu.com/s/1cfd2bHt5SNVlaVzUCct9XQ </a></span>提取码: sdjw<br />
欢迎在评论区或群留言讨论!</p> -
主包、主包。不要跟风,把登录过期时间设计这么短。好不好@鲁迪乌斯 因为灰度更新了,应该是更新导致的
-
兄弟们,有谁打通过支付通道@鲁迪乌斯 什么东西
-
可以叫网安的朋友攻击一下吗666,想干嘛啊