尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32+ESP8266接入阿里云物联网平台:从AT指令到MQTT实战

STM32+ESP8266接入阿里云物联网平台:从AT指令到MQTT实战 做嵌入式这几年几乎每个搞单片机的朋友在某个阶段都会想同一件事把板子上的数据弄到云上去人不在现场也能随时看。我最早认真做这套方案是在给一个环境监测小设备升级的时候。当时设备已经跑得很稳但每次要看数据都得跑到现场接串口实在太低效。正巧手上囤了一块STM32F103C8T6最小系统板和几个ESP8266模块就想把数据通过WiFi送到阿里云物联网平台在手机端实时查看趋势图再顺手做个远程开关。整个过程踩了不少坑从AT指令连WiFi到MQTT报文破解再到阿里云的设备认证每一步都值得记录下来。这篇文章不会泛泛讲概念而是从方案选型、硬件接线、平台配置、核心代码到调试排错把一条能直接复现的路径完整放出来。适合正在做毕业设计、项目原型或者产品Demo的嵌入式开发者也适合刚接触物联网、想搞懂MQTT到底怎么在单片机上跑起来的朋友。1. 方案选型为什么是F103C8T6 ESP8266 阿里云这个组合1.1 板子与模块的选择逻辑STM32F103C8T6这颗芯片放在今天依然不过时原因不是性能多强而是生态太成熟。查资料、找例程、买配件都极其方便成本和容错率都很友好。C8T6有64KB Flash、20KB RAM跑一个轻量级MQTT客户端和AT指令驱动绰绰有余。要联网必须有个通信模块而ESP8266几乎是入门WiFi联网的首选淘宝几块钱一片支持TCP/IP协议栈乐鑫官方和安信可都维护AT固件不需要你懂WiFi协议细节串口发AT指令就能打通一条到云端的TCP链路。为什么不用ESP32一体板很多时候ESP32确实能一个芯片搞定全部但如果你是希望复用现有的STM32传感器逻辑、不想把采集程序重写成ESP-IDF或Arduino框架STM32 ESP8266这种方式改动最小。把ESP8266纯粹当无线透传管道STM32端原有逻辑几乎不受影响。如果项目后续要升级到4G或者NB-IoT也只要把ESP8266换成对应的透传模块STM32端代码基本不用动这种解耦思路在工业项目里非常实用。1.2 云平台为什么选阿里云可选平台不少OneNET、百度天工、自建EMQX Broker都能实现数据上报。但阿里云物联网平台的优点在于物联网平台本身提供产品、设备、Topic、物模型一整套概念从设备接入到数据存储再到可视化大屏、规则引擎链路很完整。而且公共实例下设备接入是免费的对一个学习型项目或者小规模的设备接入场景成本可以忽略不计。更关键的一点是阿里云物联网平台兼容标准MQTT协议端口1883。这意味着ESP8266不需要任何私有SDK只要按MQTT协议报文格式往TCP连接里塞数据就行。相比之下有些平台把协议封装在自家SDK里在单片机上移植难度高出不少。1.3 这套组合的典型适用场景如果你的项目属于这几类这套方案可以直接抄作业一是环境数据采集类比如温湿度、PM2.5、土壤湿度定时上报云端二是设备远程控制类比如路灯开关、水泵启停、门锁控制通过平台下发命令三是告警通知类比如传感器检测到异常值设备端上报后云端联动短信或钉钉通知四是课程设计类需要展示一个完整的物联网闭环。以上场景的共同诉求是低功耗要求不高、数据量不大、实时性要求不高只求稳定可靠地把链路跑通。2. 开工前的三件事硬件接线、CubeMX配置、阿里云平台准备2.1 硬件接线记好这六根线STM32F103C8T6的USART1我保留给调试串口打印日志用ESP8266接到USART2。这样调程序时能同时看到STM32的日志和ESP8266串口返回的数据排查问题会舒服很多。接线表如下STM32F103C8T6ESP8266模块说明PA2 (USART2_TX)RXD数据发送PA3 (USART2_RX)TXD数据接收3.3VVCC供电注意电流GNDGND共地必须接悬空CH_PD (EN)模块使能接3.3V或10K上拉悬空RST可悬空需要时接GPIO控制复位注意STM32和ESP8266都是3.3V电平可以直连不需要电平转换。但共地这根线千万别省否则串口数据全是乱码。ESP8266的供电是我最先踩的坑。WiFi发射瞬间电流能到200mA以上如果用ST-Link板载的3.3V直接供电电压一掉模块就反复重启串口一直输出乱码。最稳妥的做法是用AMS1117-3.3稳压模块单独供电或者用一个带大电容的3.3V电源轨STM32和ESP8266只要共地就行。2.2 CubeMX配置两个串口一个中断用STM32CubeMX生成工程配置如下RCCHSE选择Crystal/Ceramic ResonatorSYSDebug选择Serial Wire不然一会儿烧录后第二次找不到芯片USART1异步模式波特率115200用于调试日志USART2异步模式波特率115200开启全局中断用于ESP8266数据收发时钟树如果外部晶振是8MHz系统时钟直接拉到64MHzUSART2必须开中断因为ESP8266返回的AT应答、WIFI GOT IP提示、MQTT CONNACK、下行命令数据都需要实时接收。C8T6的RAM不大接收缓冲区用DMA 空闲中断高级一点但入门阶段可以简单用一个串口接收中断配合环形缓冲区跑这个场景完全够。生成工程后记得在main.c里实现printf重定向把fputc指向USART1调试信息才能打印出来。2.3 阿里云平台配置拿到三元组平台侧的配置流程登录阿里云控制台搜索“物联网平台”进入控制台如果提示开通直接开通公共实例。左侧菜单选择“设备管理 产品”创建一个产品。产品名称随便写如“STM32传感器”节点类型选择“直连设备”连网方式选择“WiFi”数据格式选择“Alink JSON”。在产品详情中默认Topic列表里可以看到系统预置的Topic其中两个最常用属性上报/sys/{productKey}/{deviceName}/thing/event/property/post属性设置云端下发/sys/{productKey}/{deviceName}/thing/service/property/set添加设备在“设备管理 设备”中添加一个设备输入DeviceName可以自定义比如testDevice。添加完成后控制台会生成三元组ProductKey、DeviceName、DeviceSecret。这个三元组是设备身份的凭证一定保存好。到这里平台就准备好了。后面代码里只需要把三元组填进去再配合签名算法算出MQTT密码就能建立设备到云端的通道。3. ESP8266建链从AT指令到MQTT通道打通3.1 先验证AT固件状态拿到ESP8266模块后先单独供电把它的TXD、RXD通过USB转TTL接到电脑串口助手发一个AT如果返回OK说明固件正常。芯片出厂默认波特率通常是115200不确定时可以在串口助手依次尝试115200和9600。这里有个容易被忽略的点即使模块能返回OK你也不确定固件版本是哪一个。如果固件太老或者被刷过非官方固件后续指令行为会有差异。稳妥的办法是发ATGMR查看固件版本新的版本会打印类似AT version:3.2.0.0的内容。如果是新版本就能使用官方新增的MQTT AT指令建链会省事很多如果是老版本就需要自己手动构造MQTT报文。我在下面两种方案都会讲到。3.2 方案A传统AT指令 透传模式最通用这是一条完整建链的AT指令序列AT // 测试指令返回OK ATRST // 复位模块等待约3秒 ATE0 // 关闭回显后续解析应答更干净 ATCWMODE1 // 设为STA模式 ATCWJAP你的WiFi名,你的WiFi密码 // 连接WiFi等待返回WIFI GOT IP ATCIPMUX0 // 单连接模式 ATCIPSTARTTCP,a1xxxxxx.iot-as-mqtt.cn-shanghai.aliyuncs.com,1883 // 建立TCP连接返回CONNECT OK ATCIPMODE1 // 进入透传模式 ATCIPSEND // 开始发送数据返回 符号之后STM32往USART2发送的所有字节都会被原样封装成TCP报文发到服务器。服务器返回的数据也会原样通过USART2收下来。MTQTT的CONNECT报文就在进入透传后发送。域名这里要注意阿里云公共实例的MQTT接入地址格式是{ProductKey}.iot-as-mqtt.{RegionId}.aliyuncs.com。比如产品在中国上海地域地址就是a1xxxxxx.iot-as-mqtt.cn-shanghai.aliyuncs.com。这个域名必须用域名形式去连不要自己解析成IP因为平台对IP直连有限制用了可能直接秒断。3.3 方案B新版AT固件自带的MQTT指令更省事如果ESP8266模块固件较新支持ATMQTTCONN这条指令可以完全不用手动组MQTT报文。建链序列变成ATCWMODE1 ATCWJAP你的WiFi名,你的WiFi密码 ATMQTTCONNa1xxxxxx.iot-as-mqtt.cn-shanghai.aliyuncs.com,1883,clientId,username,password之后用ATMQTTSUB订阅Topic用ATMQTTPUB发布数据非常直观。这种方式省掉了自己拼报文的麻烦代价是必须确认固件支持这些指令。如果手上的模块刷的是老版本AT固件就得先通过乐鑫官方烧录工具把新固件刷进去。我建议调试初期先走透传方案因为即使后面升级到MQTT AT指令你对MQTT报文的整体认识也更扎实遇到问题能更快定位是密码错、clientId格式错还是Topic错。3.4 阿里云设备认证的密码怎么来这里需要理解阿里云一机一密的认证原理。MQTT连接参数中clientId格式{deviceName}|securemode3,signmethodhmacsha1,timestamp0|username格式{productKey}{deviceName}password格式用deviceSecret对一段固定字符串做HMAC-SHA1计算结果转成十六进制小写字符串。签名原文内容是clientId{clientId}deviceName{deviceName}productKey{productKey}timestamp{timestamp}注意这其中的clientId部分要使用去掉管道符之后的deviceName。计算HMAC-SHA1在PC端很容易在STM32上则需要移植SHA1和HMAC实现或者使用CubeMX中间件里的mbedTLS。对大多数场景我建议调试阶段先在电脑上用Python脚本算出password把它硬编码到固件里先把链路跑通之后再去折腾动态签名。Python脚本内容很简单import hmac, hashlib productKey a1xxxxxx deviceName testDevice deviceSecret xxxxxxxxxxxxxxxx timestamp 0 clientId deviceName content clientId clientId deviceName deviceName productKey productKey timestamp timestamp password hmac.new(deviceSecret.encode(), content.encode(), hashlib.sha1).hexdigest() print(password)注意签名原文里的clientId字段用的是不带管道符的deviceName。实际踩坑经历告诉我好多人第一次把完整clientId带|securemode3...|的那一长串拿去签名结果服务器一直拒绝连接返回CONNACK code5。这个问题下文调试章节还会详细说。4. 核心代码拆解连接、上报、订阅与命令下发4.1 整体代码架构代码逻辑分成三层硬件驱动层负责USART2收发ESP8266数据AT协议层负责发AT指令、等待应答、建立TCP透传MQTT业务层负责构造报文、发送数据、解析下行命令。这里给出的是最小可用架构方便看懂和改造。变量定义和常量。#define PRODUCT_KEY a1xxxxxx #define DEVICE_NAME testDevice #define DEVICE_SECRET xxxxxxxxxxxxxxxx #define WIFI_SSID your_wifi #define WIFI_PASSWORD your_password #define MQTT_HOST PRODUCT_KEY .iot-as-mqtt.cn-shanghai.aliyuncs.com #define MQTT_PORT 1883 // MQTT连接参数 #define MQTT_CLIENT_ID DEVICE_NAME |securemode3,signmethodhmacsha1,timestamp0| #define MQTT_USERNAME PRODUCT_KEY DEVICE_NAME #define MQTT_PASSWORD xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // Python脚本算出的签名值 #define TOPIC_PROPERTY_POST /sys/ PRODUCT_KEY / DEVICE_NAME /thing/event/property/post #define TOPIC_PROPERTY_SET /sys/ PRODUCT_KEY / DEVICE_NAME /thing/service/property/set4.2 USART2接收串口数据别丢USART2接收采用中断方式每收到一个字节就存进环形缓冲区。代码里定义一个足够大的缓冲区512字节因为MQTT PUBLISH报文可能包含JSON数据太小会溢出。#define RX_BUF_SIZE 512 uint8_t rxBuf[RX_BUF_SIZE]; volatile uint16_t rxHead 0; volatile uint16_t rxTail 0; void USART2_IRQHandler(void) { if (USART_GetITStatus(USART2, USART_IT_RXNE) ! RESET) { uint8_t data USART_ReceiveData(USART2); rxBuf[rxHead] data; rxHead (rxHead 1) % RX_BUF_SIZE; } }标准库方式需要判断缓冲区满的情况而CubeMX生成的HAL库代码则是在HAL_UART_RxCpltCallback里处理。不管哪种方式核心思路都是把ESP8266返回的内容缓存下来供上层解析。4.3 AT指令驱动注意应答匹配AT指令是典型的一问一答模式发送指令后等待预期关键字符串即可。为避免阻塞太长时间我使用了一个简单的等待函数超时时间可配。uint8_t ESP8266_SendCommand(char *cmd, char *ack, uint16_t timeout_ms) { USART2_SendString(cmd); return wait_ack(ack, timeout_ms); } uint8_t ESP8266_Init(void) { ESP8266_SendCommand(AT\r\n, OK, 1000); ESP8266_SendCommand(ATE0\r\n, OK, 1000); ESP8266_SendCommand(ATCWMODE1\r\n, OK, 1000); ESP8266_SendCommand(ATCWJAP\ WIFI_SSID \,\ WIFI_PASSWORD \\r\n, WIFI GOT IP, 8000); ESP8266_SendCommand(ATCIPMUX0\r\n, OK, 1000); ESP8266_SendCommand(ATCIPSTART\TCP\,\ MQTT_HOST \, STR(MQTT_PORT) \r\n, CONNECT OK, 5000); ESP8266_SendCommand(ATCIPMODE1\r\n, OK, 1000); ESP8266_SendCommand(ATCIPSEND\r\n, , 1000); return 1; }需要注意ATCWJAP连接WiFi时如果路由器信号弱模块可能需要几秒钟超时时间要给足。ATCIPSTART用的是阿里云域名模块内部需要先做DNS解析解析也耗时间5秒只是保守值实际可能300ms内就返回CONNECT OK。4.4 手动构造MQTT CONNECT报文如果你选择透传方案这步是核心。MQTT报文由固定报头、可变报头、载荷三部分组成。CONNECT报文的固定报头字节是0x10剩余长度按MQTT规则编码小于128直接用一字节表示大于128有专门算法。可变报头包含协议名“MQTT”、协议级别0x04、连接标志0xC2、心跳时间两字节。载荷依次是clientId、username、password。uint16_t MQTT_BuildConnectPacket(uint8_t *buf) { uint16_t len 0; uint16_t clientIdLen strlen(MQTT_CLIENT_ID); uint16_t usernameLen strlen(MQTT_USERNAME); uint16_t passwordLen strlen(MQTT_PASSWORD); uint32_t remainLen 10 (2 clientIdLen) (2 usernameLen) (2 passwordLen); buf[len] 0x10; // 剩余长度这里假设小于128大于128需另外编码 buf[len] remainLen; buf[len] 0x00; buf[len] 0x04; buf[len] M; buf[len] Q; buf[len] T; buf[len] T; buf[len] 0x04; buf[len] 0xC2; // 有用户名、有密码、clean session1 buf[len] 0x00; buf[len] 0x3C; // keep alive 30秒 buf[len] clientIdLen 8; buf[len] clientIdLen 0xFF; memcpy(buf[len], MQTT_CLIENT_ID, clientIdLen); len clientIdLen; buf[len] usernameLen 8; buf[len] usernameLen 0xFF; memcpy(buf[len], MQTT_USERNAME, usernameLen); len usernameLen; buf[len] passwordLen 8; buf[len] passwordLen 0xFF; memcpy(buf[len], MQTT_PASSWORD, passwordLen); len passwordLen; return len; }CONNECT报文拼好后通过USART2发出去。几毫秒后ESP8266串口会收到服务器返回的CONNACK报文固定报头是0x20第二个字节根据结果可能是0或5。0表示连接成功5表示认证失败。实际调试时我会在串口助手里看原始数据再做判断。4.5 属性上报与心跳包属性上报实际是发送一个MQTT PUBLISH报文固定报头0x30Topic放在报文里payload是Alink JSON数据。报文构造逻辑与CONNECT类似。我写成两个函数一个是MQTT_SendPacket负责构造带Topic的PUBLISH包另一个是DataReport拼出上行的JSON。void MQTT_Publish(const char *topic, const char *payload) { uint16_t topicLen strlen(topic); uint16_t payloadLen strlen(payload); uint32_t remainLen 2 topicLen payloadLen; uint8_t buf[256]; buf[0] 0x30; buf[1] remainLen; buf[2] topicLen 8; buf[3] topicLen 0xFF; memcpy(buf[4], topic, topicLen); memcpy(buf[4 topicLen], payload, payloadLen); USART2_SendString((char *)buf); // 注意发送长度4topicLenpayloadLen } void DataReport(void) { char json[128]; sprintf(json, {\id\:\1\,\version\:\1.0\,\params\:{\Temperature\:25.5},\method\:\thing.event.property.post\}); MQTT_Publish(TOPIC_PROPERTY_POST, json); }如果长时间不发数据服务器会断开连接。所以在主循环里要周期性发送PINGREQ报文固定报头是0xC0固定报头剩余长度是0。30秒的keep alive设置下每20秒发一次心跳比较安全。4.6 订阅Topic和解析下行命令订阅Topic需要发SUBSCRIBE报文固定报头0x82。报文里要把订阅的Topic和QoS等级带上。这个函数在CONNACK之后调用具体报文构造如下void MQTT_Subscribe(const char *topic) { uint16_t topicLen strlen(topic); uint32_t remainLen 2 2 topicLen 1; uint8_t buf[128]; buf[0] 0x82; buf[1] remainLen; buf[2] 0x00; buf[3] 0x01; // packet id buf[4] topicLen 8; buf[5] topicLen 0xFF; memcpy(buf[6], topic, topicLen); buf[6 topicLen] 0x00; // QoS 0 USART2_SendData(buf, 7 topicLen); }订阅成功后服务器下发的命令会以PUBLISH报文形式从ESP8266串口进来。在STM32主循环里需要从USART2环形缓冲区里扫描接收到的字节。如果识别到固定报头0x30再往下解析Topic字段判断Topic里是否包含/thing/service/property/set。如果是说明是属性设置指令提取后面的JSON字段进行控制逻辑处理。标准做法是解析完整的MQTT PUBLISH报文结构但在轻量场景下可以写一个简单的字符串匹配函数查找params后面的内容即可。这虽然不够严谨但足够快也容易理解。4.7 主循环框架int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); ESP8266_Init(); MQTT_SendPacket(MQTT_BuildConnectPacket(mqttBuf), connLen); HAL_Delay(1000); MQTT_Subscribe(TOPIC_PROPERTY_SET); while (1) { DataReport(); // 定时上报 HAL_Delay(5000); MQTT_Ping(); // 心跳 HAL_Delay(20000); // 循环解析USART2接收缓冲区处理下行命令 ParseMQTTMessage(); } }实际项目里定时器或者系统Tick会精准一些这个框架只是把流程展现出来。5. 调试实战我踩过的坑和完整排查链路5.1 第一个晚上CONNACK code5认证失败排查第一次连阿里云TCP连接正常CONNECT报文发出后串口收到的不是CONNACK等很久也没有回应。或者偶尔收到0x20 0x02 0x00 0x05这个报文明确告诉我服务器拒绝了连接认证失败。当时第一反应是三元组填错反复核对没用。后来把clientId、username、password打印出来一份一份检查才发现问题出在password签名上。我在签名时用的content是完整clientId字符串testDevice|securemode3,signmethodhmacsha1,timestamp0|但正确做法是只用clientId标识字符部分也就是testDevice。这一差别直接导致HMAC-SHA1结果完全不同服务器自然不认。后来又发现一个细节签名转十六进制字符串时有些工具生成的是大写字母而阿里云要求小写。用Python的hexdigest()默认就是小写但要小心网上有些在线工具给出的是大写十六进制。这个坑也很隐蔽CONNACK一样返回5。排查建议先在PC上用Python脚本生成password再用MQTT.fx这类桌面工具连一次阿里云。如果MQTT.fx能连上说明平台配置和密码没问题剩下的问题就全在STM32端的报文构造上。分段排查不要一上来就在单片机上死磕。5.2 第二个晚上数据上报成功但云端看不到数据TCP链路通了CONNACK也返回0了数据也发出去了但阿里云平台设备列表的“状态”还是未激活或者日志服务里查不到上行数据。这个问题困扰了整个晚上。最后发现出在payload的JSON格式上。阿里云物联网平台对首次上行的数据要求是Alink JSON格式并且必须在产品里定义好对应的属性标识符。我在产品物模型里定义的属性名是Temperature但代码里上报时拼的字段名写成了Temp字段不匹配平台直接把这个消息丢弃了而且不在设备日志里报错只在“日志服务”里能看到一条“上行消息分析失败”的记录。正确做法是上报前先确认物模型用户自定义Topic的话不会带method字段但是默认的/thing/event/property/post这个Topic上报的数据必须带Alink格式一个标准格式如下{ id: 123, version: 1.0, params: { Temperature: 25.5 }, method: thing.event.property.post }属性名的大小写也必须和物模型一致。改完这个平台刷新一下数据立刻就有了。另外如果一直提示设备未激活也检查一下是不是设备刚创建但没发过CONNACK平台要在设备首次连上来之后才把状态变为在线激活了才能收到后续消息。5.3 透传模式下发的命令丢了怎么办透传模式有一个特性进入ATCIPSEND之后模块会把串口收到的数据直接当TCP数据发送。服务器下发的数据也会原样从串口出来。但如果你想让命令下发之后设备执行动作就有个问题STM32主循环一边在发上报数据一边在解析串口收缓冲区如果串口缓冲区处理不及时字符就可能被覆盖。我的解决办法是开一个足够大的环形缓冲区主循环每几十毫秒就去扫一次并解析。解析时注意识别一条完整PUBLISH报文的剩余长度字段根据剩余长度判断这条报文结束位置避免把下一条心跳包当命令内容解析。另外ESP8266进入透传后如果想要发送数据有个隐含时序问题第一次调用ATCIPSEND返回之后紧接着发送的数据有可能送入太早而被丢掉。稳妥做法是在进入透传后先发一个空行或随便发一个字节作为握手确认再开始发MQTT CONNECT报文。这个空数据包不会影响MQTT连接实测下来反而稳定很多。5.4 模块反复重启和乱码的排查链路如果出现ESP8266怎么发AT都没反应或者串口疯狂输出ready之类的字符多半是供电不稳导致模块重启。用万用表量模块VCC引脚正常应该在3.14V到3.46V之间。掉到3.0V以下就会重启。排查顺序我建议这样来先量电压再确认CH_PD引脚最后查串口接线。ESP8266的CH_PD是使能脚如果悬空或者被拉低模块会进入复位或不工作状态。很多人第一次玩的时候忘了接这个脚折腾半天。串口乱码除了接线和波特率还有一个容易被忽略的点STM32和ESP8266模块的地电位不一致。如果STM32用USB供电ESP8266用另外的电源适配器供电两个电源之间没有共地串口信号就没有参考地必然乱码。把两个GND短接问题就消失。5.5 阿里云免费的调试利器设备日志调试过程中最推荐打开阿里云控制台里的“日志服务”。在物联网平台的设备详情页左侧“日志服务”能实时看到设备上行、下行、连接断开的日志记录。它比串口打印更直观能直接看到平台收没收到你的数据、报文解析成功还是失败。我上面的payload字段不匹配问题就是通过日志服务里一条红色的“消息解析失败”记录定位出来的。没有这个日志全靠串口猜效率会低很多。所以平台配置到设备接入始终保持日志服务页面在后台开着设备每发一条消息这边立刻刷新看结果。5.6 补充建议新AT固件下的更优路径如果你确定手上的ESP8266固件支持ATMQTTCONN那么推进速度会快很多。连接不需要手动拼MQTT报文代码只需要发送AT指令字符串省去构造CONNECT、SUBSCRIBE、PUBLISH的麻烦。而且官方AT固件内部已经处理了重连、心跳等逻辑鲁棒性比自己拼报文更好。但这种方案的缺点是你无法看到MQTT报文细节一旦平台侧报错排查手段少一些。我的建议是学习阶段一定走一遍手动报文流程哪怕只是理解一下MQTT CONNECT报文那几行字节的含义后面遇到问题都能保住下限。生产环境或者工程交付阶段用官方MQTT AT会更省心。最后再分享一点我的实际体会整套方案跑通之后我会建议你在STM32代码里多留几个调试开关比如用宏开关控制是否打印原始日志这样后面接更多传感器、加控制逻辑时不需要来回改代码。数据上报的周期也不要设置太短阿里云公共实例虽然没有硬性限流但过于频繁的上报对WiFi模块和电源都是负担一般5秒到30秒之间比较合理。还有一个建议是给产品里定义好物模型属性之后先把属性标识符和代码里的JSON字段名做一次对照表写纸上都行能省掉很多低级错误。这套链路本身不难难的是把这些细节都照顾到希望这篇笔记能让你少走我走过的弯路。
返回列表