51单片机PT100温度控制系统设计与Proteus仿真全解析
2026/8/31 18:27:16 网站建设 项目流程

简介:本资源是一套完整的基于51单片机的温度闭环控制系统设计资料,面向嵌入式初学者、课程设计学生及电子类实训教师,解决温度实时采集、上下限设定与加热/散热执行控制等典型工程问题。压缩包共39个文件,含Proteus仿真工程(.DSN)、原理图(.SchDoc)、流程图(.bmp)、物料清单(.xls)、C语言源代码(main.c、TLC1543.c)、编译输出文件(.hex、.lst、.obj)及PDF版原理图与功能说明文档,全面覆盖硬件设计、软件逻辑与仿真验证环节,总大小774KB。已有117人学习下载,资源结构清晰:源码含PT100信号调理与ADC转换处理、数码管动态扫描显示、独立按键参数设置及继电器驱动逻辑;配套流程图与原理图便于理解系统架构,仿真图可直接加载运行观察温控响应过程,是掌握传感器应用与单片机外围控制的高实用性入门项目。 提到51单片机课程设计,温度控制几乎是最常见的一道题,但很多人在PT100上栽跟头。DS18B20固然省事,数字接口直接接IO口就行,可题目指定PT100,那就必须老老实实从模拟前端开始搭。这篇文章我就把基于51单片机 + PT100 + 数码管 + Proteus的完整实现思路写出来,包括原理图怎么画、信号链怎么算、软件怎么写、仿真的坑在哪里,物料清单和核心源代码也会给到可复现的版本。做完这个项目,你会发现PT100并没有想象中那么可怕,真正难的是把调理电路和软件标定配合好。

1. 项目拆解:你要做的到底是一个什么东西

1.1 题目要求逐条拆解

“基于51单片机的温度控制(PT100,上下限,数码管)proteus,原理图、流程图、物料清单、仿真图、源代码”这句话信息量很大,拆开看其实是四件事:

第一,控制器必须是51系列单片机。Proteus里最常用的是AT89C51或者AT89C52,做实物推荐STC89C52RC,指令兼容,下载方便。第二,测温元件必须用PT100,这是铂热电阻,不是数字传感器,所以必须设计模拟调理电路。第三,系统要有上、下限控制功能,也就是温度低于下限要启动加热,高于上限要停止加热或报警,具体怎么分配由需求决定。第四,显示输出用数码管,同时还要交付原理图、流程图、物料清单、仿真图和源代码,这基本就是一套完整的单片机工程项目。

很多同学会把PT100当成DS18B20一样直接接一个IO口,这是最典型的错误。PT100是电阻型传感器,阻抗随温度变化,但单片机不认识电阻,只知道高电平和低电平,所以必须先把电阻变化转换成电压或数字信号。围绕这一条,就引出了运算放大器、ADC、查表、滤波等一系列问题。整个项目并没有复杂的算法,难点在于模拟前端的设计和软件标定的一致性。

1.2 核心方案:从传感器到输出的完整信号链路

常见的基于51的PT100测温方案有三类,我对比一下:

  • 方案一:PT100 + 恒流源 + 运算放大器 + ADC。恒流源给PT100供电,得到电压经运放放大后送ADC。这种方案精度高、抗干扰好,但恒流源电路搭建稍复杂,适合对精度有要求的场合。
  • 方案二:PT100 + 电桥 + 运放 + ADC。把PT100作为电桥的一个桥臂,电桥输出的差分电压经运放放大后送ADC。这是课程设计里最稳妥的方案,元件常见,计算也直白。
  • 方案三:PT100 + 比较器 + 上下限电位器。这种方案不测真实温度,只判断是否超过阈值,虽然省掉ADC和数码管,但无法显示当前温度。题目要求数码管显示,所以直接排除。

所以最佳选择是方案二。完整信号链路是:

PT100 → 三线制电桥 → LM358双运放差分放大 → ADC0832 → 51单片机 → 数码管显示;同时按键设置上下限,单片机输出IO控制继电器或蜂鸣器。

ADC的选型也值得说一下。AT89C51本身没有ADC,常用ADC0809或者ADC0832。ADC0809是8路8位并行ADC,接口并行,但需要外部时钟,占用的IO口比较多。ADC0832是两路8位串行ADC,只需要CS、CLK、DIO三根线,占用引脚少,程序时序短,我用的是ADC0832。如果使用STC89C52,部分型号自带10位ADC,实物可以直接用,但Proteus里对STC的模拟支持不太完整,仿真依旧建议用AT89C51 + ADC0832,逻辑一致,实物换芯片时保留同样的信号链即可。

2. 硬件设计:PT100调理电路与Proteus里的正确画法

2.1 PT100测温到底难在哪:非线性、导线电阻与自热

PT100比NTC、DS18B20麻烦,主要是三个问题:

第一,非线性。PT100在0℃时阻值是100Ω,100℃时阻值是138.5Ω,中间的阻值-温度曲线并不是严格的直线。在0~100℃范围内,非线性误差大概有零点几摄氏度;如果测量范围扩展到150℃以上,误差会增大到好几度。对课程设计这种精度要求不高的场景,可以忽略非线性,直接用线性计算;但你要较真,可以用查表法或分段插值。

第二,导线电阻。PT100本身是低阻值传感器,100Ω级别,连接导线的电阻哪怕只有0.5Ω,引入的误差就有1℃左右。如果导线比较长,误差会更大。解决思路是改用三线制接法:激励电流从一根线流进,电压从第二根线采样,第三根线用来补偿另一根导线的压降,这样电桥输出基本不受导线电阻影响。这也是题目里“PT100三线制”这个关键词的意义所在。

第三,自热效应。PT100在工作时要通过电流,电流越大,传感器自身发热越明显,测量值就会偏高。一般把激励电流控制在1mA左右比较合理,自热功率不到0.1mW。电桥电路里用几十毫安的电流显然不行,所以我在设计时会在电桥供电端串电阻限流,保证流过PT100的电流在小电流范围内。

Proteus仿真里其实没有真实PT100模型,这一点必须提前说清楚。通常的办法是用固定电阻加电位器模拟:PT100在0℃对应100Ω,把固定电阻100Ω和电位器串联,电位器调到38.5Ω时,总电阻138.5Ω,就对应100℃。调试时转动电位器,就能模拟温度变化。这种方法虽然粗糙,但验证整个信号链和软件逻辑完全够用。

2.2 三线制电桥加运放:最经典也最稳定的前端

下面说电路设计。我这里采用的是经典三线制惠斯通电桥结构,PT100接在其中一个桥臂。电桥的其他三个桥臂用精密电阻,阻值选择和PT100的量程中心有关。为了限制桥臂电流,我在供电端串联了限流电阻,保证PT100上的工作电流在1mA量级。

电桥会输出一个差分电压,这个电压的变化量很小。以PT100在0~100℃变化为例,阻值从100Ω变到138.5Ω,桥路输出通常只有几十毫伏。8位ADC的参考电压是5V,1 LSB对应约19.5mV。如果不放大,当温度变化1℃时,PT100阻值变化约0.385Ω,电桥输出电压变化只有不到1mV,这显然远低于ADC分辨率,所以必须用运放把差分信号放大。

运放选用双运放LM358,这是最常见的低压低功耗运放。使用一级差分放大电路,把电桥输出的差分电压放大到0~5V范围内。放大倍数怎么定?假设你希望0~150℃对应ADC输入0~5V,那么150℃时电桥输出大概60mV,放大倍数大约83倍。实际不用算得特别死,只要保证最低温和最高温时运放输出都在0.2~4.8V以内就行。太大的放大倍数会让输出提前饱和,太小则浪费ADC分辨率。

这里要给一个关键的实操建议:在运放反馈回路里加一个10kΩ电位器或者固定电阻微调,用于校准增益。仿真时可以先把固定电阻值算好,实物焊接时再用电位器调零点和满量程。我的经验是先不接PT100,用100Ω标准电阻接上,调电桥平衡让ADC输出接近0;再接一个138.5Ω的标准电阻,调放大倍数让ADC输出接近满量程。两个点校准完,中间段的误差就不会太大。

2.3 数码管驱动与上下限设置电路

数码管显示部分,我推荐用四位共阳数码管。在Proteus里搜索7SEG-MPX4-CA就是共阳四位数码管,7SEG-MPX4-CC是共阴。共阳显示段码和共阴是取反关系,代码里要改表,不要搞混。

如果直接用P0口接段选,P0口内部没有上拉电阻,仿真中亮度会很暗或者根本不亮。正确做法是P0口接1kΩ排阻上拉到5V,或者改用74HC573锁存器驱动。我常用74HC573来做段选和位选:P0口输出数据,P2.5控制段选锁存,P2.6控制位选锁存。先送段码,LE引脚给一个上升沿,数据锁存到输出端;再送位选码,同样锁存。这样数码管显示稳定,不会闪烁。

上下限设置电路很简单,至少三个轻触按键:设置键SET、加键INC、减键DEC。按键一端接IO口,另一端接地,IO口内部上拉或外部接10kΩ上拉。按SET进入上限设置模式,再按SET进入下限设置模式,第三次按SET退出设置模式回到正常显示。在设置模式下,INC和DEC调整数值。

控制执行部分,我建议用继电器或者发光二极管指示即可。仿真中直接用LED最方便,不同温度状态用不同颜色LED指示:低于下限亮红色,高于上限亮黄色,正常范围内亮绿色。实物如果接加热器,需要用三极管S8050驱动继电器,继电器线圈两端并联1N4007续流二极管,否则断电瞬间反向电动势可能会击穿单片机IO口,这个细节非常重要。

3. 软件设计:从ADC采样到数码管显示的控制流程

3.1 温度换算:查表还是分段线性,ADC数据如何变成温度

软件的核心是把ADC读到的数字量换算成真实温度。硬件电路确定以后,ADC输入电压与PT100阻值近似线性关系,所以最简单的方法就是两点线性标定。

标定过程如下:先把电路调到0℃状态,比如用100Ω电阻替代PT100,记录此时ADC输出为adc0;然后把PT100调到100℃状态,用138.5Ω电阻替代,记录adc100。实际温度T可以这样计算:

T = (adc_now - adc0) * 100 / (adc100 - adc0)

这个公式的前提是ADC转换结果和输入电压线性,以及放大电路在线性区。对于8位ADC,线性度足够;对于课程设计,这个算法是最容易实现且理解成本最低的。

如果要求高一点,可以用查表法。这里不是查PT100分度表,而是查你自己硬件电路标定出来的ADC值表:在0℃、10℃、20℃……每10℃记录对应的ADC数值,放在一个const数组里。程序运行时,先二分查找当前ADC值所在区间,然后线性插值。查表法可以把非线性误差、器件离散误差都压到很低,适合温度范围较大,或者不同批次器件之间的校准。

查表法的缺点是标定过程麻烦,如果你没有标准温度计和恒温源,就别折腾了。课程设计大多数场景两点线性标定就够,报告中可以写清楚误差来源,这反而显得更专业。

3.2 按键上下限设置与去抖

按键处理最怕抖动。机械按键按下时,会在几十毫秒内出现多次闭合和断开,如果不消抖,一次按下可能被识别成三四次。最简单的消抖方法是软件延时10~20ms后再次确认电平,稳定后再执行动作。

我的按键状态机是:

  1. 检测到按键按下,记录当前系统时间。
  2. 延时10ms,再次读取按键状态。
  3. 如果仍为按下,则确认有效按键,执行相应功能。
  4. 等待按键释放,防止长按触发重复事件。

如果要支持长按连续调节,比如按住INC键不松手,每200ms自动加1,那就要用定时器计时,不能把主程序卡在while里。我实际写代码的时候,定义了一个按键扫描函数,在10ms定时中断里调用,主循环通过标志位判断按键事件。这样长按和短按都能处理,也不会影响数码管扫描。

上下限的逻辑约束也要写进代码。增加上限时,如果数值已经等于或小于下限,就自动把上限加到下限+1;减少下限时,如果数值已经等于或大于上限,就自动把下限降到上限-1。这个看起来简单的判断,能避免后续控制逻辑出现矛盾。

3.3 数码管动态扫描与抗干扰

四位一体的数码管要显示四位数字,如果所有位同时点亮,占用的IO口和驱动器会很多,所以采用动态扫描。原理是同一时刻只接通一位数码管的公共端,并送出这一位要显示的字形码,然后关断,再切换到下一位。这样高速轮流点亮,利用人眼视觉暂留,看起来就是四位同时显示。

动态扫描的周期很关键。一个完整的四位扫描周期建议控制在20ms以内,也就是每位点亮时间不超过5ms。这样刷新率约50Hz,人眼感觉不到闪烁。如果主程序里有按键消抖延时或者大循环,扫描周期会被拉长,就会出现闪烁。所以动态扫描最好放在定时器中断里做,主循环只负责更新显示缓冲区。

抗干扰方面,ADC采集到的数据一定要滤波。最简单的滤波是连续采集5次到10次,去掉最大值和最小值,剩下的取平均。我实测过,不加滤波的时候,数码管显示的最后一位会有1~2个字的跳动,加上中值平均滤波后基本稳定。注意ADC0832在每次转换之前,采样保持电容的建立需要时间,所以连续采集之间加一点延时,或者调用函数时留出操作时钟间隔。

3.4 主程序流程图

用文字描述一下主程序流程:

上电后先初始化:设置定时器、中断、I/O方向、ADC引脚,读取默认上下限值。然后进入主循环:

  1. 调用ADC采集子程序,对当前温度进行多次采样和滤波。
  2. 调用温度换算子程序,把ADC值换算成实际温度。
  3. 调用控制子程序,将当前温度与上限下限做比较。如果温度低于下限,开启加热继电器;如果温度高于上限,关闭加热继电器并触发报警;如果温度在上下限之间,保持之前的输出状态或者恢复到正常状态。
  4. 调用显示子程序。如果处于正常模式,显示实时温度;如果处于设置模式,显示当前设定的上限或下限。
  5. 调用按键扫描子程序,处理按键事件。

定时器中断同时承担两件事:数码管动态扫描和按键去抖计时。主循环和中断之间通过全局变量通信,注意中断中用到的变量如果用char类型就不容易出错,跨多个字节的变量建议在临界区更新。

课程设计报告要画流程图时,按照这个层级画出“主程序流程图”和“定时器中断流程图”即可。Proteus仿真验证时,将上述流程转换成代码后,应该能看到数码管实时更新温度,按键调节上下限后控制输出状态发生变化。

4. Proteus仿真实战:搭建、调试、踩坑

4.1 元件选型与Proteus仿真库注意事项

Proteus搭建工程时,元件名称和实际型号不一定完全一样,我列一下常用搜索词:

  • 单片机:AT89C51或AT89C52,在Microprocessor ICs目录。
  • 运算放大器:LM358,在Operational Amplifiers目录。
  • ADC芯片:ADC0832是常见的,如果没有,搜索ADC0809也可以。ADC0809有28个引脚,连接复杂一些,但Proteus支持得很好。
  • 数码管:7SEG-MPX4-CA是共阳四位数码管,7SEG-MPX4-CC是共阴。
  • 按键:BUTTON。
  • 电阻、电容、电位器:RES、CAP、POT-HG,电位器在调节时旋转滚轮就能改变阻值。
  • 继电器:搜索RELAY,或者直接用一个LED代替。

Proteus里没有专门的PT100符号,不要浪费时间去找PT100。常规做法是把一个100Ω固定电阻和一个电位器串联,这个组合当温度变化时调节阻值。电位器的最大阻值可以用10kΩ,但实际只用到38.5Ω的一段,调节会比较灵敏,不太好拧。解决办法是串联一个标称100Ω的电阻,再并联一个100Ω的微调电阻?不推荐,直接用POT-HG,阻值范围选100Ω或50Ω,Proteus的POT可以设置最大阻值。

很多初学者会在Proteus中把51单片机的晶振直接省略,但为了仿真精确,我建议还是放上12MHz晶振和两个22pF电容,复位电路用10μF电容和10kΩ电阻。这样程序下载到实物时,至少这部分不需要改。

4.2 常见仿真问题与排查

我把自己在Proteus仿真中常踩的坑整理成一张速查表,照着排查能节约大量时间:

现象可能原因解决方法
仿真运行但单片机不工作没有加载HEX文件双击单片机,Program File选择编译生成的HEX
数码管不亮或亮度很暗P0口没有上拉P0口加1kΩ排阻到5V,或改用P1/P2口
数码管乱码共阳和共阴段码表写反确认数码管类型,调整段码表
ADC读数始终为255运放输出超过ADC参考电压降低放大倍数,确保输入在0~5V
ADC读数始终为0运放输出接近0V或接线错误用电压表检查运放输出脚电压
按键没反应按键上拉电阻漏接加10kΩ上拉电阻,确认按键另一端接地
温度显示不变化电位器阻值没调运行后用鼠标转动电位器或按R/R键调节

这里单独说一下ADC0832。ADC0832的时序虽然简单,但很多人第一次写会卡住。判断方法很简单:用一个固定电压源接到ADC输入通道,分别给0V、2.5V、5V,如果读出来的数值是0、128、255附近,说明ADC时序是正确的。如果数值不对,先查CLK和DIO电平时序,尤其注意读取数据时是在CLK的哪个边沿采样。STC89C52和AT89C51对IO操作没有本质区别,但如果你在Keil里开了优化,可能影响时序,把优化级别设为0(不优化)再试试。

4.3 仿真与实物的差异

仿真通过,实物不一定顺利,区别体现在几个环节:

第一,PT100换电阻模型。仿真中电位器阻值可以稳定在100Ω,但实物的PT100导线长度、焊接点电阻、接线端子阻值都不可忽略。所以实物调试前,先量一下PT100两线之间在室温下的实际阻值,并和万用表校准。如果室温25℃,测出来应该在109.7Ω左右,偏差太大就要检查导线和接点。

第二,运放供电。Proteus里LM358用5V单电源直接仿真,实物也一样。但要注意LM358的输出并不是真正的轨到轨,输出电压最多到3.5~4V左右。解决办法是不要追求满量程5V,把ADC输入范围设计在0.2~4.5V,这样在有效测温区间内,运放能保持线性。

第三,继电器驱动。仿真中继电器只是个开关模型,实物必须加三极管和续流二极管,否则单片机会被继电器线圈的反向电动势打复位。另外继电器吸合时电流比较大,5V继电器线圈电流通常50mA以上,不能直接接在P1口上,驱动电路用S8050加1kΩ基极电阻即可。

第四,电源干扰。实物用USB转串口供电时,容易因为USB带载能力不足导致电压跌落。我建议先用万用表测一下5V电压,再接负载。如果电压波动明显,在电源输入端加一个100μF电解电容和0.1μF瓷片电容,这能解决大部分复位和数字跳动问题。

5. 物料清单、源代码框架与二次扩展

5.1 标准物料清单

做实物时的物料清单如下,仿真时有些元件可以简化:

元件型号/参数数量备注
单片机STC89C52RC1实物可用,仿真用AT89C52
晶振12MHz1配22pF电容两只
复位电路10μF电解电容 + 10kΩ电阻1组标准复位电路
PT100铂热电阻,三线制1温度传感器
运放LM3581双运放
ADCADC08321串行8位ADC
数码管四位共阳7SEG-MPX4-CA1显示温度/设定值
锁存器74HC5732段选和位选驱动
按键轻触开关3SET、INC、DEC
继电器5V继电器1控制加热设备
三极管S80501驱动继电器
二极管1N40071继电器续流
LED红/黄/绿各13状态指示
排阻1kΩ ×81P0口上拉
电阻100Ω、1kΩ、10kΩ、100kΩ若干按原理图配置
电位器100Ω或10kΩ1校准用
蜂鸣器5V有源1可选报警

仿真阶段不需要STC芯片、三极管、继电器,直接用AT89C51和LED代替就能验证逻辑。实测的物料清单和仿真清单分开列,报告会更规范。

5.2 源代码核心模块示例

这里给一个核心代码框架,Keil C51编译通过。首先是ADC0832读取函数,这是最常见的写法:

#include <reg51.h> #include <intrins.h> sbit ADC_CS = P1^0; sbit ADC_CLK = P1^1; sbit ADC_DIO = P1^2; unsigned char adc0832_read(unsigned char channel) { unsigned char i, dat = 0; ADC_CS = 0; ADC_CLK = 0; ADC_DIO = 1; // start bit ADC_CLK = 1; _nop_(); ADC_CLK = 0; ADC_DIO = 1; // single-ended mode ADC_CLK = 1; _nop_(); ADC_CLK = 0; ADC_DIO = channel; // channel select: 0 or 1 ADC_CLK = 1; _nop_(); ADC_CLK = 0; ADC_DIO = 1; // read mode for (i = 0; i < 8; i++) { ADC_CLK = 1; _nop_(); dat = (dat << 1) | ADC_DIO; ADC_CLK = 0; _nop_(); } ADC_CS = 1; return dat; }

ADC0832的通道选择位,通道0时channel=0,通道1时channel=1。这个函数返回8位数据,范围0~255。注意读取数据时DIO要改为输入模式,程序里通过对IO口赋值后又要读取,实际51单片机IO工作在准双向模式,先写1再读是没问题的。

温度采集滤波函数可以这样写:

unsigned int filter_adc(void) { unsigned char i, max, min, temp; unsigned int sum = 0; max = 0; min = 255; for (i = 0; i < 8; i++) { temp = adc0832_read(0); if (temp > max) max = temp; if (temp < min) min = temp; sum += temp; } sum = sum - max - min; // 去掉最大最小值 return sum / 6; // 取平均 }

温度换算部分,根据标定值计算,例如标定adc0=30,adc100=220,则当前温度为:

#define ADC_0C 30 #define ADC_100C 220 int adc_to_temp(unsigned int adc) { int temp; temp = (int)(adc - ADC_0C) * 100 / (ADC_100C - ADC_0C); return temp; }

这个近似公式忽略了非线性,但你可以在报告中说明误差范围。

数码管动态扫描代码不细算了,核心是定时器中断里每隔2ms切换一位,显示缓冲区存放四个位的段码或数字。共阳数码管段码表一般这样定义:

unsigned char code seg_table[10] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90 };

按键扫描函数需要放在主循环或者定时器中断中处理。我习惯在10ms定时器中断里做状态机,主循环只负责取事件标志。上下限控制逻辑放在主循环里:

void control(int temp) { if (temp < lower_limit) { RELAY = 1; // 开启加热 LED_LOW = 1; LED_HIGH = 0; } else if (temp > upper_limit) { RELAY = 0; // 关闭加热 LED_LOW = 0; LED_HIGH = 1; } else { RELAY = 1; // 中间温度维持加热(可选) LED_LOW = 0; LED_HIGH = 0; } }

这里中间区域的策略可以调整。更合理的是加入滞回控制:低于下限加热,加热到上限回差值(比如上限-5℃)再关闭,避免继电器频繁通断。比如设置上限80℃,下限20℃,当温度低于20℃时开启加热,加热到75℃就关闭,而不是非要到80℃才关。这样会减少设备磨损。

5.3 这个项目还能怎么改

做完基础的温度控制后,可以往几个方向扩展:

一是把数码管换成LCD1602。LCD1602能显示“Temp: 25.6℃”和“H:80 L:20”,可读性比数码管强很多,代码量也不会增加太多。

二是引入PID控制。当前实现的开关控制会让温度在上下限之间波动,如果要精确控温,可以用PWM控制加热功率,再配合PID算法。51单片机的运算能力完全够跑一个简单的增量式PID,只需要定时采集温度、计算偏差、输出PWM占空比。

三是增加EEPROM存储功能。用AT24C02把设置好的上下限值存起来,掉电不丢失。这样下次上电不用重新设置,在实物演示时显得更完整。

四是串口通信。单片机每隔1秒把温度通过串口发送到电脑,上位机用Python的pyserial读取并画实时曲线。这个功能很加分,尤其适合做毕设演示,但要注意串口通信和中断优先级的协调。

最后,仿真和实物都一样,硬件上电顺序很重要。先开电源,等1秒再让单片机执行主要逻辑,避免继电器吸合瞬间拉低电压导致复位。可以在main函数开头加一个延时函数,这个看起来没技术含量的小细节,往往能解决很多莫名其妙的问题。

我在实际调试这个项目的时候,最大的体会是:不管Proteus仿真跑得多漂亮,实物上温度显示的校准永远绕不开。把PT100分度表打印出来放在工作台上,用热水和冰水做0℃和100℃附近的粗校准,再用线性公式修正,你的报告和演示效果都会扎实很多。多备几个电位器,每次焊接前先量一遍阻值,这些都是花小钱省大功夫的事。

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

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

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

立即咨询