STM32+ESP8266+LabVIEW物联网温度采集系统设计与排坑实战
2026/9/10 0:29:34 网站建设 项目流程

简介:这是一个基于ESP8266 Wi-Fi模块、STM32F103ZET6微控制器和LabVIEW上位机的物联网温度采集项目资源包,面向嵌入式系统、物联网方向的学生及课程设计开发者,提供了一套完整的无线数据采集与可视化实现方案。资源共包含288个文件,覆盖STM32 HAL库工程源码(大量.c与.h文件)、编译生成的.o/.hex/.map等中间文件,以及LabVIEW的.vi上位机程序、PDF说明文档与工程配置文件,压缩包仅2.03MB,结构清晰便于按模块查阅。目前已有2492人学习下载。通过此包可系统掌握温度传感器数据读取、STM32串口通信、ESP8266 AT指令配网及TCP数据透传,以及LabVIEW网络通信与实时显示界面设计等关键环节;其中还包含部分带注释的C源码和硬件配置文件,非常适合进行课设复现、二次开发或作为物联网综合实训的参考样例。 做这个项目的时候,实验室刚好有一批STM32ZET6开发板闲置,现场又需要把设备间的温度实时传到办公室电脑上。一开始图省事,直接用USB转串口线延长,结果超过十米就开始乱码,最后干脆把方案改成了“STM32ZET6采集温度 + ESP8266无线上行 + LabVIEW上位机显示”。稳定跑了小半年,中间踩过的坑比想象中多:ESP8266连OneNET反复失败、LabVIEW安装后打不开、上位机收到的全是乱码。这篇文章就把完整的实现链路和排查过程记录下来,给正要入坑物联网温度采集的朋友一个参考。

1. 这套架构为什么要用“STM32采集 + ESP8266传输 + LabVIEW显示”

先讲清楚选型逻辑,因为很多新手第一个问号就是:ESP8266本身也有GPIO,为什么不能直接挂传感器读温度,非得中间塞一个STM32?

1.1 三层架构各自的分工边界

ESP8266作为一颗Wi-Fi SoC,跑AT固件或者NodeMCU固件以后,主要优势在网络协议栈和无线收发上,GPIO的实时控制能力、定时器的确定性、多路传感器的管理能力都比较弱。如果你只用它读一个DS18B20还好,一旦系统里再挂几路模拟量传感器、需要做滤波算法、甚至要控制继电器,ESP8266的资源和开发效率就会很吃力。

STM32ZET6这边资源就很充裕:Cortex-M3内核、64KB RAM、512KB Flash,USART、SPI、I2C、ADC一应俱全。用它做主控,温度传感器采集、数据预处理、协议组帧都跑得稳稳当当,还能保留后续扩展其他传感器的余地。

LabVIEW则承担了“人机交互层”的角色,它的强项是快速搭建可视化界面——实时波形图、温度表盘、数据落盘、历史回放,这些能力如果用C#或者Qt写,工作量会成倍增加,而LabVIEW拖几个控件就能搞定。

1.2 为什么通信链路选“TCP透传”而不是“MQTT”

原方案里ESP8266要连OneNET平台,很多人会推荐直接走MQTT协议。我最终没用MQTT,而是让ESP8266工作在透传模式,把数据通过TCP直接推给局域网里的LabVIEW上位机,原因很简单:

  • LabVIEW对TCP的支持是原生且成熟的,TCP Listen.viTCP Read.vi几个节点就能搞定,不需要额外安装工具包。
  • 走MQTT必须有一个MQTT Broker(比如OneNET、巴法云),链路变长,还要处理QoS、心跳、topic订阅问题,对“实时看个温度”这种需求来说有点过度设计。
  • 透传模式下ESP8266相当于一个“无线串口”,STM32串口发什么,LabVIEW就收什么,数据格式完全由自己定义,排错也直观。

如果你想对接云平台做远程查看,那就保留OneNET那条链路;如果像我这个项目一样,人就在局域网内,用TCP透传是最务实的方案。

2. 硬件接线与STM32ZET6温度采集端实现

2.1 传感器选型:DS18B20单总线方案

温度传感器我用了DS18B20,主要是看中它三个特点:单总线协议,只占一个GPIO;数字输出,不需要ADC校准;测温范围-55℃到+125℃,实验室环境完全够用。

STM32ZET6这边用PB1作为DS18B20的数据引脚,接线方式是:DS18B20的VCC接3.3V,GND接GND,DQ接PB1,同时在DQ和VCC之间接一个4.7kΩ上拉电阻。这个上拉电阻很容易被忽略,但少了它,单总线在长线传输时读到的数据经常是0xFF或者随机值。

2.2 单总线时序的坑

DS18B20的时序要求很严格,初始化、读时隙、写时隙都是微秒级的操作,建议直接在STM32的HAL库里做延时函数。很多人在F103系列上遇到的“能复位但读不了ROM”问题,大概率是延时精度不够,比如用了HAL_Delay(1)这种毫秒级延时去凑微秒时序,必挂。

我用自己的代码稳定运行的时序实现如下(简化版,核心是微秒级延时和时序分段):

// 复位DS18B20 uint8_t DS18B20_Reset(void) { uint8_t presence = 0; GPIO_InitTypeDef GPIO_InitStruct = {0}; // PB1配置为输出 GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 开漏输出 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); delay_us(480); // 拉低480us HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); delay_us(70); // 释放总线等待70us // 切换到输入模式读取存在脉冲 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); presence = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); delay_us(410); return presence; } // 读取一位 uint8_t DS18B20_ReadBit(void) { uint8_t bit = 0; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); delay_us(2); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); delay_us(10); bit = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); delay_us(50); return bit; }

注意:DS18B20的DQ引脚在读取阶段需要配置成输入模式,写入阶段配置成开漏输出模式。很多教程里只配置一次GPIO方向,导致读写时序不完整,数据全是0xFF或者0x00。

2.3 如何规划串口与ESP8266的接线

STM32ZET6的USART1用于和ESP8266通信,引脚分配是PA9(TX)接ESP8266的RXD,PA10(RX)接ESP8266的TXD,GND必须共地。这个“共地”是新手最容易漏的,不共地的话,串口电平参考点不一致,数据收发时好时坏。

波特率我设成115200,8N1,实测在2米以内的杜邦线连接下非常稳定,不需要刻意降低波特率。

如果调试时发现ESP8266收不到数据,先用USB转TTL工具单独测试ESP8266,确认它能响应AT指令,再去排查STM32端的串口配置。这样做的好处是快速隔离问题域,不会两边互相猜。

3. 数据帧格式设计:让上位机每次都能正确解析

3.1 为什么不能直接发裸温度值

很多初学者的做法是STM32直接把温度的浮点数通过串口发出去,LabVIEW端收到什么就显示什么。这在纯串口直连时勉强可用,一旦经过ESP8266透传,问题就来了:Wi-Fi环境下数据会分包、粘包,如果接收端不按帧解析,数据流就乱了。

正确的做法是设计一套带帧头、长度、数据和校验的通信协议。我的帧格式如下:

字段长度说明
帧头0xAA1字节固定值,用于识别帧起始
帧头0x551字节固定值,与0xAA组成双重帧头
数据长度1字节后面数据的字节数
温度整数部分1字节有符号数,负温用补码
温度小数部分1字节无符号数,0~99
校验和1字节前面所有字节求和取低八位

3.2 负温度处理:很多人的“隐形炸弹”

温度低于零度时,如果直接强制类型转换成uint8_t,会得到一个很大的正数,上位机解析出来的温度就变成了两百多度。这是这个项目里最典型的错误之一。

处理方式是在STM32端判断温度正负,负温时整数部分用补码保存(例如-5℃,存0xFB),上位机解析时先判断最高位,如果是1就先减256得到负数,再拼接小数部分。

void SendTemperature(float temp) { uint8_t buf[6] = {0}; int8_t temp_int = (int8_t)temp; // 取整数部分 uint8_t temp_dec = (uint8_t)((temp - (int16_t)temp) * 100); // 取小数部分 buf[0] = 0xAA; buf[1] = 0x55; buf[2] = 0x02; buf[3] = (uint8_t)temp_int; buf[4] = temp_dec; buf[5] = buf[0] + buf[1] + buf[2] + buf[3] + buf[4]; // 校验和 HAL_UART_Transmit(&huart1, buf, 6, 100); }

帧头为什么用两个字节而不用一个?因为温度数据里可能出现0xFF、0xAA这样的值,单字节帧头很容易误触发。双帧头加校验和,基本可以杜绝解析错位的问题。

4. ESP8266组网与OneNET连接失败的排查链路

4.1 ESP8266的AT固件配置步骤

我用的是ESP8266-12F模块,刷的官方AT固件,通过串口助手发送指令验证。连接逻辑很简单,但指令顺序不能乱:

ATE0 # 关闭回显,减小串口数据干扰 AT+CWMODE=1 # Station模式,连接外部路由 AT+CWJAP="WiFi名称","WiFi密码" # 连接热点 AT+CIPSTART="TCP","192.168.1.100",8080 # 连接LabVIEW上位机TCP服务器 AT+CIPMODE=1 # 进入透传模式 AT+CIPSEND # 开始发送数据

注意AT+CIPSTART里的目标IP和端口,是LabVIEW上位机所在电脑的局域网IP。如果你要让ESP8266连OneNET,这里的IP和端口要换成平台的接入地址,而不再是电脑的IP。

4.2 连不上OneNET的排查顺序

热词里“esp8266连接onenet失败”特别多,我梳理一下自己当时的完整排查链路:

第一步:确认ESP8266本身能不能连上Wi-Fi。直接用串口助手发AT+CWJAP,看返回WIFI GOT IP。如果一直卡在WIFI DISCONNECT,先检查热点名称和密码,再把ESP8266靠近路由器一点。ESP8266的板载天线增益有限,隔两堵墙很容易连不上。

第二步:确认OneNET平台的设备配置。这里有两个常见坑:一是设备没激活,OneNET新版平台创建设备后需要设备端上报一次数据才能变为“在线”状态;二是接入协议选错,如果你在OneNET上创建的是“HTTP协议”设备,ESP8266却用TCP去连,必然失败。我的建议是:既然用了TCP透传,直接对接本地LabVIEW,不然就统一用MQTT协议对接OneNET,别混着来。

第三步:确认接入地址和端口。OneNET的接入地址会根据协议走不同的端口,MQTT是183.230.40.39:6002(旧版),新版平台推荐用域名接入。用AT+CIPSTART="TCP","183.230.40.39",6002测试,如果返回CONNECT OK说明TCP链路通,剩下的就是设备鉴权校验了。

第四步:设备鉴权信息。旧版OneNET用的是设备ID和APIKey,新版用的是产品ID、设备ID、鉴权信息。这些参数必须和固件里的代码完全一致,哪怕多一个空格或者换行都会导致平台拒绝接入。最好在PC上用MQTT客户端工具先模拟一次设备接入,确认参数没问题,再让ESP8266去连。

4.3 ESP8266丢包的问题定位与缓解

“esp8266丢包”是另一个高频热词。我从实际使用中的经验看,至少有三个层面会导致丢包:

第一个层面是供电。ESP8266在Wi-Fi发射瞬间电流可以达到300mA甚至更高,如果模块的VCC直接从STM32开发板的3.3V引脚取电,而那个引脚又是由板载稳压器供的,电流余量不足时模块会自动重启或者发射功率下降,表现为数据时好时坏。解决方法是给ESP8266单独配一个AMS1117-3.3稳压芯片或者用带大电容的供电模块,在VCC和GND之间并联一个100μF电解电容加一个0.1μF陶瓷电容。

第二个层面是串口缓冲溢出。STM32串口发送频率高、数据量大,而ESP8266的串口缓冲区就那么大,来不及转发就会丢弃。缓解措施有两个:一是降低上报频率,温度采集这种场景一秒一次完全够了,没必要博尔特式的猛发;二是在STM32端把数据包拆分,每次不大于256字节。

第三个层面是Wi-Fi本身的干扰。2.4GHz频段环境复杂,实测下来,路由器旁边如果有USB 3.0设备、微波炉、蓝牙设备,丢包率会明显上升。把ESP8266的天线位置调整一下,尽量远离金属物体,丢包率能下降不少。

5. LabVIEW上位机实现:TCP接收、波形显示与数据落盘

5.1 LabVIEW安装容易踩的坑

先说一个很多人都遇到过的问题:LabVIEW安装失败或者打开报错。从经验看,90%跟安装路径有关系。LabVIEW的默认安装路径是C:\Program Files (x86)\National Instruments\,这个路径本身没问题,有问题的是很多人改成了带中文的路径,比如D:\软件\LabVIEW2018,这样的路径会导致运行时引擎找不到配置文件,报错弹出一堆“无法定位程序输入点”之类的对话框。

我的建议是:装LabVIEW时,安装目录直接保持默认或者用纯英文路径;2018版之后还需要装对应的Runtime Engine,如果电脑上装了多个版本的LabVIEW,运行时引擎版本和开发版版本不一致,也会出莫名其妙的错误。

5.2 上位机的整体程序框架

LabVIEW上位机的核心逻辑是:建立一个TCP服务器,监听指定端口,等待ESP8266连入,然后循环读取数据,按协议解析,把温度值显示在波形图上并写入文件。

框图逻辑大概是这样:

  • 使用TCP Listen.vi创建TCP服务器监听指定端口(和ESP8266里AT+CIPSTART用的端口一致)。
  • 当ESP8266连入以后,外层While循环里调用TCP Read.vi读取字节数组。
  • 把读到的字节数组按帧头0xAA、0x55进行同步搜索,找到帧头后按长度字段截取完整一帧。
  • 校验和正确后,拆出温度整数和小数,拼成浮点数,送入波形图Waveform Chart显示。
  • 同时使用Write To Measurement File这个Express VI把数据写入LVM文件或者TDMS文件。

5.3 波形图数据类型的坑:为什么波形图上全是乱码

热词里有一条“labview波形图改为u16”,这个问题的根源在于:LabVIEW的波形图控件默认接受的输入是Double类型,如果你把串口读到的原始字节数组直接连到波形图上,LabVIEW会把这个一维字节数组当成一维数值数组显示,结果呈现出的是一条杂乱无章的曲线,没有任何意义。

正确的做法是把字节数组先经过解析转换成单个浮点数,再让这个浮点数进波形图。如果你拿到的数据本来就是U16或者U8编码的数字量,需要先用“数值→字符串”的转换节点处理,再显示。

特别提醒:LabVIEW里的“字节数组转换成字符串”“字符串转数值”这几个节点,选错字节序(大小端)是经常踩的坑。比如STM32发送的浮点数4字节是大端排列,LabVIEW默认按小端解析,读出来的数值会完全不一样。用“Unflatten From String”节点时,一定要先确认数据的字节序设置。

5.4 Write To Measurement File的通道名称设置

热词里提到“labview express vi 写入测量文件 设置通道名称”,这个Express VI确实需要设置好通道名称才能让数据文件里的列名有实际意义。具体操作是:双击Write To Measurement File,在“通道名称”那一栏填入“温度1”、“温度2”之类的名称,和前面采集的数据一一对应。

文件格式的选择上,我用的是TDMS格式,读取速度快,而且LabVIEW生态内后续分析方便。如果你想导出来用Excel打开,那就选LVM格式,它是文本格式,但文件体积大、读取慢。温度和信号数据量不大的场景,LVM更友好。

6. 联调阶段的数据异常分析与处理

6.1 Loopback测试:先隔离再联调

整个系统联调的时候,我的调试顺序是这样的:先用USB转TTL直接将STM32和PC的串口助手对接,确认STM32发出来的数据帧是完整、正确的。接着用ESP8266模块连接电脑调试助手的TCP Server,手动发送测试帧,确认无线链路通。最后才把STM32和ESP8266对接起来,全链路跑通。

这个顺序看似多此一举,实际上能在问题出现时迅速缩小范围:如果第一步就发现数据不对,问题在STM32端;如果第一步正常第二步异常,问题在ESP8266的透传配置;如果前两步都正常第三步异常,重点查串口波特率和供电。

6.2 半包和粘包现象的处理

TCP透传模式下,ESP8266可能会把STM32发来的完整一帧数据拆成两次发出来,也可能把两帧数据合成一次发出来。这意味着LabVIEW端不能简单地“读取一次就认为是一帧”,必须用缓冲区把读到的数据缓存起来,然后在缓冲区里搜索帧头、按帧头拆包。

我在LabVIEW里用的是生产者消费者模式:生产者循环不断TCP Read并写入队列,消费者循环从队列里取出数据,在数据缓冲中搜索帧头并解析。这样做的好处是即使网络抖动导致数据延迟,也不会遗漏数据。

6.3 数据出现“野值”的处理思路

即便带了校验和,偶尔还是会碰到解析出来的温度一下子跳到一百多度,然后又恢复正常的“野值”。排查下来有两类原因:一是Wi-Fi环境恶劣,数据在传输中发生比特翻转,校验和能拦住一部分;二是LabVIEW端TCP Read读到了旧的残留数据,导致帧解析错位。

我的处理方式是:校验和不通过直接丢弃整帧,不参与显示和落盘。宁可少一帧数据,也不能让一个错误数据污染曲线。另外,LabVIEW端可以加入限幅滤波,温度变化率超过一定阈值(比如每秒超过10℃)的一律视为无效数据,这在工业现场是常用的抗干扰手段。

6.4 关于ESP8266固件的选择建议

如果你用的是ESP8266裸模块,需要自行烧录AT固件,热词里的“esp8266烧录固件步骤”、“esp8266 flasher工具”说的就是这个事。烧录时注意:ESP8266进入下载模式需要把GPIO0拉低,然后上电,用ESPFlashDownloadTool或者esptool.py烧录。

我推荐直接使用带有AT固件的ESP-01或ESP-12F成品模块,出厂自带固件,省去很多麻烦。如果你刷了NodeMCU固件或者MicroPython固件,那AT指令这套就不适用了,需要改用Lua或者Python脚本,链路会复杂很多。对于本文这个项目来说,AT固件是学习和排错成本最低的选择。

7. 稳定运行的关键参数与后续扩展

这个项目跑通以后,我把关键参数固化下来了,这里直接分享出来供你参考:

  • 温度采集周期:1秒一次,STM32每隔1秒读一次DS18B20并通过串口发送。
  • 串口参数:115200,8N1。
  • TCP端口:8080,LabVIEW监听,ESP8266主动连接。
  • 数据帧格式:6字节固定长度,带双重帧头和校验和。
  • LabVIEW波形图刷新方式:每次解析出一帧有效数据就更新一次波形。

如果你要把这个系统扩展成多路温度采集,思路是:STM32在帧头后加一个设备ID或通道ID字段,上位机根据通道ID区分数据来自哪个传感器;如果节点数量多,每个STM32节点配一个ESP8266,上位机用多个TCP端口监听,或者走MQTT通过topic做消息分发。

这个项目让我最深刻的体会是:物联网项目的难点通常不在单点技术上,而在整条链路的可靠性设计上。STM32端的代码几天就能写完,ESP8266的配置小半天就搞定,但真正让系统稳定跑起来、不出乱子,靠的是协议设计、供电设计、异常处理这些看似不起眼的部分。最后再分享一个习惯:联调过程中每改一次串口波特率、每换一次IP地址,一定要用串口助手和网络调试助手先单独验证,再组合起来测,不要怕麻烦,这一步至少能帮你省下三分之二的排错时间。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询