简介:这是面向STM32与物联网开发者的项目实战代码,基于STM32F103与ESP8266,通过MQTT协议接入腾讯云物联网平台,并支持腾讯连连小程序,覆盖设备上云、数据主动上报与远程控制下发。压缩包共187个文件、6.36MB,以45个h头文件、43个c源文件为主,辅以目标文件、编译配置及hex固件,包含STM32标准外设库、ESP8266驱动、MQTT协议层等关键模块,便于二次开发与学习。代码基于KEIL开发,当前适配STM32F103C8T6,也可通过修改芯片型号和FLASH容量用于其他F103型号;实现了多路继电器状态上报及平台指令下发动作逻辑,并在工程中给出J-Link/S-T-Link下载器选型提醒。资源已有2603人学习,适合正在从事STM32物联网项目、希望快速接入云平台并借鉴数据交互与控制流程的开发者参考。 做物联网项目实战,被问得最多的问题就是:怎么把手里的单片机连上云,用手机随时随地看数据。这篇文章就围绕一套最典型的组合方案展开——STM32作为主控,ESP8266负责WIFI联网,数据传输走MQTT协议,云平台选腾讯云物联网云平台,最终在腾讯连连小程序里完成设备绑定、数据查看和指令下发。整条链路覆盖硬件接线、云平台配置、代码编写和联调四个环节,适合做课程设计、毕业设计、或者单纯想给个人DIY项目加上远程监控能力的读者。下面所有内容都是我自己反复跑通过的项目记录,照着做基本能一次走通。
1. 整体方案:为什么是STM32+ESP8266+MQTT+腾讯云
1.1 硬件组合的取舍逻辑
主控选择STM32F103C8T6,理由很直接:价格便宜、资料铺天盖地、库函数和HAL库都成熟,读几个传感器、跑一个数据上报任务绰绰有余。ESP8266则负责WIFI这一层,模块十几块钱,AT指令交互简单,既能当透传通道,也能承载MQTT报文的收发。
有朋友问我,为什么不直接用带WIFI的ESP32,甚至干脆让ESP8266自己跑逻辑?我的看法是,STM32管业务,ESP8266只管联网,两者各司其职,后面要换平台、换网络模块,主控代码几乎不用动。比如我把网络层从ESP8266换成4G模块,或者改成以太网,只需要替换驱动部分的实现,传感器采集、数据处理、本地控制逻辑完全复用。对于毕设和产品原型来说,这种分层结构维护成本低,排查问题时也能按层切分。
还有个容易踩的坑是电平。STM32串口输出是3.3V TTL,ESP8266串口也是3.3V TTL,两者之间能直接连,不需要转换。我见过不少新手习惯性用5V去拉,一上电模块就冒烟了。尤其是从Arduino转到STM32的朋友,这个习惯必须改。
1.2 协议与平台的选型逻辑
MQTT是物联网领域的事实标准协议,核心是发布/订阅模型。设备往主题发布消息,云端、App订阅主题接收消息,设备也可以订阅另一个主题来接收指令。这种解耦方式特别适合“远程看数据、远程控制设备”这种需求。
选腾讯云物联网平台(IoT Explorer),一个关键原因是有腾讯连连小程序。它省去了我从零开发App的工作量,小程序里搜索添加设备,直接能看到属性数据、下发控制指令。对于项目验收、现场演示来说,这种“打开微信就能用”的体验很加分。如果自建EMQX加网页客户端,还得处理域名、证书、鉴权,设备端联调成本高不少。
在开始写代码前,我建议先花半小时把MQTT的CONNECT、CONNACK、PUBLISH、SUBSCRIBE这几个核心报文概念过一遍。腾讯云连接参数里的ClientID、用户名、密码,本质上就对应CONNECT报文里的字段。理解了这个,后面配置参数就不是玄学,而是有逻辑可循的操作。
2. 环境准备与硬件接线:动手前的必修课
2.1 开发工具链搭建
STM32这边,用Keil MDK最成熟。装完Keil后要装STM32F1系列的芯片支持包,否则编译器不认识F103C8T6。烧录工具我习惯用ST-Link,配合STM32CubeProgrammer或者ST-Link Utility都行。如果只写简单串口程序,用串口ISP方式也能烧,但调试体验差很多,建议直接上ST-Link。
ESP8266这边,大部分模块出厂就预刷了AT固件,电脑上装个串口助手(XCOM、正点原子串口助手都行)就能直接调试。如果固件版本太老或者没有MQTT指令,就用乐鑫的Flash Download Tools重新烧写。烧录时把GPIO0拉低进入下载模式,固件写到0x00000地址,波特率设为115200,点击START就行。刷完后重新上电,串口发AT,返回OK就代表固件正常。
如果是用Arduino IDE开发ESP8266,需要先在开发板管理器里添加esp8266支持包,这个网上教程很多。不过我这套方案里,ESP8266只跑AT固件,STM32通过串口发AT指令来控制它,不在ESP8266上写业务代码。优势是代码量少、调试直观,也最贴近很多学校课程里教的AT指令操作方式。
2.2 硬件清单与接线
硬件部分,我常用的清单如下:
STM32F103C8T6最小系统板 ESP8266模块(ESP-01S、ESP-12F、NodeMCU均可) USB转TTL模块(CH340芯片即可) ST-Link V2下载器 杜邦线若干接线是整个项目最容易出问题的一步,不是接线本身难,而是电源和共地经常被忽略。正确接法是:STM32的USART1_TX(PA9)连接ESP8266的RXD,STM32的USART1_RX(PA10)连接ESP8266的TXD,GND两端必须连在一起。
供电这里我多提醒一句:ESP8266在连接WIFI的瞬间,电流峰值能达到300mA以上。如果直接用STM32板上的3.3V给它供电,电压容易被瞬间拉低,导致模块反复重启或者连接失败。我最早跑实验时就是贪方便,直接从最小系统板取电,结果连WIFI十次有八次失败,排查了半天才发现是供电不足。现在我的做法是给ESP8266单独用AMS1117-3.3稳压模块供电,或者至少并联一个大容量的电解电容稳住电压。
2.3 AT固件版本与联网预验证
ESP8266的固件版本直接决定后面代码能不能跑通。我推荐用安信可官方较新的AT固件,因为老版本固件只支持TCP/UDP透传,不支持MQTT指令。新固件多了AT+MQTTUSERCFG、AT+MQTTCONN这些指令,通过串口就能完成MQTT连接、订阅、发布,省去在STM32里手动拼MQTT报文的麻烦。
在接入STM32之前,强烈建议先把ESP8266单独接到电脑上,用串口助手验证一遍联网能力。操作是这样:
AT+CWMODE=1 // 设置为Station模式 AT+CWJAP="YourSSID","YourPassword" // 连接路由器正常情况下会返回WIFI CONNECTED,接着返回WIFI GOT IP,说明模块已经拿到IP地址。这一步提前验证,能把“WIFI问题”和“MQTT问题”分开,后面联调时如果连接云端失败,至少能确定WIFI这层是通的,不用从头排查。
3. 腾讯云物联网平台配置:拿三元组和连接参数
3.1 创建产品与数据模板
腾讯云物联网开发平台的入口叫IoT Explorer,登录后先创建产品。产品类型选“普通产品”,节点类型选“设备”,联网方式选“WIFI”,数据协议建议选“数据模板”模式。数据模板的好处是平台会帮你生成一套标准化的Topic和JSON数据格式,腾讯连连小程序能直接识别。
数据模板的定义是整个平台配置的基石。举个例子,做温湿度采集,就在数据模板里定义两个属性:temp(浮点型)、humidity(浮点型)。字段名、数据类型、读写权限都要认真填,因为后面设备上报的JSON字段名必须和模板完全一致,平台才会接收,否则数据会被丢弃。模板保存后,记得在产品层面发布一次,不发布的话,腾讯连连添加设备时会找不到该产品。
3.2 创建设备并保存三元组
在产品下创建设备,平台会自动分配三元组信息:ProductID(产品ID)、DeviceName(设备名称)、DeviceSecret(设备密钥)。这三个值就是设备端接入云端的“身份证”,后面写AT指令或用MQTT客户端测试时全都要用到。
这里有个细节:设备创建后,控制台里设备状态显示是“未激活”,这不代表有问题,只要设备第一次成功接入云平台,状态就会自动变成“上线”。另外我习惯把三元组单独存到一个文本文件里,写代码、配参数都从里面复制,避免手动输入时打错字符。尤其ProductID是数字和字母混合的长字符串,手输很容易出错。
3.3 MQTT连接参数计算与验证
腾讯云物联网平台的MQTT接入地址格式是{ProductID}.iotcloud.tencentdevices.com,调试阶段用1883端口(明文),正式生产再考虑8883端口的TLS加密。
连接时需要三个参数:ClientID、UserName、PassWord。以我实际项目用到的规则来说,格式大致如下:
ClientID = {ProductID}.{DeviceName} UserName = {ProductID}.{DeviceName};12010126;{时间戳};{signature} PassWord = {signature}其中signature是用DeviceSecret对{ProductID}{DeviceName}做HMAC-SHA256,再转成小写十六进制字符串。不同时期的平台文档对签名原文的说明可能略有差异,所以我的习惯是先去控制台的“设备调试”页面看它给出的连接参数示例,再照着算。计算我用Python脚本:
import hmac, hashlib, time ProductID = "你的产品ID" DeviceName = "你的设备名" DeviceSecret = "你的设备密钥" timestamp = str(int(time.time())) sign_content = (ProductID + DeviceName).encode() signature = hmac.new(DeviceSecret.encode(), sign_content, hashlib.sha256).hexdigest() print("timestamp:", timestamp) print("signature:", signature)把算出的ClientID、UserName、PassWord填进MQTT客户端测试工具(比如MQTTX),能连上并且设备状态变成“上线”,说明参数没问题。很多连接失败的案例,最后查出来都是签名规则里的字符串多了空格、换行,或者时间戳不是服务器当前时间,用脚本算一次再去和代码里的结果对比,效率会高很多。
4. 代码实现:STM32+ESP8266打通MQTT全链路
4.1 STM32串口驱动与数据处理
STM32侧的核心工作可以拆成三块:读传感器数据、格式化数据、通过串口控制ESP8266收发AT指令。我用STM32CubeMX初始化USART1,波特率115200,8位数据位、1位停止位、无校验,然后开启接收中断。
ESP8266的AT指令都是以\r\n结尾,应答也是以\r\n结尾。如果串口驱动一收到字节就立刻处理,很容易把一条完整的+MQTTCONNED: 0拆成好几段,导致解析失败。我的做法是在驱动层做一个简单的环形缓冲区,串口中断只负责把数据塞进缓冲区,主循环里按行读取,收到\r\n才做一次完整的指令匹配。这样判断“是否收到OK”“是否收到WIFI GOT IP”都非常方便。
4.2 AT指令流程与数据上云
程序启动后,STM32按下面这个顺序下发AT指令:
AT+CWMODE=1 AT+CWJAP="YourSSID","YourPassword" # 等待返回 WIFI GOT IP AT+MQTTUSERCFG=0,0,"clientID","userName","password",0,0,"" AT+MQTTCONN=0,"yourProductID.iotcloud.tencentdevices.com",1883,1 # 等待返回 +MQTTCONNED: 0 AT+MQTTSUB=0,"$thing/down/property/{ProductID}/{DeviceName}",1 AT+MQTTPUB=0,"$thing/up/property/{ProductID}/{DeviceName}","{\"type\":\"report\",\"clientToken\":\"123\",\"data\":{\"temp\":25.5,\"humidity\":60}}",0,0这套流程是基于带MQTT功能的AT固件写的,不同固件指令集有差异,但整体思路一致:配网、配置MQTT参数、连接云端、订阅主题、发布数据。
其中需要重点理解的是Topic。$thing/up/property/{ProductID}/{DeviceName}是属性上报的Topic,传感器数据封装成JSON后通过PUBLISH报上去;$thing/down/property/{ProductID}/{DeviceName}是属性下发Topic,小程序下发指令时,STTM32订阅该主题后能收到云端推过来的JSON。Payload的格式可以直接从腾讯云控制台的“设备调试”里复制示例,把字段值替换成自己的数据即可。
4.3 腾讯连连小程序绑定与验证
设备端跑起来后,在微信里搜索“腾讯连连”小程序,登录同一个腾讯云账号,点击添加设备,按产品ID和设备名称填写绑定信息。
这里有个关键点:腾讯连连绑定设备时填的是产品ID、设备名称,不是扫标签上的二维码。如果设备还没激活,或者产品没有发布,小程序会一直提示“添加失败”。我的验证顺序是,先在PC控制台看到设备状态是“上线”,再去小程序添加设备,这样能快速定位问题出在设备端还是小程序端。
如果小程序提示“设备已被绑定”,说明这个DeviceName之前被添加过了。处理方法就是在控制台删除该设备重建一个,或者在小程序里解绑旧设备。实际演示时遇到这类问题不用慌,多半是重复绑定造成的。
5. 实测踩坑记录与排查速查表
5.1 ESP8266连不上WIFI怎么办
AT+CWJAP返回ERROR或一直FAIL,最常见的原因有三个:SSID密码填错、路由器是5G频段、信号太弱。ESP8266只支持2.4G频段,很多双频路由器默认开了5G,手机能连上但模块扫不到。
排查顺序我一般是这样:
- 先用手机确认路由器是2.4G还是5G频段,5G频段直接换个热点测试;
- 确认WIFI密码末尾没有多余空格,复制粘贴时极容易带上换行符;
- 把模块靠近路由器再测试,排除信号强度问题;
- 反复失败时重启模块和路由器,重新发送AT+CWJAP。
另一个容易被忽略的是路由器开启了AP隔离,设备之间无法互相通信。在校企网络、办公室网络里特别常见。我吃过一次亏,排查半天最后换了手机热点才解决。所以在实验室或办公环境测试,直接用手机开热点是最省心的方案。
5.2 MQTT连接超时或返回ERROR
AT+MQTTCONN返回ERROR或者一直没响应,大概率是三个参数之一填错了:ClientID格式不对、签名算法算错、端口不匹配。
排查思路:
- 确认当前没有其他MQTT客户端在占用同一个设备连接,腾讯云一个设备一般只允许一个在线连接,重复连接会把前面的踢下线;
- 确认时间戳是服务器当前时间,如果开发板本地时间不准,用了旧的固定时间戳,平台会拒绝鉴权;
- 用MQTTX这类PC客户端先手动填一次参数,如果能连上,说明参数正确,问题出在ESP8266固件或AT指令拼写上。
另外,网上很多教程的签名规则来自其他云平台,比如OneNET或阿里云,各平台的算法和参数分隔符不一样,不能直接套用。照着本文最后的Python脚本算一遍,再去对照控制台给出的连接参数示例,是最靠谱的。
5.3 数据上报到平台后看不到或刷新不及时
数据上报成功但控制台没显示,先检查PUBLISH的Topic和Payload格式。JSON字段名必须与数据模板里的定义完全一致,多一个下划线、大小写不对,平台都会当成无效数据丢弃。
腾讯连连小程序刷新延迟,通常和订阅Topic有关。设备端要确保已经成功订阅了$thing/down/property/...这个下行Topic,因为腾讯连连的数据展示和指令下发都依赖这个通道。如果订阅失败,设备能上报数据,但小程序里的指令发不下去,表现为“只能看不能控”。
我联调时的一个习惯是,把STM32串口1的AT交互原样打印到调试串口,相当于给项目装了“黑匣子日志”。哪条指令没成功、哪个应答超时,直接看日志一目了然,不用靠猜。这个习惯在整个项目调试阶段能节省大量时间,尤其是现场排查问题时,日志就是最直接的证据。
最后再说个经验:这个项目的技术点不复杂,但链路长、节点多,从硬件供电到云平台鉴权,每一层都可能出问题。按“底层到上层”的顺序排查——先看供电稳不稳,再看WIFI通不通,然后验证MQTT参数对不对,最后检查数据模板匹不匹配——能最快定位问题。这组方案我后来复用了好多次,做过温湿度监控、远程开关、报警通知几个变体,整体稳定性和开发效率都很满意。如果你也在折腾类似的东西,先按这条最小链路跑通,再往上加你的业务逻辑,后面会轻松很多。
本文还有配套的精品资源,点击获取