十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32+ESP8266+OneNet:物联网数据上报完整指南

STM32+ESP8266+OneNet:物联网数据上报完整指南 简介面向ESP8266与STM32F103ZET6开发初学者的智能物联实战资料演示将DHT11温湿度数据通过ESP8266模块上传至OneNET云平台。内容涵盖器件选型、引脚接线说明ESP8266-01S与正点原子模组均适用、云端产品与设备创建、固件烧录方法、实物演示及常见问题汇总帮助读者快速打通“单片机—Wi-Fi模块—云平台”的完整链路。资源包为RAR压缩格式共289个文件、58.82MB以C语言工程源文件h/c、编译中间文件o/d/axf、固件镜像bin、烧录工具exe及说明文档pdf/txt为主另包含工程配置、界面截图等辅助文件便于对照Keil工程直接学习、调试或二次开发。目前已有497人学习下载适合具备基础C语言和单片机知识、希望上手OneNET物联网平台的学生与开发者整包既可作为课程设计或毕业设计的参考也可作为入门智能家居、远程监测项目的起步模板。1. ZET6 把数据交给 ESP8266再由 ESP8266 POST 到 OneNetB站搜「ESP8266 上传 OneNet ZET6」能刷出一批播放量不低的视频评论区出现频率最高的问题是数据没上去、平台看不到点、串口助手卡在某条 AT 指令。这套方案的本质是一条完整链路——STM32F103ZET6 负责采集和组包通过串口把 JSON 交给 ESP8266ESP8266 连上路由器后以 HTTP POST 把数据写入 OneNet 的数据点最后在网页端画成折线图。适合三类人做课程设计或竞赛项目、需要把单片机数据搬上云的学生工位上想远程看设备状态的工程师以及想搞懂 AT 指令与 HTTP 上报如何衔接的初学者。真正的难点不在代码本身而在每一层的接通顺序和参数匹配接下来就从这两块板子的分工说起。2. 先分清楚 ZET6 与 ESP8266 的职责采集归单片机上云归 ESP82662.1 为什么需要两块板子ZET6 管实时采集ESP8266 管网络协议STM32F103ZET6 是 512KB Flash、64KB RAM 的高容量型号串口多、ADC 通道多、定时器资源丰富适合干确定性强的活定时采样、跑 DHT11 之类的单总线时序、处理本地逻辑。ESP8266 的价值在射频和协议栈出厂固件里已经把 TCP/IP、Wi-Fi 连接、DNS、Socket 都封装成了 AT 指令你不需要关心数据链路层。但 ESP8266 的 GPIO 少裸模块上跑完整应用代码的体验并不好尤其当你需要同时管 ADC、按键、显示时引脚和内存都不够用。把它们组合在一起就成了物联网里最经典的「主控 透传网卡」架构这也是标题里同时出现 ZET6 和 ESP8266 的原因。另有一种常见做法是给 ESP8266 刷 Arduino 固件让模块自己采集传感器再上报STM32 只在旁边打下手。这套方案在很多 ESP8266 入门教程里很流行但你的项目已经以 ZET6 为主控再引入一套 Arduino 工具链等于把两个平台的学习曲线叠在一起排查问题时要同时排查两套栈。我的建议是ESP8266 在这里就当一个外设用 AT 指令控制代码量最少哪层出问题也一眼能看出来。2.2 接线与电平匹配ZET6、ESP8266 和电源的接法先用表格确定物理连接。以 USART2 为例PA2 发、PA3 收STM32F103ZET6ESP8266 模块PA2 (USART2_TX)RXDPA3 (USART2_RX)TXDGNDGND3V3VCC3V3 经 10kΩ 电阻EN / CH_PD整条链路最容易出问题的是供电。ESP8266 在 Wi-Fi 发射瞬间电流可以达到 300mA 级别如果 3.3V 电源纹波大、掉压明显模块会不断复位表现就是串口第一句 AT 都没有回复。ZET6 开发板上的板载 3.3V LDO 通常是为单片机设计的余量不大我一般给 ESP8266 单独用一个 AMS1117-3.3从 5V 取电再把两边的 GND 接在一起。EN/CH_PD 在 ESP-01 这类模块上必须拉高很多模块出厂已内部上拉但如果你用的是裸模块或二手板建议显式接一个 10kΩ 到 3V3避免上电后模块不工作。电平方面ZET6 开发板正常以 3.3V 供电时PA2/PA3 的输出高电平就是 3.3V与 ESP8266 兼容直连没有问题。如果你手上是 5V 单片机或者中间还串了 TTL 转 USB 模块才需要额外加电平转换或电阻分压否则长期高压可能损伤 ESP8266 的 RX 引脚。2.3 先用四条 AT 指令验证 ESP8266 能连上路由器在写任何 STM32 代码之前先把 ESP8266 接到 USB-TTL 上用串口助手手动发一遍下面的序列确认模块本身是好的ATE0 ATCWMODE1 ATRST ATCWJAP你的SSID,你的密码 ATCIFSRATE0 关闭命令回显让后续输出更干净ATCWMODE1 把模块设为 Station 模式也就是只作为设备去连接路由器而不是自己开热点改完模式后必须重启一次所以紧接着发 ATRST。ATCWJAP 带上你的 Wi-Fi 名称和密码返回 WIFI CONNECTED 再出现 OK表示联网成功注意这一步要等一两秒不要看到 OK 就去建 TCP 连接。ATCIFSR 显示模块拿到的 IP 地址能看到 192.168.x.x 这类地址就说明路由器已经给模块分配了地址。如果 AT 指令完全没反应先检查两件事波特率是不是 115200部分旧固件是 9600EN 脚和供电是不是正常。如果 ATCWJAP 一直返回 ERROR多半是路由器开了 5GHz 频段——ESP8266 只支持 2.4GHz手机热点也要手动切成 2.4GHz 再试。3. OneNet 云平台接入生成 APIKey 与数据流的三个准备步骤3.1 在控制台创建产品和设备老版多协议接入的 HTTP 通道OneNet 要接收数据先得有产品和设备。登录云平台后找一个叫「多协议接入」的入口不同版本控制台布局不太一样首页找不到就站内搜索这个关键词选择 HTTP 协议创建一个产品。产品名随意比如“ZET6温度上报”。然后在产品下添加设备平台会分配一串数字格式的设备 ID后面所有上报请求都要用到这个 ID。接着生成 APIKey在设备或产品管理页找到 APIKey 菜单添加一个授权对象选刚才那台设备不要选产品级别。设备级 APIKey 只对单台设备有效即使将来泄露影响范围也被限制在一台设备上。这里说明一下平台现状。OneNet 后来的新平台主推 MQTT 和一套新的设备接入体系但很多入门的 AT 指令教程仍然基于老版多协议接入的 HTTP 接口原因是这条链路最短不需要理解 topic、clientId、心跳这些概念一条 POST 就能把一个数据点写进去。如果你看的是老视频控制台入口可能已经挪了位置但接口路径 api.heclouds.com 和 api-key 请求头仍然有效。遇到控制台页面不一致时优先在平台文档里搜「HTTP 数据点」来对齐字段。3.2 数据流模板先建好 temp 和 hum避免类型推断的坑数据流可以理解为一台设备的“传感器字段”。OneNet 的机制是你用 POST 上传一个带 id 的数值如果这个数据流不存在平台会自动创建出来。但自动创建的类型是按第一次上报的值推断的第一次上传的是整数 26平台就建一个 int 类型的数据流之后你想传 26.5要么被截断要么直接报错网页端折线图也会显示成锯齿状整数台阶。这种“上传成功但数值不对”的现象非常容易误导人排查半天往往才发现是类型问题。所以在上传之前先到设备的「数据流模板」里手动添加两个数据流名字叫 temp 和 hum类型选 float。这一步看起来多余但能省掉后面一整类问题。模板里加好之后上报的 JSON 里 id 必须和模板名字一字不差否则平台仍然会按新数据流自动创建绕过了你预建的模板。提示先建模板再上传能避免自动创建数据流导致的类型错误这也是「上传成功但折线图不对」最常见的原因。3.3 上报接口与请求头curl 先验证再交给单片机在动板子之前先用电脑上的 curl 验证一遍云端配置把设备 ID 和 APIKey 填进去curl -X POST \ http://api.heclouds.com/devices/1234567890/datapoints \ -H api-key: YOUR_API_KEY \ -H Content-Type: application/json \ -d {datastreams:[{id:temp,datapoints:[{value:26.5}]}]}这里 -H 指定了两个请求头api-key 是 OneNet 用来鉴权的凭证Content-Type 声明内容为 JSON。请求体最外层是 datastreams 数组每项代表一个数据流id 是你在模板里创建的字段名datapoints 里放一个或多个数据点value 就是数值本身。下面的表格列出了 body 里常用字段的含义字段作用说明id数据流名称必须与模板一致不能带空格value数据点的值支持 float、int、string 等at数据点时间可选不填则使用平台服务器时间datapoints数据点数组一次可以上报多个值按顺序排列如果一切正常返回体是 {errno:0,error:succ}。errno 为 0 表示成功非 0 时按 error 字段的文本内容排查最常见的两类是 api-key 不对和 device_id 写错。curl 这一步能通云端就算准备好了后面调单片机时不用再怀疑云平台配置。3.4 设备 ID、APIKey 与请求头的三个高频错误这三个错误几乎覆盖了所有“云端配置没问题却发不出去”的场景。第一是把设备 ID 写成产品 ID 或者别的数字OneNet 按设备路由数据点ID 错了返回的错误提示有时并不明显建议在控制台设备列表里复制而不是手敲。第二是用 Authorization 替代 api-key老教程里经常混用这两种写法但旧版 HTTP 接口认的是 api-key 这个字段名换掉之后就返回鉴权失败。第三是 Content-Length 与实际 body 不一致这在 curl 里不存在因为工具会自动算但在 STM32 代码里需要手动计算等到了第 4 章会专门讲这个坑。4. 核心实现STM32 拼 HTTP 报文ESP8266 经 CIPSEND 上传4.1 透传与非透传为什么上报场景推荐 CIPSENDlengthESP8266 的 AT 固件提供两种发送 TCP 数据的方式。透传模式由 ATCIPMODE1 开启进入后数据直接发出退出时需要发一串 号固件版本不同时序要求也不一样有时还得配合延时。这种模式的优点是省去每次发送的长度计算缺点是一旦退出时序不对模块就卡在透传状态后续 AT 指令全部失效只能复位重来。非透传模式则要求每次发送前执行 ATCIPSEND长度模块回一个 提示符你发完指定长度的字节后自动返回 SEND OK整个流程有明确的开始和结束不用手动退出。对于周期上报温湿度这类短连接场景我更推荐非透传代码量也更少。下面的表格是两种方式的直观对比对比项透传模式非透传模式发送前无需长度ATCIPSEND长度发送结束需自行退出自动返回 SEND OK代码复杂度低但状态难控略高但行为确定适合场景长连接持续上行周期短连接上报4.2 核心代码拼报文、发 CIPSEND、等 OK 与 succ下面的代码是 STM32 侧最小可用的上报函数骨架假设 USART2 连接 ESP8266串口中断把收到的字节以字符串形式持续写入 uart2_rx_buf末尾补 \0void uart2_send(const char *s) { while (*s) { while (!(USART2-SR USART_SR_TXE)); USART2-DR *s; } } uint8_t wait_resp(const char *expect, uint32_t ms) { uint32_t start uwTick; while (uwTick - start ms) { if (strstr((char *)uart2_rx_buf, expect)) { return 1; } } return 0; } void onenet_post(float temp) { char body[64]; char req[256]; memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf)); /* 避免上次残留干扰匹配 */ sprintf(body, {\datastreams\:[{\id\:\temp\,\datapoints\:[{\value\:%.1f}]}]}, temp); sprintf(req, POST /devices/%s/datapoints HTTP/1.1\r\n Host: api.heclouds.com\r\n api-key: %s\r\n Content-Type: application/json\r\n Content-Length: %d\r\n \r\n %s, DEVICE_ID, API_KEY, (int)strlen(body), body); uart2_send(ATCIPSTART\TCP\,\api.heclouds.com\,80\r\n); if (!wait_resp(CONNECT OK, 3000)) { uart2_send(ATCIPCLOSE\r\n); return; } char cipsend[32]; sprintf(cipsend, ATCIPSEND%d\r\n, (int)strlen(req)); uart2_send(cipsend); if (!wait_resp(, 1000)) return; uart2_send(req); wait_resp(SEND OK, 3000); wait_resp(succ, 3000); }先看 body 和 req 两个缓冲区body 只放数据流 JSONreq 把 HTTP 请求头和 body 拼成完整报文。拼报文时行尾必须用 \r\n尤其是请求头和 body 之间的空行少一个 \r\n 都会让 OneNet 认为请求没结束。Content-Length 用 strlen(body) 计算指的是 body 的字节数不包含结尾的 \0这里最常踩的坑是用 sizeof(body)那会把整个缓冲区大小 64 算进去服务器会一直等剩下的数据直到超时。CIPSEND 后面的长度是完整 req 的字节数和 Content-Length 不是同一个值别混。注意Content-Length 和 CIPSEND 的参数都要用 strlen 动态计算不要用 sizeof 或者写死的魔数。函数开头清一次串口缓冲是为了避免上一次上报残留的 OK、SEND OK 干扰这次的匹配。wait_resp 用 strstr 在缓冲里找目标字符串找到就返回找不到就超时返回 0。每次上报前先建立 TCP 连接失败时主动发 ATCIPCLOSE 关闭连接避免下一次 CIPSTART 返回 ALREADY CONNECTED。整个流程可以理解成CIPSTART 建链路、CIPSEND 告知长度、发送报文、SEND OK 表示本地发出、succ 表示云端接收。4.3 从复位到数据可见的完整 AT 指令时序把上面的 C 代码翻译成串口日志就是下面这一串往返。如果你用 USB-TTL 接 ESP8266 手动调试也应该能看到一致的节奏AT ATE0 ATCWMODE1 ATRST # 等待重启完成出现 ready 再继续 ATCWJAP你的SSID,你的密码 # 返回 WIFI CONNECTED / OK ATCIPSTARTTCP,api.heclouds.com,80 # 返回 CONNECT OK ATCIPSEND281 # 返回 # 粘贴完整 HTTP 请求含请求头和 body # 返回 SEND OK # 返回 {errno:0,error:succ}注意 ATCIPSTART 的返回CONNECT OK 表示 TCP 链路建立成功如果返回 DNS FAIL多半是路由器 DNS 有问题或者域名写错如果返回 ALREADY CONNECTED说明上一次连接没关干净需要在代码里先发 CIPCLOSE。ATCIPSEND 后如果迟迟不出现 提示符不要盲发数据先排查链路状态。发送字节数和 CIPSEND 参数不一致时模块表现比较怪异发少了连接挂起发多了多余字节会被当作下一条 AT 指令处理日志里会出现一段乱码。4.4 没有传感器也能跑先让链路通再谈数据精度很多初学者卡在传感器时序上其实这一环可以暂时放掉。ZET6 的 ADC 随便接一个电位器读一个 0 到 4095 的整数缩放成 0.0 到 100.0 的浮点数直接塞进 onenet_post 就能把链路打通。等 OneNet 网页端的折线图出现变化再去替换真正的温湿度传感器。链路不通时数据来源是什么根本不重要链路通了再回头按 DHT11 或 SHT30 的数据手册把采集部分补上整个调试难度会小很多。5. ESP8266 数据没上报到 OneNet从串口日志逐层定位两步缩小故障范围5.1 第一步把 ESP8266 单独拆下来验证当数据始终没有出现在 OneNet 时第一个动作不是改代码而是把物理链路拆开。用 USB-TTL 接住 ESP8266在串口助手里手动把 4.3 节的指令序列重发一遍如果手动能成功说明问题出在 STM32 程序如果手动也失败那问题在 Wi-Fi 或云平台配置和单片机代码毫无关系。这一步能把排查范围缩小一半也能避免在代码里加各种 debug 打印却看不到真实网络交互的尴尬。5.2 第二步对照串口日志分级表定位把串口助手里看到的现象和故障层面对应起来按下面这张表逐条核对串口现象故障层优先检查项AT 无任何回复模块本身供电电流、EN 引脚、波特率迟迟不出现 WIFI CONNECTED路由器2.4GHz 频段、密码、信号强度CONNECT OK 不出现TCP/DNS域名是否完整、路由器外网状态SEND OK 后没有 succHTTP 内容api-key、device_id、Content-Length有 succ 但折线图不对数据流模板类型是否 float、字段名是否一致这张表基本覆盖了入门阶段能遇到的所有断点。特别注意前两行AT 无反应优先查电源ESP8266 对供电敏感瞬间掉压会表现为“时好时坏”连不上路由器先查频段ESP8266 不支持 5GHz手机热点默认开 5GHz 就会一直失败。5.3 三类容易忽略的边界情况Content-Length 和 CIPSEND 都用 strlen 计算不要用 sizeof在缓冲区以外的地方多一个 \0 不影响 strlen但如果你误用了数组长度服务器端就会一直等待剩余字节。上报周期不建议小于 5 秒OneNet 对数据点写入有限流更重要的是每次上报都涉及一次完整的 TCP 握手和 HTTP 解析周期太短除了给自己制造日志噪音没有任何收益。还要注意 HTTP 响应体不一定和 SEND OK 同时到达wait_resp 的等待时间要留够不要在收到 SEND OK 后立刻关 socket。5.4 工程化的小修改APIKey 不要留在固件里开发阶段把 APIKey 写成宏是图省事但如果视频会拍屏幕、代码会发到仓库这个习惯就得改。简单做法是把 DEVICE_ID 和 APIKey 写进 ZET6 Flash 的某个固定扇区上电时读出来拼进 req 字符串代码仓库里只保留占位符。设备多了之后每个设备单独创建 APIKey 而不是共用一个产品级密钥这样即使某台设备被反读固件影响的也只是那一台设备的数据。本文还有配套的精品资源点击获取
返回列表