MQTT协议基础知识速成(智能家居项目)
智能家居项目
计划
看视频先做一遍纸制笔记
大概分成三个部分
分别记录疑问,总结,知识点。
再看课程配套的文档
自己跟着视频完成一遍
整理电子笔记(总结)
学习资料
略
1网络基础知识
网络基础知识解析
短距离不需要服务器,长距离需要。
通过 IP(公网 IP 唯一,局域网 IP 可重复),端口确定通信对象。
局域网到公网通信流程
- 局域网设备主动发起请求
- 路由器伪装身份:局域网地址伪装成公网地址将请求发送给服务器
- 服务器响应路由器
- 路由器转发数据:返回数据给局域网地址
注意:公网不能主动访问局域网设备,交流需局域网设备主动发起连接
2MQTT框架
大概框架
- 服务器:如电视台,负责接收连接、转发消息。
- 客户端:如记者(发布消息)和观众(订阅消息),开发板和手机均为客户端。
- 主题:顾名思义,客户端通过订阅 / 发布特定主题实现精准推送。
MQTT 协议通信流程
- 开发板(记者)连接服务器,发布设备状态到主题 “device/status”。
- 手机(观众)连接服务器,订阅主题 “device/control” 接收指令。
- 手机发布指令到 “device/control”,服务器转发至开发板,开发板执行操作后反馈状态。
优势
轻量级,低功耗,实时双向通信,在物联网、小型设备、移动应用等方面广泛应用。
常见中英文及其作用对照表
一、核心概念
英文术语 | 中文翻译 | 作用描述 |
Broker | 代理服务器 | 负责接收、存储和转发客户端的消息,是 MQTT 网络的核心枢纽,实现客户端之间的解耦。 |
Client | 客户端 | 连接到 Broker 的设备或应用程序,可以是消息的发布者(Publisher)或订阅者(Subscriber)。 |
Topic | 主题 | 消息的分类标识,用于标识消息的类型或设备 / 业务逻辑(如 ),客户端通过订阅 Topic 接收相关消息。 |
Payload | 有效载荷 | 消息的具体内容(二进制或字符串),由客户端自定义格式(如 JSON、Protobuf)。 |
二、消息类型
英文术语 | 中文翻译 | 作用描述 |
CONNECT | 连接请求 | 客户端向 Broker 发送的连接请求,包含协议版本、客户端 ID、认证信息等。 |
CONNACK | 连接确认 | Broker 响应客户端的连接请求,返回连接结果(成功 / 失败)及会话状态。 |
PUBLISH | 发布消息 | 客户端或 Broker 发送消息到指定 Topic,是最核心的消息传输机制。 |
PUBACK | 发布确认 | 接收方(Broker 或客户端)对 QoS 1 消息的确认,确保消息至少被传递一次。 |
PUBREC | 发布接收 | 接收方对 QoS 2 消息的第一阶段确认,用于实现消息的可靠传输(保证仅传递一次)。 |
PUBREL | 发布释放 | 发送方对 QoS 2 消息的第二阶段确认,完成消息传递的可靠性流程。 |
PUBCOMP | 发布完成 | 接收方对 QoS 2 消息的最终确认,标志着消息可靠传输流程结束。 |
SUBSCRIBE | 订阅请求 | 客户端向 Broker 请求订阅一个或多个 Topic,指定消息接收的 QoS 等级。 |
SUBACK | 订阅确认 | Broker 响应订阅请求,返回每个 Topic 的订阅结果(QoS 等级)。 |
UNSUBSCRIBE | 取消订阅 | 客户端向 Broker 请求取消已订阅的 Topic。 |
UNSUBACK | 取消订阅确认 | Broker 响应取消订阅请求,确认取消操作完成。 |
PINGREQ | 心跳请求 | 客户端向 Broker 发送的心跳包,用于检测连接是否存活,防止因长时间无数据传输而断开连接。 |
PINGRESP | 心跳响应 | Broker 对 PINGREQ 的响应,确认连接正常。 |
DISCONNECT | 断开连接 | 客户端或 Broker 主动终止连接,释放资源(如会话状态)。 |
三、关键参数与特性
英文术语 | 中文翻译 | 作用描述 |
QoS(Quality of Service) | 服务质量等级 | 定义消息传递的可靠性等级: |
Retain | 保留消息 | 若设置为 ,Broker 会保留最后一条消息,新订阅该 Topic 的客户端会立即收到这条保留消息。 |
Clean Session | 清除会话 | 客户端连接时的标志位: :断开连接后清除所有会话状态(非持久订阅) :保留会话状态(支持离线消息存储和持久订阅) |
Client ID | 客户端 ID | 唯一标识客户端的字符串,用于 Broker 区分不同连接(部分场景下可设置为匿名)。 |
Will Message | 遗嘱消息 | 客户端连接时设置的可选消息,若客户端异常断开(未发送 DISCONNECT),Broker 会向指定 Topic 发布该消息,用于通知其他客户端异常状态。 |
3MQTT源码分析
通信模型
-
- 基于 "记者 - 电视台 - 观众" 模式,即发布 - 订阅模式
- 核心流程:连接 (Connect)→订阅 (Subscribe)→发布 (Publish)→循环处理数据
-
关键机制
-
- 保持连接状态:通过心跳维持长连接
- 异步消息处理:通过独立线程循环读取网络数据
程序分层
+----------------+
| APP层 | 业务逻辑(控制设备、处理数据)
+----------------+
| MQTT层 | 协议实现(连接、订阅、发布)
+----------------+
| 平台层 | 多线程、定时器、网络接口
+----------------+
情景分析
连接服务器
mainclient = mqtt_lease();mqtt_set_port(client, "1883");mqtt_set_host(client, "www.jiejie01.top");mqtt_connect(client);mqtt_connect_with_results(c);rc = network_init(c->mqtt_network, c->mqtt_host, c->mqtt_port, NULL);rc = network_connect(c->mqtt_network);nettype_tcp_connect(n); platform_net_socket_connect
创建线程
mainmqtt_connect(client);mqtt_connect_with_results(c);rc = network_init(c->mqtt_network, c->mqtt_host, c->mqtt_port, NULL);rc = network_connect(c->mqtt_network);/* send connect packet */if ((rc = mqtt_send_packet(c, len, &connect_timer)) != MQTT_SUCCESS_ERROR)goto exit;if (mqtt_wait_packet(c, CONNACK, &connect_timer) == CONNACK) {}/* connect success, and need init mqtt thread */c->mqtt_thread= platform_thread_init("mqtt_yield_thread", mqtt_yield_thread,c, ...);
发布消息
mainres = pthread_create(&thread1, NULL, mqtt_publish_thread, client);mqtt_publish_threadmqtt_publish(client, "topic1", &msg);// 1. 构造消息
mqtt_message_t msg;memset(&msg, 0, sizeof(msg));
msg.payload = (void *) buf;
msg.payloadlen = xxx;mqtt_publish(client, "topic1", &msg);// 1.1 根据MQTT协议构造数据包// 1.2 根据平台相关的函数发送数据包mqtt_send_packetnetwork_writenettype_tcp_writeplatform_net_socket_write_timeout
订阅消息
某个内核线程不断查询是否接收数据
接收到数据就进行判断,处理。
4MQTT源码移植STM32F103
移植文件的本质是改错
内容上
- 修改引脚
- 解决报错
- 修改编译环境
移植程序四步骤
- 合并源码
-
- 创建自己的文件库
- 找到 main 函数里面的所有的初始化和数据类型文件
- 移植到自己的文件库中
- 解决编译(语法 / 类型)链接(符号未定义 / 找不到)错误
-
- 头文件找不到(自己指定路径)
- 数据类型报错
- 语法报错
- 调试
-
- 打断点并且全速运行
- 逐步判断错误
5编写ESP8266驱动
编译通过
编译没有问题
调试通过
写一段代码功能正常
不能正常运行就调试
6实现网络层
7MQTT综合测试
这不是有手就行
8健壮性
懒得写
9补充
寄存器
外设类型(前缀)
略
寄存器类别(中缀)
中缀 | 寄存器类型 | 核心功能 |
CR | Control Register | 配置外设工作模式(如使能、波特率、分频比) |
SR | Status Register | 存储外设状态标志(如发送完成、接收就绪) |
DR | Data Register | 数据读写(发送/接收缓冲区、ADC转换值) |
BRR | Baud Rate Register | 设置通信波特率(USART、SPI) |
CCR | Capture/Compare Register | 定时器捕获事件或生成PWM波形 |
ARR | Auto-Reload Register | 定时器自动重装载值(决定定时周期) |
PSC | Prescaler Register | 定时器预分频器(降低时钟频率) |
ODR | Output Data Register | GPIO输出数据寄存器(写1/0控制引脚电平) |
IDR | Input Data Register | GPIO输入数据寄存器(读引脚电平) |
BSRR | Bit Set/Reset Register | 原子操作GPIO引脚(单独置位/复位) |
CNT | Counter Register | 定时器当前计数值 |
字母 | 英文全称 | 中文含义 | 示例寄存器 |
R | Register | 寄存器 | USART_SR(状态寄存器) |
C | Control | 控制 | TIMx_CR1(控制寄存器 1) |
S | Status | 状态 | ADC_SR(状态寄存器) |
D | Data | 数据 | SPI_DR(数据寄存器) |
B | Baud Rate | 波特率 | USART_BRR(波特率寄存器) |
T | Timer/Counter | 定时器 / 计数器 | TIMx(定时器外设) |
O | Output | 输出 | GPIO_ODR(输出数据寄存器) |
I | Input | 输入 | GPIO_IDR(输入数据寄存器) |
具体标志位(后缀)
1. 通用标志位(常见于SR寄存器)
标志位 | 含义 | 典型场景 |
RXNE | Receive Buffer Not Empty | USART/SPI/I2C接收缓冲区非空(可读) |
TXE | Transmit Buffer Empty | USART/SPI/I2C发送缓冲区空(可写) |
TC | Transmission Complete | 发送完成标志(帧发送结束) |
OVR | Overrun Error | 接收溢出错误(数据覆盖) |
UDR | UnderRun Error | 发送下溢错误(发送缓冲区空但仍在发送) |
SB | Start Bit | USART检测到起始位 |
PE | Parity Error | 奇偶校验错误 |
字母 | 英文全称 | 中文含义 | 示例标志位 |
E | Enable | 使能 | USART_CR1_TE(发送使能) |
N | Not Empty | 非空 | USART_SR_RXNE(接收非空) |
C | Complete | 完成 | USART_SR_TC(发送完成) |
O | Overrun | 溢出 | SPI_SR_OVR(溢出错误) |
P | Parity | 奇偶校验 | USART_SR_PE(奇偶错误) |
S | Start | 起始 | USART_SR_SB(起始位) |
T | Transmission | 传输 | USART_CR1_TE(发送使能) |
R | Reception | 接收 | USART_CR1_RE(接收使能) |
2. 定时器专用标志位
标志位 | 含义 | 典型场景 |
UP | Update Event | 定时器更新事件(计数器溢出/重载) |
CC1IF | Capture/Compare 1 Interrupt Flag | 定时器通道1捕获/比较匹配 |
TRG | Trigger Event | 定时器触发事件(用于同步多个定时器) |
COM | Commutation Event | 定时器换相事件(用于电机控制) |
3. GPIO专用标志位
标志位 | 含义 | 典型场景 |
ODR | Output Data Register | 写1/0控制GPIO引脚输出电平 |
IDR | Input Data Register | 读GPIO引脚当前电平 |
BSRR | Bit Set/Reset Register | 原子操作置位/复位单个引脚(无竞争) |
BRR | Bit Reset Register | 复位GPIO引脚(等效于BSRR的低16位) |
4. 其他外设标志位
标志位 | 含义 | 典型场景 |
ADON | ADC ON | ADC使能位(开启模数转换) |
EOC | End of Conversion | ADC转换结束标志 |
AWD | Analog Watchdog | ADC模拟看门狗(监测电压范围) |
TCIF | Transfer Complete Interrupt Flag | DMA传输完成中断标志 |
ITR | Interrupt Trigger | 中断触发源选择 |
实例解析
- USART1_SR_RXNE
-
- 串口1状态寄存器的接收缓冲区非空标志
- 作用:当接收到数据时,硬件置1,提示软件读取DR寄存器
- TIM2_CCR1
-
- 定时器2的捕获/比较寄存器1
- 作用:配置PWM占空比(输出模式)或记录捕获事件时间(输入模式)
- GPIOA_BSRR_BS5
-
- GPIOA端口的位设置寄存器的第5位
- 作用:写1将GPIOA.5引脚置高电平(原子操作,无竞争)
- ADC1_DR
-
- ADC1的数据寄存器
- 作用:存放ADC转换后的数字值(读取该寄存器获取采样结果)
- SPI1_CR1_SPE
-
- SPI1控制寄存器1的SPI使能位
- 作用:写1启用SPI1外设,写0禁用
- I2C1_SR1_ADDR
-
- I2C1状态寄存器1的地址匹配标志
- 作用:当从设备地址被主设备匹配时置1
- DMA1_CCR1_TCIE
-
- DMA1通道1控制寄存器的传输完成中断使能位
- 作用:写1使能DMA传输完成时触发中断
快速判断步骤
- 看前缀:确定所属外设(如USART、GPIO、TIM)
- 看中缀:识别寄存器类型(CR=控制,SR=状态,DR=数据)
- 看后缀:明确具体功能(RXNE=接收非空,TXE=发送空,CCR=捕获比较)
&| 操作一般是确定具体的某一位
10 成品
略