温度检测系统,包含 51 单片机下位机(温度采集)、LabVIEW 上位机(数据显示与处理)、硬件连接和代码实现。
一、系统架构
┌─────────────────────────────────────────────────────────────┐
│ 温度检测系统架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ DS18B20温度传感器 → 51单片机 → USB/TTL → PC/LabVIEW │
│ │
│ 温度采集模块 数据处理模块 通信模块 │
│ │
└─────────────────────────────────────────────────────────────┘
二、硬件设计
1. 硬件清单
| 元件 | 型号 | 数量 | 备注 |
|---|---|---|---|
| 单片机 | AT89C51/AT89S51 | 1 | 51 系列单片机 |
| 温度传感器 | DS18B20 | 1 | 数字温度传感器 |
| 晶振 | 11.0592MHz | 1 | 用于串口通信 |
| 电容 | 30pF | 2 | 晶振匹配电容 |
| 电阻 | 4.7kΩ | 1 | DS18B20 上拉电阻 |
| 电阻 | 10kΩ | 1 | 复位电路 |
| 电解电容 | 10μF | 1 | 电源滤波 |
| USB-TTL模块 | CH340/PL2303 | 1 | 串口通信 |
| 面包板/PCB | - | 1 | 电路搭建 |
2. 硬件连接图
┌─────────────┐
│ DS18B20 │
│ │
│ GND ───────┼── GND
│ DQ ───────┼── P3.7 (单总线)
│ VDD ───────┼── +5V
│ │
└─────────────┘
│
4.7kΩ
│
+5V
┌─────────────┐
│ AT89C51 │
│ │
│ P3.0(RXD) ─┼───→ USB-TTL TX
│ P3.1(TXD) ─┼───→ USB-TTL RX
│ P3.7 ─┼───→ DS18B20 DQ
│ RST ─┼───→ 复位电路
│ XTAL1 ─┼───→ 晶振 11.0592MHz
│ XTAL2 ─┼───→ 晶振 11.0592MHz
│ GND ─┼───→ GND
│ VCC ─┼───→ +5V
│ │
└─────────────┘
│
┌────┴────┐
│ USB-TTL │
│ 模块 │
└────┬────┘
│
┌────┴────┐
│ PC │
│ LabVIEW │
└─────────┘
三、51 单片机程序设计
1. 主程序 (main.c)
c
/**
******************************************************************************
* @file main.c
* @author Embedded Developer
* @version V1.0
* @date 2024-01-01
* @brief 51单片机温度检测主程序
******************************************************************************
*/
#include "reg52.h"
#include "ds18b20.h"
#include "uart.h"
#include "delay.h"
// 全局变量
float temperature = 0.0f;
unsigned char temp_int = 0;
unsigned char temp_dec = 0;
// 函数声明
void System_Init(void);
void Timer0_Init(void);
void Send_Temperature_To_PC(float temp);
void main(void)
{
// 系统初始化
System_Init();
UART_Init();
DS18B20_Init();
Timer0_Init();
EA = 1; // 开启总中断
// 发送启动信息
UART_SendString("51单片机温度检测系统启动...\r\n");
Delay_ms(100);
while(1)
{
// 读取温度
temperature = DS18B20_GetTemp();
// 分离整数和小数部分
temp_int = (unsigned char)temperature;
temp_dec = (unsigned char)((temperature - temp_int) * 100);
// 发送温度数据到PC
Send_Temperature_To_PC(temperature);
// 延时1秒
Delay_ms(1000);
}
}
/**
* @brief 系统初始化
* @param None
* @retval None
*/
void System_Init(void)
{
// 端口初始化
P3 = 0xFF; // P3口作为输入
P1 = 0x00; // P1口作为输出
P2 = 0x00; // P2口作为输出
// 关闭看门狗(如果使用STC单片机)
// WDT_CONTR = 0x00;
}
/**
* @brief 定时器0初始化(用于延时)
* @param None
* @retval None
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; // 清除T0控制位
TMOD |= 0x01; // 设置T0为模式1(16位定时器)
TH0 = 0xFC; // 装载初值(1ms@11.0592MHz)
TL0 = 0x66;
ET0 = 1; // 允许T0中断
TR0 = 1; // 启动T0
}
/**
* @brief 发送温度数据到PC
* @param temp: 温度值
* @retval None
*/
void Send_Temperature_To_PC(float temp)
{
unsigned char buffer[20];
unsigned char i = 0;
// 格式化温度数据
buffer[i++] = 'T';
buffer[i++] = ':';
buffer[i++] = temp_int / 100 + '0';
buffer[i++] = temp_int / 10 % 10 + '0';
buffer[i++] = temp_int % 10 + '0';
buffer[i++] = '.';
buffer[i++] = temp_dec / 10 + '0';
buffer[i++] = temp_dec % 10 + '0';
buffer[i++] = 'C';
buffer[i++] = '\r';
buffer[i++] = '\n';
// 发送数据
for(unsigned char j = 0; j < i; j++)
{
UART_SendByte(buffer[j]);
}
}
/**
* @brief 定时器0中断服务函数
* @param None
* @retval None
*/
void Timer0_ISR(void) interrupt 1
{
TH0 = 0xFC; // 重装初值
TL0 = 0x66;
// 在这里可以添加定时任务
}
2. DS18B20 驱动 (ds18b20.c)
c
/**
******************************************************************************
* @file ds18b20.c
* @author Embedded Developer
* @version V1.0
* @date 2024-01-01
* @brief DS18B20温度传感器驱动
******************************************************************************
*/
#include "ds18b20.h"
#include "delay.h"
// DS18B20引脚定义
sbit DQ = P3^7; // 单总线引脚
/**
* @brief DS18B20延时函数(微秒级)
* @param us: 延时微秒数
* @retval None
*/
void DS18B20_DelayUs(unsigned int us)
{
while(us--)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
/**
* @brief DS18B20初始化
* @param None
* @retval 0=成功, 1=失败
*/
unsigned char DS18B20_Init(void)
{
unsigned char retry = 0;
DQ = 1;
DS18B20_DelayUs(1);
DQ = 0;
DS18B20_DelayUs(480); // 480us复位脉冲
DQ = 1;
DS18B20_DelayUs(60); // 等待60us
// 检测存在脉冲
while(DQ && retry < 240)
{
retry++;
DS18B20_DelayUs(1);
}
if(retry >= 240)
return 1; // 初始化失败
DS18B20_DelayUs(420); // 等待420us
return 0; // 初始化成功
}
/**
* @brief 向DS18B20写入一个字节
* @param dat: 要写入的数据
* @retval None
*/
void DS18B20_WriteByte(unsigned char dat)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
DQ = 0;
DS18B20_DelayUs(2); // 2us
DQ = dat & 0x01; // 发送最低位
DS18B20_DelayUs(60); // 60us
DQ = 1;
dat >>= 1;
DS18B20_DelayUs(2); // 2us恢复时间
}
}
/**
* @brief 从DS18B20读取一个字节
* @param None
* @retval 读取的字节
*/
unsigned char DS18B20_ReadByte(void)
{
unsigned char i, dat = 0;
for(i = 0; i < 8; i++)
{
DQ = 0;
DS18B20_DelayUs(2); // 2us
DQ = 1;
DS18B20_DelayUs(2); // 2us
dat >>= 1;
if(DQ)
dat |= 0x80;
DS18B20_DelayUs(60); // 60us
}
return dat;
}
/**
* @brief 启动温度转换
* @param None
* @retval None
*/
void DS18B20_StartConvert(void)
{
DS18B20_Init();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 启动温度转换
}
/**
* @brief 读取温度值
* @param None
* @retval 温度值(摄氏度)
*/
float DS18B20_GetTemp(void)
{
unsigned char temp_l, temp_h;
int temp;
float temperature;
DS18B20_StartConvert();
Delay_ms(750); // 等待转换完成(12位精度需要750ms)
DS18B20_Init();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0xBE); // 读取暂存器
temp_l = DS18B20_ReadByte(); // 温度低字节
temp_h = DS18B20_ReadByte(); // 温度高字节
temp = (temp_h << 8) | temp_l;
if(temp < 0) // 负温度
{
temperature = -((~temp + 1) * 0.0625f);
}
else // 正温度
{
temperature = temp * 0.0625f;
}
return temperature;
}
3. DS18B20 头文件 (ds18b20.h)
c
/**
******************************************************************************
* @file ds18b20.h
* @author Embedded Developer
* @version V1.0
* @date 2024-01-01
* @brief DS18B20温度传感器头文件
******************************************************************************
*/
#ifndef __DS18B20_H
#define __DS18B20_H
#include "reg52.h"
#include "delay.h"
// 函数声明
unsigned char DS18B20_Init(void);
void DS18B20_WriteByte(unsigned char dat);
unsigned char DS18B20_ReadByte(void);
void DS18B20_StartConvert(void);
float DS18B20_GetTemp(void);
#endif /* __DS18B20_H */
4. 串口通信驱动 (uart.c)
c
/**
******************************************************************************
* @file uart.c
* @author Embedded Developer
* @version V1.0
* @date 2024-01-01
* @brief 串口通信驱动
******************************************************************************
*/
#include "uart.h"
/**
* @brief 串口初始化
* @param None
* @retval None
*/
void UART_Init(void)
{
TMOD |= 0x20; // 设置T1为模式2(8位自动重装)
TH1 = 0xFD; // 波特率9600@11.0592MHz
TL1 = 0xFD;
TR1 = 1; // 启动T1
SM0 = 0; // 设置串口为模式1
SM1 = 1;
REN = 1; // 允许接收
EA = 1; // 开启总中断
ES = 1; // 开启串口中断
}
/**
* @brief 发送一个字节
* @param dat: 要发送的字节
* @retval None
*/
void UART_SendByte(unsigned char dat)
{
SBUF = dat;
while(!TI); // 等待发送完成
TI = 0; // 清除发送中断标志
}
/**
* @brief 发送字符串
* @param str: 要发送的字符串
* @retval None
*/
void UART_SendString(char *str)
{
while(*str)
{
UART_SendByte(*str++);
}
}
/**
* @brief 串口中断服务函数
* @param None
* @retval None
*/
void UART_ISR(void) interrupt 4
{
unsigned char receive_data;
if(RI) // 接收中断
{
RI = 0; // 清除接收中断标志
receive_data = SBUF; // 读取接收到的数据
// 回显接收到的数据
UART_SendByte(receive_data);
}
}
5. 延时函数 (delay.c)
c
/**
******************************************************************************
* @file delay.c
* @author Embedded Developer
* @version V1.0
* @date 2024-01-01
* @brief 延时函数
******************************************************************************
*/
#include "delay.h"
/**
* @brief 毫秒延时
* @param ms: 延时毫秒数
* @retval None
*/
void Delay_ms(unsigned int ms)
{
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 110; j > 0; j--);
}
/**
* @brief 微秒延时
* @param us: 延时微秒数
* @retval None
*/
void Delay_us(unsigned int us)
{
while(us--)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
四、LabVIEW 上位机设计
1. 前面板设计
┌─────────────────────────────────────────────────────────────┐
│ 温度检测系统 - 前面板 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ ┌─────────────────────────────┐ │
│ │ 系统控制面板 │ │ 温度显示面板 │ │
│ ├─────────────────────┤ ├─────────────────────────────┤ │
│ │ 串口选择: [COM3 ▼] │ │ 当前温度: 25.50 °C │ │
│ │ 波特率: [9600 ▼] │ │ 最高温度: 30.20 °C │ │
│ │ 数据位: [8 ▼] │ │ 最低温度: 22.10 °C │ │
│ │ 停止位: [1 ▼] │ │ 平均温度: 26.80 °C │ │
│ │ 校验位: [无 ▼] │ │ │ │
│ │ │ │ ┌─────────────────────┐ │ │
│ │ [连接串口] [断开] │ │ │ 温度趋势图 │ │ │
│ │ │ │ │ │ │ │
│ │ [开始采集] [停止] │ │ │ ↑ │ │ │
│ │ │ │ │ │ │ │ │
│ │ 报警设置: │ │ │ │ │ │ │
│ │ 上限: [30.0] °C │ │ │ └─────────────────┘ │ │
│ │ 下限: [20.0] °C │ │ │ │ │ │
│ │ [启用报警] │ │ └─────────────────────────────┘ │
│ └─────────────────────┘ │ │
│ │ ┌─────────────────────────────┐ │
│ │ │ 数据记录面板 │ │
│ │ ├─────────────────────────────┤ │
│ │ │ [保存数据] [清空记录] │ │
│ │ │ │ │
│ │ │ 采集时间: 2024-01-01 10:30 │ │
│ │ │ 采集点数: 1000 │ │
│ │ │ 文件路径: C:\temp_data.txt │ │
│ │ └─────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2. 程序框图设计
┌─────────────────────────────────────────────────────────────┐
│ 温度检测系统 - 程序框图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 串口配置 │───▶│ 串口读取 │───▶│ 数据解析 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 温度显示 │◀───│ 数据处理 │◀───│ 报警判断 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 曲线绘制 │ │ 数据存储 │ │ 报警输出 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
3. LabVIEW 核心代码(G语言描述)
3.1 串口初始化子VI
┌─────────────────────────────────────┐
│ 串口初始化子VI │
├─────────────────────────────────────┤
│ │
│ [VISA Configure Serial Port] │
│ │ │
│ ▼ │
│ [VISA Open] │
│ │ │
│ ▼ │
│ [VISA Set Timeout] │
│ │ │
│ ▼ │
│ [输出: VISA资源名] │
│ │
└─────────────────────────────────────┘
参数设置:
- 波特率:9600
- 数据位:8
- 停止位:1
- 校验位:None
- 超时:1000ms
3.2 数据读取与解析子VI
┌─────────────────────────────────────┐
│ 数据读取与解析子VI │
├─────────────────────────────────────┤
│ │
│ [VISA Read] ──▶ [字符串搜索] ──▶ │
│ │ │ │
│ ▼ ▼ │
│ [截取字符串] ──▶ [十进制数字转换] │
│ │ │ │
│ ▼ ▼ │
│ [输出: 温度值(°C)] ◀─┘ │
│ │
└─────────────────────────────────────┘
数据格式解析:
输入字符串: "T:25.50C\r\n"
解析步骤:
1. 搜索 "T:" 位置
2. 截取 ":" 之后的数字部分
3. 转换为浮点数 25.50
3.3 温度显示与报警子VI
┌─────────────────────────────────────┐
│ 温度显示与报警子VI │
├─────────────────────────────────────┤
│ │
│ 温度值 ──▶ [数值显示] │
│ │ │ │
│ ├──▶ [温度计显示] │
│ │ │ │
│ ├──▶ [柱状图显示] │
│ │ │ │
│ └──▶ [报警判断] ──▶ [指示灯] │
│ │ │
│ ├── 温度 > 上限 → 红灯 │
│ ├── 温度 < 下限 → 蓝灯 │
│ └── 正常范围 → 绿灯 │
│ │
└─────────────────────────────────────┘
4. 完整 LabVIEW 程序代码(文本描述)
由于无法直接提供 .vi 文件,以下是详细的实现步骤:
4.1 创建新VI
- 打开 LabVIEW
- 新建 VI (File → New VI)
- 保存为
Temperature_Monitor.vi
4.2 前面板设计步骤
-
添加串口控件:
- Controls Palette → Modern → I/O → VISA Resource Name
- 放置到前面板,命名为 "串口选择"
-
添加数值显示控件:
- Controls Palette → Modern → Numeric → Gauge
- 放置到前面板,命名为 "当前温度"
-
添加波形图表:
- Controls Palette → Modern → Graph → Waveform Chart
- 放置到前面板,命名为 "温度趋势图"
-
添加按钮控件:
- Controls Palette → Modern → Boolean → OK Button
- 添加 "连接串口"、"开始采集"、"停止采集" 按钮
4.3 程序框图实现步骤
主循环结构:
While Loop
│
├── Case Structure (串口连接)
│ ├── True: VISA Configure Serial Port
│ └── False: VISA Close
│
├── Case Structure (数据采集)
│ ├── True: VISA Read → 数据解析 → 显示更新
│ └── False: 停止采集
│
├── 定时结构 (Wait ms)
│
└── 停止条件
数据解析代码:
VISA Read (Bytes at Port)
│
├── 字符串 → 字节数组
│
├── 搜索 "T:" 位置
│
├── 截取温度字符串
│
└── 字符串 → 数值转换
参考代码 基于LabVIEW和51单片机的温度检测 www.youwenfan.com/contentcsv/112928.html
五、系统测试与调试
1. 硬件测试
步骤1:检查电源
用万用表测量:
- VCC 对 GND: 5.0V ± 0.1V
- DS18B20 VDD 对 GND: 5.0V
步骤2:检查DS18B20
用示波器观察 P3.7 引脚:
- 初始化时有复位脉冲
- 有数据波形输出
步骤3:检查串口
用串口调试助手测试:
- 发送 "AT" 应收到响应
- 波特率设置为 9600
2. 软件测试
51单片机测试程序:
c
// 测试程序:发送固定温度值
void Test_UART(void)
{
UART_SendString("T:25.50C\r\n");
Delay_ms(1000);
}
LabVIEW测试:
- 打开串口调试助手
- 设置波特率 9600
- 应收到 "T:25.50C\r\n" 数据
3. 常见问题解决
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 无法读取温度 | DS18B20接触不良 | 检查接线,更换传感器 |
| 温度读数错误 | 上拉电阻缺失 | 添加4.7kΩ上拉电阻 |
| 串口通信失败 | 波特率不匹配 | 确认11.0592MHz晶振 |
| LabVIEW无数据 | VISA驱动未安装 | 安装NI-VISA驱动 |
| 温度波动大 | 电源干扰 | 添加电源滤波电容 |
六、系统扩展功能
1. 多路温度检测
c
// 多路DS18B20检测
float temperatures[8];
for(i = 0; i < 8; i++)
{
DS18B20_SelectSensor(rom_codes[i]);
temperatures[i] = DS18B20_GetTemp();
}
2. 温度报警功能
c
// 温度报警
if(temperature > ALARM_HIGH)
{
P1_0 = 0; // 红灯亮
UART_SendString("ALARM: High Temperature!\r\n");
}
else if(temperature < ALARM_LOW)
{
P1_1 = 0; // 蓝灯亮
UART_SendString("ALARM: Low Temperature!\r\n");
}
3. 数据存储功能
c
// 存储到EEPROM
void Save_Temperature_To_EEPROM(float temp)
{
unsigned int addr = 0x0000;
EEPROM_Write(addr, (unsigned char*)&temp, sizeof(float));
}
4. 无线传输扩展
c
// 通过WiFi模块发送
void Send_To_Cloud(float temp)
{
ESP8266_SendData("temperature", temp);
}
七、完整项目文件结构
Temperature_Monitor/
├── Firmware/
│ ├── main.c
│ ├── ds18b20.c
│ ├── ds18b20.h
│ ├── uart.c
│ ├── uart.h
│ ├── delay.c
│ ├── delay.h
│ └── Temperature_Monitor.hex
├── LabVIEW/
│ ├── Temperature_Monitor.vi
│ ├── SubVIs/
│ │ ├── Serial_Init.vi
│ │ ├── Data_Parse.vi
│ │ ├── Temperature_Display.vi
│ │ └── Alarm_Check.vi
│ └── Config/
│ └── Serial_Config.ini
├── Hardware/
│ ├── Schematic.pdf
│ ├── PCB/
│ │ ├── TopLayer.brd
│ │ └── BottomLayer.brd
│ └── BOM.xlsx
├── Documentation/
│ ├── User_Manual.pdf
│ ├── Technical_Specification.pdf
│ └── Test_Report.pdf
└── README.md
这个系统实现了完整的温度检测功能,具有实时显示、数据存储、报警提示等特点。51单片机负责温度采集,LabVIEW负责数据显示和分析,两者通过串口通信。系统稳定可靠,易于扩展和维护。