简介:基于51单片机的热电偶测温设计项目,提供程序、仿真与文档一体化的完整方案,适合单片机初学者、课程设计及工业测温应用开发者参考。系统以AT89C51为核心,搭配PT100热电偶、TDA2030放大、ADC0808转换,实现温度采集、数码管显示与声光报警,覆盖硬件电路和软件算法双重设计。包内共57个文件,整体约13.66MB,以Keil工程源文件(.c/.h/.uvproj)、Proteus仿真文件(.pdsprj/.dsn)、PDF说明文档、Word论文材料及配套元件技术手册为主,另含操作演示视频和JPG预览图,便于按目录快速定位学习。已有71人学习使用,资料从使用说明、源程序到仿真验证层层递进,可帮助读者快速上手PT100测温方案,理解模数转换与显示报警逻辑,适合直接用于课程设计或项目原型搭建。
1. 热电偶测温为什么非要用 ADC0808 和 51 单片机
热电偶输出的是毫伏级缓慢变化电压,51 单片机本身没有任何模拟采集能力,要读数就得外挂一个 A/D 转换器。ADC0808 在这个设计里的位置很关键:它把经过放大的热电偶电压变成 8 位数字量,51 再按查表或公式还原成温度,最后送到 SEG4 数码管显示,超限时触发 BZ 蜂鸣器。整套链路典型、成本低,是课程设计和电子竞赛入门最常见的架构。很多人做这类题目会卡在两点:ADC0808 的地址锁存、启动转换和读数据时序没有理顺;放大电路增益设得太大或太小,导致热电偶的毫伏信号要么削顶要么落在 ADC 分辨率之外。这篇文章按“信号链”顺序讲清楚采样端怎么搭、程序怎么写、仿真怎么调,最后补一点冷端补偿和滤波的经验,属于直接可以动手复现的那种写法。
2. 硬件链路:热电偶放大、ADC0808 与 51 的接口连接
2.1 热电偶输出信号与 ADC0808 输入范围的电压匹配
K 型热电偶的灵敏度大约是 40μV/℃,在 0 到 200℃ 范围内热电动势只有 0 到 8mV 左右。ADC0808 的模拟输入量程是 0~5V,如果不做放大,8mV 电压换算成 8 位数字量只占 0.4 个 LSB,结果要么是 0 要么是 1,完全测不了温差。因此信号调理的第一件事是确定放大倍数。
ADC0808 是 8 位逐次逼近型转换器,分辨率是满量程电压除以 256。若供电和基准都为 5V,每个 LSB 对应约 19.5mV。若希望 0.8℃ 的变化能体现在一个数字码上,则热电偶侧每码需要对应 32μV 左右,放大倍数取:
Gain = 19.5mV / (40μV/℃ × 0.8℃) ≈ 610实际电路通常取 500~600 倍,用两级放大或者一级仪表放大器实现。一级同相比例放大器用 OP07 这类低失调运放,反馈电阻取 Rf=510kΩ、R1=1kΩ,增益就是 511 倍,刚好落在量程附近。
提示:增益不是越大越好。200℃ 时热电偶输出 8.137mV,放大 511 倍后是 4.16V,不削顶;若用 1000 倍增益,200℃ 时输出 8.1V,超过 5V 会被截止,这时高位码全为 1,温度显示直接溢出。
在实际设计中还应在 ADC 输入端加入电压跟随器或 RC 低通滤波,把高频干扰滤掉。常见做法是在运放输出与 IN0 之间串一个 1kΩ 电阻,再对地接 0.1μF 电容,形成约 1.6kHz 截止频率的低通滤波,避免工频和开关噪声混入采样值。
2.2 ADC0808 与 51 单片机的引脚连接方式
ADC0808 是 28 脚芯片,内部带有 8 路模拟开关,但实际使用中只需要一路或两路输入。地址线 ADDA、ADDB、ADDC 决定选通哪一路模拟输入,例如 000 对应 IN0,001 对应 IN1。地址锁存使能 ALE 与启动转换 START 可以接同一个 IO 口,因为转换启动时必须同时锁存通道地址。
下面是一个可用的引脚映射表,数码管显示部分使用 P0 口作为段码输出,P2 口高位作为位选,蜂鸣器接 P2.7:
| ADC0808 引脚 | 51 单片机引脚 | 功能说明 |
|---|---|---|
| D0 ~ D7 | P1.0 ~ P1.7 | 8 位数字量输出 |
| ADDA、ADDB、ADDC | P2.0、P2.1、P2.2 | 通道选择,000 选 IN0 |
| ALE | P3.0 | 地址锁存,高有效,与 START 并联 |
| START | P3.0 | 转换启动,下降沿有效 |
| EOC | P3.1 | 转换结束指示,低电平表示转换中 |
| OE | P3.2 | 输出使能,高电平时 D0-D7 输出数据 |
| CLOCK | 500kHz 方波 | 最大不能超过 640kHz |
| VREF+、VREF- | +5V、GND | 基准电压 |
注意 CLOCK 这一路,样例资料里常直接接单片机 ALE 引脚。但 12MHz 晶振下 ALE 输出 2MHz,超过 ADC0808 上限 640kHz,转换结果会不稳定。解决办法有两种:一是在仿真里加一个频率为 500kHz 的方波信号源接到 CLOCK;二是在实物中用 74LS74 双 D 触发器把 ALE 四分频到 500kHz。
2.3 SEG4 数码管与 BZ 蜂鸣器驱动要点
SEG4 指 4 位一体的数码管,本设计显示温度值加一个符号位,例如 015 显示为三位数字,最高位熄灭或显示“C”。可以选用共阴或共阳数码管,区别仅在段码表不同。采用动态扫描方式时,4 个位选引脚轮流拉低,P0 口依次送出对应位段码。由于 P0 口内部没有上拉电阻,驱动共阴数码管段码时必须在 P0 口体外加上拉排阻,否则段码高电平会被拉低,数码管亮度不足。
蜂鸣器驱动不要直接把 IO 口接蜂鸣器。51 的 P2 口灌电流虽然可达 20mA,但课程设计中为了避免端口电流超限,通常用 NPN 三极管驱动。P2.7 输出高电平时三极管导通,蜂鸣器发声;输出低电平时关闭。代码中可以用一个阈值变量控制:
if (temperature > threshold) { BZ = 0; // 高电平驱动三极管导通,默认低电平关断 }3. 软件实现:ADC0808 时序驱动、温度换算与显示
3.1 ADC0808 转换时序:启动、等待 EOC、读取数据的 C 语言写法
ADC0808 的控制时序分为三阶段:先通过 ALE 锁存通道地址,再给 START 一个下降沿启动转换,然后持续查询 EOC;EOC 由低变高表示转换完成,最后让 OE 输出高电平,从 P1 口读取数据。由于 ALE 和 START 并联在同一根线上,产生一个下降沿就同时完成了地址锁存和启动。
#include <reg51.h> sbit AD_ALE_START = P3^0; sbit AD_EOC = P3^1; sbit AD_OE = P3^2; unsigned char adc_read(unsigned char channel) { unsigned char dat; channel &= 0x07; P2 = (P2 & 0xF8) | channel; // 通道号写入 ADDA/ADDB/ADDC AD_OE = 0; // 禁止输出 AD_ALE_START = 0; AD_ALE_START = 1; // 高电平准备 AD_ALE_START = 0; // 下降沿启动转换 while (AD_EOC == 0); // 等待转换完成 AD_OE = 1; // 打开三态输出 dat = P1; // 读取转换结果 AD_OE = 0; return dat; }这段代码的关键点在于三个顺序:先通过 P2 低三位设置通道地址,再制造 START 下降沿启动转换,最后等待 EOC 变高后使能 OE 读取 P1 口。注意 P1 口此时必须配置为准双向模式,51 的 P1 口默认就是准双向,直接读没有问题。
如果程序在等待 EOC 处死循环,仿真中经常会卡住。稳妥的处理是加一个超时计数器,例如查询 1000 次后若 EOC 仍无变化,则强制读取一次或返回上一帧数据,防止 ADC 时钟线接触不良时程序跑飞。
3.2 从 ADC 数字量还原为温度:K 型热电偶的分段线性表
ADC0808 返回的是 0~255 的数字量,需要先换算成输入电压,再换算成热电偶电动势,最后通过查表得到温度。假设放大增益为 511 倍,输入电压与数字量的关系是:
voltage = adc_value * 5.0 / 255.0 // 单位 V thermal_mv = voltage * 1000.0 / 511.0 // 单位 mV得到电动势后直接用线性公式换算误差太大,因为热电偶是非线性传感器。推荐做法是建立一个稀疏分度表,只存 0℃ 到 250℃ 每 10℃ 一个点的热电动势,然后做线性插值。K 型热电偶的分度表数据大致如下(以典型手册为准):
| 温度 ℃ | 热电动势 mV |
|---|---|
| 0 | 0.000 |
| 10 | 0.397 |
| 20 | 0.798 |
| 30 | 1.203 |
| 40 | 1.611 |
| 50 | 2.022 |
| 60 | 2.436 |
| 100 | 4.095 |
| 150 | 6.137 |
| 200 | 8.137 |
代码中可以把表格拆成两个数组:temp_table[25]与mv_table[25]。每次采样后先用 ADC 值算thermal_mv,然后在mv_table中找到相邻的两个点做插值:
float mv_to_temperature(float mv) { unsigned char i; float ratio; for (i = 0; i < 24; i++) { if (mv <= mv_table[i + 1]) { ratio = (mv - mv_table[i]) / (mv_table[i + 1] - mv_table[i]); return temp_table[i] + ratio * 10.0; } } return temp_table[24]; }这样处理比直接乘以系数准确得多,尤其在 150℃ 以上区域,线性系数法的误差会超过 5℃,而分段线性插值可以把误差压缩到 0.5℃ 以内。
3.3 数码管动态扫描与蜂鸣器报警逻辑
数码管动态扫描依赖定时器中断,每隔 2ms 切换到下一位。P0 口喂段码,P2 口控制位选。温度显示范围 0~250℃,数码管布局为百位、十位、个位加一个符号位。段码表按共阴数码管定义:
unsigned char code seg_table[] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F };定时器 T0 配置为 2ms 中断,每次中断修改位选并送出段码。报警逻辑放在主循环中读取温度之后,这里加了 30℃ 的回差,防止温度在阈值附近抖动时蜂鸣器反复开关。
if (temperature > threshold) { beep_count++; if (beep_count > 50) BZ = 0; } else { beep_count = 0; BZ = 1; }beep_count的作用是消抖,连续 100ms 超过阈值才触发报警。
4. Proteus 仿真搭建:从信号源到数码管显示调通的步骤
4.1 仿真元件清单与核心连线
Proteus 仿真中使用的器件型号如下:
| 元件 | Proteus 关键字 | 参数设置 |
|---|---|---|
| 单片机 | AT89C51 | 晶振 12MHz |
| ADC | ADC0808 | VREF+ 接 +5V |
| 运放 | OP07 | 差模放大,增益 511 倍 |
| 数码管 | 7SEG-MPX4-CA | 共阳或共阴,注意段码表 |
| 信号源 | SIGNAL GENERATOR | 输出 10mV 直流,模拟热电偶 |
| 方波源 | PULSE | 频率 500kHz,幅值 5V,接 CLOCK |
操作中先把 OP07 搭成同相放大电路,输入接信号发生器的直流电压,输出接 ADC0808 的 IN0 脚,然后用电压表量一下放大后的输出是否落在 0~5V 区间。如果信号源设为 4mV 而放大后应当为 2.04V,与实际偏差过大,优先检查反馈电阻阻值。
4.2 仿真调试中的三个关键验证点
第一个验证点是 ADC 时钟。Proteus 里直接双击信号源,设置为 500kHz 方波,接到 ADC0808 的 CLOCK 脚。如果忘记接时钟,EOC 永远不会变高,程序会卡在while (AD_EOC == 0);这一行。需要判断是没启动转换还是时钟未到达,可以在 EOC 引脚上放一个虚拟示波器观察波形。
第二个验证点是显示通路。先把adc_read(0)的返回值原样显示在数码管上,不换算温度,比如给信号源 2.5V 电压,ADC 读数应该在 128 左右。如果读数不对,用虚拟示波器观察 OE 使能期间的 P1 口数据是否与 D0-D7 一致。常见错误是把 P1 口既当输入又当输出,读数据前被其他函数改写。
第三个验证点是极性。信号发生器输出不能为负电压,若接反或输入超过 VREF+,数码管会显示 0 或 255 这种极值,而不是真实温度。改用滑动变阻器 POT-HG 分压得到 0~5V 模拟信号,比信号发生器更直观。调通后再把信号源替换成 4mV 模拟 100℃ 热电偶输出电压,观察显示结果是否落在 98~102℃ 区间。
5. 进阶工程处理:冷端补偿、PT100 辅助通道与滤波标定
热电偶测的是热端与冷端的温差,冷端如果悬在空气中,环境温度变化直接影响测量结果。实测中常把冷端置于接线端子,温度可能是 25℃ 也可能是 35℃,不补偿就是 10℃ 误差。标题里的 PT100 在这里派上用场:把 PT100 贴在冷端,用 ADC0808 的 IN1 通道采样 PT100 电桥输出电压,得到冷端温度,再从热端电动势中加上冷端对应的电动势,这是标准的硬件冷端补偿方案的软件实现。
代码上很简单,先读 IN0 得到热端电动势e_hot,再读 IN1 计算冷端温度t_cold,通过查表得到e_cold,最终真实电动势为e_real = e_hot + e_cold,再用e_real反查温度表。注意 ADC0808 是 8 位分辨率,冷端温度精度有 ±1℃ 的抖动,可以采 5 次取中位值:
unsigned char adc_filter(unsigned char ch) { unsigned char i, j, tmp; unsigned char buf[5]; for (i = 0; i < 5; i++) buf[i] = adc_read(ch); for (i = 0; i < 4; i++) { for (j = i + 1; j < 5; j++) { if (buf[j] < buf[i]) { tmp = buf[i]; buf[i] = buf[j]; buf[j] = tmp; } } } return buf[2]; }量程标定方面,建议在 0℃ 和 100℃ 两个点做两点校准。0℃ 用冰水混合物,100℃ 用沸水。先记录 ADC 读数,再反推实际的放大增益,替换代码里的 511.0 常数。这样可以把 OP07 反馈电阻精度和热电偶导线电阻引起的系统误差一起消除。仿真中用电压源模拟时不涉及这个问题,但在实物联调时两点标定是保证精度的关键一步。
本文还有配套的精品资源,点击获取