拓冰建站拓冰建站
首页 / 资讯中心 / 正文

51单片机与LabVIEW温度监测系统:I2C采集与串口通信实战

简介这是一套以51单片机和LabVIEW为核心的温度监测系统资料适合电子、自动化、计算机等专业学生以及嵌入式入门开发者用于完成课程设计或理解单片机与上位机联调方法。压缩包共29个文件大小约444KB包含LabVIEW的vi程序、C语言源文件、头文件、HEX烧录文件、工程配置文件以及用户管理、温度记录和报警记录三个数据库完整覆盖数据采集、通信、显示、存储与报警等模块。已有369人学习。资源内可对照单片机端C代码主程序、温度采集、LCD显示理清传感器驱动与界面逻辑也可结合LabVIEW端主监测界面、通讯设置和数据查询程序学习串口通信、实时曲线显示与数据库管理。工程与烧录文件齐全便于直接编译验证适合作为本科毕设或创新项目的参考原型。1. 把温度监测系统拆成两条线51单片机的数据采集与LabVIEW的界面呈现在搭建温度监测系统时很多工程师容易一头扎进上位机界面的控件摆放里忽略了底层串口报文是否规整、数据帧有没有 CRC 校验。基于单片机和 LabVIEW 的温度监测系统本质上要解决两件事让 51 单片机把温度传感器读到的值按约定帧格式通过串口送出来让 LabVIEW 作为上位机把这串字节流解析成可读的温度数字再画成曲线或触发表格。这套组合之所以常被用于课程设计和工业小样机是因为 51 单片机成本低、C 语言开发资料庞杂而 LabVIEW 把串口收发封装成了图形化节点不写一行文本代码就能完成串口配置、字节截取和波形显示。如果你手头有一块 STC89C52 或 AT89S52 开发板、一个 I2C 接口的温度传感器比如 TC74加上一台装有 LabVIEW 的 PC几个小时就能打通一条可靠的数据链路。2. 51单片机端的数据采集与 Modbus 帧接收程序这个标题里的“温度监测”在单片机侧最实在的落地方式是用 I2C 温敏芯片替代热敏电阻加 ADC 的老方案。热敏电阻需要自己标定分压电阻和查表而 I2C 温度传感器直接给出数字量省掉了大量校准时间。下面以 TC74A0 为例讲清楚接线、I2C 读取、串口发送和帧协议封装。2.1 TC74 温度传感器的接线与 I2C 初始化TC74 是一个兼容 I2C 接口的 8 位温度传感器测量范围 -40℃ 到 125℃分辨率 1℃在 0℃ 到 70℃ 范围内的误差只有 ±1℃。它的 I2C 从机地址由硬件引脚 A2、A1、A0 决定默认地址是 0x48 到 0x4F 区间。以常见的 0x48 为例8 位地址字节左移后是 0x90 写地址、0x91 读地址。接线时 SCL 接 P1.0SDA 接 P1.1两个引脚各接一个 4.7kΩ 上拉电阻到 VCC这是 I2C 总线工作在标准模式100kbps的必需条件。单片机端的 I2C 通信不能用传统的延时函数糊弄因为系统还要同时跑串口中断和定时器。我习惯用 GPIO 模拟时序但是把 SCL 翻转和 SDA 采样做成宏定义方便在 STC89C52 和 STC15 系列之间移植。#include reg52.h sbit SCL P1^0; sbit SDA P1^1; #define I2C_DELAY() { _nop_(); _nop_(); _nop_(); _nop_(); } void I2C_Start(void) { SDA 1; SCL 1; I2C_DELAY(); SDA 0; I2C_DELAY(); SCL 0; } void I2C_Stop(void) { SDA 0; SCL 1; I2C_DELAY(); SDA 1; } bit I2C_WriteByte(unsigned char dat) { unsigned char i; bit ack; for (i 0; i 8; i) { SDA (dat 0x80) ? 1 : 0; dat 1; SCL 1; I2C_DELAY(); SCL 0; I2C_DELAY(); } SDA 1; // 释放SDA线等待从机应答 SCL 1; I2C_DELAY(); ack SDA; SCL 0; return ack; } unsigned char I2C_ReadByte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { SCL 1; I2C_DELAY(); dat (dat 1) | SDA; SCL 0; I2C_DELAY(); } return dat; }这段代码的关键在于应答位的处理。I2C_WriteByte 函数里写完 8 位数据后把 SDA 置 1再拉高 SCL 读取从机的 ACK。如果 TC74 没有正确应答返回的 ack 会被置位主函数可以根据这个标志决定是重发还是报错。I2C_ReadByte 则是在每个 SCL 高电平期间采样 SDA注意必须在 SCL 拉高之前把 SDA 从输出模式切换为输入模式GPIO 模拟 I2C 时最常见的错误就是漏了这一步导致读回来的字节恒为 0xFF。读 TC74 温度的时序是先发 Start 信号再发 0x90 写地址然后写配置寄存器地址 0x01 并写入 0x00 让芯片进入正常工作模式最后发 Stop接着重新发 Start再发 0x91 读地址连续读取两个字节前一个是温度寄存器数据后一个是 CRC 或无效填充。由于 TC74 是 8 位分辨率温度值就是第一个数据字节的有符号数。2.2 串口帧结构设计让 LabVIEW 十分钟内能解析单片机采集到温度后不能裸发十六进制数LabVIEW 那边需要契定的停顿时间和帧头识别。我用的协议是简化版 Modbus RTU地址 1 字节、功能码 1 字节、数据长度 1 字节、温度高字节、温度低字节、CRC16 低字节、CRC16 高字节。这样既能让 LabVIEW 的程序框图按索引截取也能配合串口调试助手人工验帧。完整的 Modbus 帧接收在单片机上也可以用状态机实现但采样系统收发的数据量很小可以直接用固定长度帧协议。#define FRAME_LEN 7 unsigned char uart_buf[FRAME_LEN]; unsigned char uart_cnt 0; bit frame_done 0; void UART_ISR() interrupt 4 { unsigned char dat; if (RI) { RI 0; dat SBUF; if (uart_cnt 0) { if (dat ! 0xAA) { // 帧头匹配 return; } uart_buf[0] dat; uart_cnt 1; } else if (uart_cnt FRAME_LEN) { uart_buf[uart_cnt] dat; if (uart_cnt FRAME_LEN) { frame_done 1; uart_cnt 0; } } } }这段串口中断程序把 UART 收到的每一字节都放进缓冲数组。第一字节必须等于 0xAA 才会继续接收否则直接丢弃这能过滤掉上电瞬间的噪声。当收满 7 字节后frame_done 置 1主循环检测到这个标志后就执行 CRC 校验和温度封装。主循环的发送部分如下其中 crc16 是标准的 Modbus CRC 算法计算结果在发送时低字节在前。unsigned int crc16_update(unsigned char *buf, unsigned char len) { unsigned int crc 0xFFFF; unsigned char i, j; for (i 0; i len; i) { crc ^ buf[i]; for (j 0; j 8; j) { if (crc 0x0001) { crc (crc 1) ^ 0xA001; } else { crc 1; } } } return crc; } void send_temperature_frame(int temp) { unsigned char buf[FRAME_LEN]; unsigned int crc; buf[0] 0xAA; // 帧头 buf[1] 0x01; // 设备地址 buf[2] 0x04; // 功能码上报温度 buf[3] (unsigned char)((temp 8) 0xFF); buf[4] (unsigned char)(temp 0xFF); crc crc16_update(buf, 5); buf[5] (unsigned char)(crc 0xFF); buf[6] (unsigned char)((crc 8) 0xFF); for (unsigned char i 0; i FRAME_LEN; i) { SBUF buf[i]; while (!TI); TI 0; } }CRC 计算时只针对帧头、地址、功能码和数据四个字段CRC 自身不参与计算。这是 Modbus 协议最核心的约定。发送函数里的 while 等待方式在低速 51 上完全可用因为串口波特率只有 9600发送 7 字节耗时大约 7.3ms不会阻塞温度采样主循环。2.3 串口参数配置与波特率误差控制51 单片机的串口工作在模式 18 位可变波特率 UART波特率由定时器 1 的溢出率决定。标准的配置是晶振 11.0592MHz这是串口通信的首选晶振频率因为 9600 波特率下它的分频系数是整数不会产生累积误差。配置项寄存器值说明TMOD0x20定时器 1 工作在模式 28 位自动重装TH10xFD波特率 9600 的重装值TL10xFD与 TH1 相同装入后即启动SCON0x50串口模式 1允许接收PCON0x00SMOD0波特率不倍增如果使用 12MHz 晶振9600 波特率的误差会上升到约 2.1%在短帧通信时勉强可用但环境温度变化大的工况下会出现偶发乱码。所以课程设计时尽量选 11.0592MHz 晶振。PCON 寄存器里 SMOD 位为 0代表波特率是定时器溢出率的 64 分频如果 PCON 置为 0x80SMOD1溢出率变成 32 分频相同重装值下波特率翻倍变成 19200但此时 TH1 要改成 0xFA 才能维持 9600。初学者最常犯的错误是在串口助手配置了 9600但单片机实际按 19200 发出导致上位机收到全部乱码。3. LabVIEW 上位机串口读取、帧解析与温度显示LabVIEW 做上位机的优势在于不需要记忆复杂的文本 API串口 VISA 节点拖出来配置好参数就能收发。但图形化编程容易让人忽略数据流方向尤其是字符串转数值这一步字节顺序错了温度就会变成离谱的大数。3.1 用 VISA 配置串口建立通信基础打开 LabVIEW 后新建一个空白 VI在前面板放置一个“VISA 资源名称”下拉列表控件、一个“串口配置”函数、一个“VISA 读取”函数和一个“VISA 关闭”函数。串口配置是 VISA 函数面板里最重要的节点需要设置以下参数参数推荐值原因波特率9600与单片机 TH10xFD 匹配数据位8单片机 UART 模式 1 为 8 位数据校验位None帧内已有 CRC16 校验停止位1.0标准 Modbus RTU 设置流控None51 单片机无 CTS/RTS 硬件握手这里有一个经常被忽略的细节VISA 配置串口的“启用终止符”默认是 TRUE终止符是 0xA换行符。单片机发的原始帧是 7 字节无换行的二进制数据如果开了终止符LabVIEW 会死等换行符到来才停止 VISA 读取程序会一直卡在读取节点。所以在程序框图中必须把“启用终止符”取消勾选或者把终止符改成 0xAA 这样永远不会单独出现的值。串口超时时间设置 2000ms 即可温度监测系统是周期性请求不需要长超时。3.2 从串口字节流中解析温度的完整逻辑LabVIEW 程序的循环结构采用消费者模式一个 While 循环负责定时发送请求帧另一个循环负责 VISA 读取并解析。发送请求帧用“VISA 写入”节点数据源是一个字符串常量内容为十六进制字节AA 01 04 00 00加 CRC 的低高字节。单片机收到这个请求后才会回传温度帧。收到数据后解析流程分三步。第一步用“字符串长度”函数检查 VISA 读取返回的字节数是否为 7不是 7 就丢弃并置错误标志。第二步用“字符串截取”函数分别截出第 4 字节和第 5 字节作为温度的高 8 位和低 8 位。第三步将两个字节按高字节左移 8 位加上低字节的方式拼接再转换为数值显示。具体的字节拼接方式可以用 LabVIEW 的“类型转换”函数先创建一个 U16 类型的数值常量把高字节用“数值-强制类型转换”变成 U8再与低字节组合。更简单的做法是使用“平化字符串转数值”函数把温度两个字节的字符串按高字节在前、低字节在后的顺序拼接再强制转换为 U16结果就是真正的温度值。需要注意温度是带符号的。TC74 在负温度时最高位为 1比如 -5℃ 对应的字节是 0xFB。直接用 U16 转换会得到 251需要在显示控件里配置为 I16 类型或者在 LabVIEW 里先转成 U16 再判断是否大于 127大于则减 256。这个符号扩展是温度解析最隐蔽的坑。3.3 温度曲线显示与报警阈值的界面搭建前面板放一个波形图表控件和一个布尔报警灯。波形图表接收的温度数据以数组形式进入图表的历史长度设为 600 个点代表最近 10 分钟每分钟一个采样点的曲线。报警逻辑用“大于”比较函数把解析出的温度与阈值常量 50.0 比较结果送入指示灯。数据记录可以先用“写入带分隔符电子表格”函数把时间戳和温度组成一维数组写入 CSV。这个函数可以设置追加模式不变写模式这样每次循环写入一行而不是覆盖已有文件。需要注意的是“写入带分隔符电子表格”内部会自动增加一个换行符所以前面板的时间显示控件用“格式化日期时间字符串”节点生成%Y-%m-%d %H:%M:%S格式的文本再与温度数字拼成两列。4. 联调排错乱码、CRC错误与 LabVIEW 读取超时单片机程序和 LabVIEW 程序单独跑都看不出问题联调时才会暴露接口层面的故障。这个环节的排查效率决定了整个温度监测系统能不能在半天内交付。4.1 先用串口调试助手独立验证单片机帧输出不要着急打开 LabVIEW先用纯串口调试助手做硬件侧检查。插好 USB 转 TTL 模块TX 接单片机 RXRX 接单片机 TXGND 共地注意 TTL 电平不能直接接 RS232 口的 DB9 接口。串口调试助手发送区填入AA 01 04 00 00加 CRC 低字节加 CRC 高字节波特率选 9600数据位 8停止位 1无校验。点击发送后接收区应该能收到AA 01 04 [温度高字节] [温度低字节] [CRC低] [CRC高]。如果没有任何返回首先检查单片机程序里是否开启了总中断 EA 和串口中断 ES。STC89C52 默认复位后串口是关闭的必须把EA1; ES1;放在串口初始化之后。其次检查 MAX232 还是 USB 转 TTL如果用了 MAX232 但接入的是 USB 转 TTL电平不匹配会导致收不到任何数据。4.2 CRC 校验失败和偶发乱码的六大根因联调中最难排查的问题是帧结构看起来对、温度数值也偶尔正确但累计几十帧后就报错。下面按经验概率排序先查通信参数再查硬件时序。症状最可能原因解决方案连续乱码无完整帧波特率不匹配单片机实际波特率是 19200检查 PCON 寄存器 SMOD 位帧头时有时无总线竞争调试助手和 LabVIEW 同时占用串口关闭串口调试助手同一时间只允许一个程序打开端口温度字节全为 0xFFI2C 读地址发错或 SDA 无上拉电阻确认发送 0x91 读地址上拉电阻 4.7kCRC 偶尔错误晶振频偏尤其是未知来源的开发板换 11.0592MHz 晶振或改波特率为 4800数据间隔过大VISA 读取超时设置太长关闭终止符识别超时设为 1000ms负温度显示成 251符号位未扩展数值控件改为 I16 类型并做负值折算还有一个隐藏问题TC74 的 SCL 上拉电阻依赖 I2C 总线的规范值部分开发板把 P1.0 和 P1.1 已经接上了 LED 和排阻可能改变了上拉等效电阻。处理办法是在程序里把读取温度到发送帧之间的延时拉长到 50ms给 I2C 总线足够的电平稳定时间。4.3 LabVIEW 运行时的 VISA 资源名称与驱动问题LabVIEW 代码如果报“VISA 资源名称无效”多半不是代码问题而是 NI-VISA 驱动没装或版本不匹配。装上 LabVIEW 2018 后还要单独装 NI-VISA Runtime这个运行库负责操作系统串口与 VISA 函数之间的桥接。安装完驱动后在“设备管理器”里能看到串口号比如 COM3LabVIEW 的 VISA 资源名称下拉列表里选择 COM3 即可。51 单片机板载的 USB 转串口芯片如果是 CH340Windows 10 以上系统会自动识别如果是老式的 PL2303建议安装厂商专用驱动但注意旧版 PL2303 芯片在 Win10 下会被系统禁用这时候需要换一根 CH340 的下载线或转接模块。LabVIEW 界面上如果发生运行时错误 56VISA 资源已关闭原因是 While 循环里 VISA 关闭节点被误放进循环内每次循环都会关闭端口。正确做法是 VISA 配置串口和 VISA 关闭节点都在主循环外循环内只保留 VISA 写入和 VISA 读取。5. 进阶把温度监测系统改造成多通道连续记录平台单一温度点监测跑通后下一步可以是多通道扩展或者优化数据存储方式。这里给出几个容易落地且提升明显的改造点。5.1 用 TDMS 文件替代 CSV 提升写入速度LabVIEW 的“写入带分隔符电子表格”每次写入都打开关闭一次文件采样频率超过 10Hz 时文件句柄反复开关会占用大量 CPU。TDMS 是 NI 专有的二进制数据格式写入效率比文本高一个数量级。程序框图中的改动很小从“文件 I/O”面板拖出“TDMS 写入”函数在进入循环前用“TDMS 打开”函数创建文件并设置属性“采样率1Hz”循环内把温度数组送入 TDMS 写入循环结束后用“TDMS 关闭”函数收尾。TDMS 文件可以用 Excel 或 NI Diadem 打开对后续数据处理也友好。5.2 用状态机实现断线自动重连实际运行中用户可能不小心拔掉 USB 转串口线LabVIEW 程序会一直停在 VISA 读取节点上报超时错误。用一个生产者-消费者状态机可以解决主状态循环里设置“连接失败”状态检测到 VISA 读取错误后进入“等待重连”分支先调用 VISA 关闭节点释放资源再延时 3 秒重新执行 VISA 配置串口。重连后要注意清空旧的串口缓冲区否则开机残留的半帧数据会破坏第一帧解析。5.3 软件时间戳与传感器数据对齐LabVIEW 程序里用“获取日期时间”函数捕获接收到完整帧的时刻但串口传输本身有延迟LabVIEW 收到帧尾的瞬间比传感器采样的实际时刻晚了大约 1 个采样周期。如果监测系统要用于过程分析可以在单片机发送帧里附带一个 16 位毫秒计数器作为时间戳LabVIEW 解析温度的同时解出该计数器值并用差值换算成实际采样时刻。这样做的好处是即使不同帧在串口队列里延迟不一致上位机记录的时间轴依然能反映真实采集顺序。以上改进都围绕数据可靠性和采集连续性展开在不更换核心硬件的前提下已经能把课程设计级别的温度监测系统拉到工程样机的水平。实际运行时把 LabVIEW 的“程序框图”界面最小化在 Windows 任务计划里设置开机启动该 VI就能作为无人值守的上位机监测终端运行。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门