简介:本资源是一套完整的单片机多点温度监控系统毕业设计/课程设计资料,面向电子信息、自动化等专业本科生及单片机初学者,解决传统热敏电阻测温精度低、需复杂信号调理的问题。方案以STC90C516RD单片机为核心,集成3路DS18B20数字温度传感器实现0℃~100℃高精度多点测温,支持数码管本地实时显示、PC端串口监控及超限蜂鸣报警,并精准标识异常测点,具备工程落地可行性。压缩包共45个文件(17.6MB),涵盖Proteus仿真工程(.pdsprj/.workspace)、Keil C源码(.c/.hex/.uvproj)、Protel 99SE原理图与PCB设计文件(.sch/.pcb)、系统论文文档(.docx)及关键效果图(.jpg/.bmp),结构完整、模块清晰,便于从仿真验证、代码调试到硬件制板全流程学习。目前已有234人下载学习,是掌握单片机外设驱动、1-Wire通信、数码管动态扫描及毕业设计文档撰写的优质实践范例。
1. 为什么用STC90C51+DS18B20做多点测温,还非得配数码管和Proteus仿真?
你手头有一块STC90C51单片机开发板,想实现3路以上温度采集,但发现串口打印太慢、LCD驱动太占资源、OLED又贵——这时候,用共阳极7段数码管动态扫描显示实时温度值,反而是最稳、最省、最易调试的落地方案。STC90C51虽是经典8位MCU,但其增强型ISP功能支持在线编程,配合DS18B20的单总线协议,能用一根IO口挂载多个传感器(实测6个无冲突),省掉ADC和信号调理电路;而Proteus仿真不是“画着玩”,它能真实复现DS18B20的时序敏感性——比如reset pulse低电平必须维持480μs±10%,否则初始化失败;再比如读取温度后需执行skip ROM指令跳过ROM校验,否则多点通信会卡死。本方案覆盖从Proteus建模、Keil C51编码、Protel 99SE原理图与PCB设计,到毕业论文级文档组织的全链路,适合电子类课程设计、毕设及小批量工业温控模块原型验证。重点不在“能不能跑”,而在“怎么让每一路DS18B20在STC90C51上稳定读出±0.5℃精度,且3位数码管不闪烁、不乱码”。
2. STC90C51与DS18B20单总线通信:时序控制与多点寻址实战
DS18B20与STC90C51之间仅靠一根数据线(DQ)完成供电、时钟、数据三重功能,这种单总线协议对IO口翻转精度要求极高。STC90C51内部没有硬件单总线控制器,必须用软件精确模拟时序,而常见误区是直接套用“延时函数+while循环”——这在Keil C51默认编译优化下极易失准。正确做法是关闭编译器优化(Project → Options for Target → C51 → Optimization Level = 0),并采用空指令循环法生成微秒级延时。
2.1 DS18B20初始化时序的C51硬编码实现
// 定义DQ引脚为P1.0(需在Keil中确认P1口已配置为准双向模式) sbit DQ = P1^0; void DS18B20_Init(void) { unsigned char i; DQ = 1; _nop_(); _nop_(); // 拉高总线,准备复位 DQ = 0; // 主机发出复位脉冲 for(i=0; i<48; i++) _nop_(); // 精确延时480μs(12MHz晶振下,1_nop_=1μs) DQ = 1; // 释放总线 for(i=0; i<6; i++) _nop_(); // 延时60μs,等待DS18B20响应 while(DQ); // 检测存在脉冲(60~240μs低电平) for(i=0; i<40; i++) _nop_(); // 延时400μs,确保采样完成 }提示:
_nop_()是Keil C51内置空操作指令,比delay_us()更可靠。若使用11.0592MHz晶振,需按比例调整循环次数(如11.0592MHz下1_nop_=0.904μs,480μs需约531次_nop_)。实测中,若存在脉冲检测失败,优先检查DQ上拉电阻——必须为4.7kΩ,阻值过大导致上升沿过缓,过小则DS18B20供电不足。
2.2 多点DS18B20的ROM地址读取与跳过ROM指令
单总线上挂多个DS18B20时,必须区分设备。标准流程是先发送0x33(Read ROM)指令读取每个传感器的64位唯一ROM码,再用0x55(Match ROM)指令定向访问。但实际工程中,若所有传感器型号一致且无需单独标定,跳过ROM(Skip ROM, 0xCC)是最优选择——它省去地址比对开销,使读取速度提升40%,且避免因地址错位导致的通信中断。
void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for(i=0; i<8; i++) { DQ = 0; _nop_(); _nop_(); if(dat & 0x01) DQ = 1; else DQ = 0; for(i=0; i<6; i++) _nop_(); // 60μs采样窗口 DQ = 1; for(i=0; i<1; i++) _nop_(); // 恢复高电平 dat >>= 1; } } void DS18B20_ReadTemp(unsigned char *temp_high, unsigned char *temp_low) { DS18B20_Init(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // Convert T // 等待转换完成(750ms @12-bit分辨率) for(unsigned int i=0; i<75000; i++) _nop_(); DS18B20_Init(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0xBE); // Read Scratchpad *temp_low = DS18B20_ReadByte(); *temp_high = DS18B20_ReadByte(); }注意:
DS18B20_ReadByte()需实现严格的读时序——主机在下降沿后15μs采样,此处省略具体代码,但关键点在于:读0时DS18B20拉低总线60μs,读1时保持高电平15μs后释放。若读出全0xFF,大概率是初始化失败或电源不足(DS18B20寄生供电模式下,VDD未接会导致转换失败)。
2.3 STC90C51内存分配与温度数据结构化存储
STC90C51片内RAM仅1280字节,需精打细算。3路DS18B20温度值(各2字节)+ 数码管显示缓冲区(3字节×3路=9字节)+ 系统变量(计数器、状态标志等)总计约20字节,完全可置于内部RAM。但关键在于避免全局变量跨函数调用导致栈溢出——Keil C51默认small模式下,函数参数和局部变量存于内部RAM,若某函数定义了大数组(如unsigned char buf[100]),立即触发?STACK溢出错误。
// 推荐定义方式:全部置于xdata段(外部RAM),STC90C51默认启用XRAM unsigned char xdata temp_data[3][2]; // 存储3路温度高低字节 unsigned char xdata seg_buf[3][3]; // 每路3位数码管显示缓冲:百/十/个位 unsigned char xdata seg_code[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; // 共阳极段码 // 温度值转BCD并存入显示缓冲区(核心算法) void TempToBCD(unsigned char high, unsigned char low, unsigned char *buf) { unsigned int temp_val = (high << 8) | low; // 合成16位值 if(temp_val & 0x8000) temp_val = -temp_val; // 补码转正数 temp_val = (temp_val * 10 + 8) / 16; // 转为整数温度(DS18B20分辨率0.0625℃,*10保留一位小数) buf[0] = temp_val / 100; // 百位 buf[1] = (temp_val % 100) / 10; // 十位 buf[2] = temp_val % 10; // 个位 }提示:
temp_val = (temp_val * 10 + 8) / 16是整数除法四舍五入技巧,避免浮点运算(STC90C51无FPU,float库占用超2KB Flash)。若需显示负号,seg_code需扩展为11元素,增加0xBF(共阳极“-”段码),并在TempToBCD中判断符号位后置buf[0]=10。
3. 3位共阳极数码管动态扫描:消隐、亮度均衡与抗干扰布线
数码管显示的核心矛盾是:人眼视觉暂留要求刷新率>60Hz,而STC90C51处理3路温度采集+转换+显示需耗时约15ms,若每路独立刷新将导致明显闪烁。解决方案是分时复用+消隐控制——用P2口3位输出选通3个数码管位,P0口8位输出段码,每次仅点亮1位,持续0.5ms后切换,3位循环一周1.5ms,远高于临界闪烁频率。
3.1 数码管驱动电路与Protel原理图关键设计
在Protel 99SE原理图中,必须明确以下三点:
- 位选信号加限流电阻:P2.0~P2.2经1kΩ电阻接至NPN三极管(如S8050)基极,三极管集电极接数码管公共端(共阳极),发射极接地。此举避免P2口直接灌电流超限(STC90C51单IO灌电流≤20mA)。
- 段码输出加驱动芯片:P0口接74HC245双向总线驱动器,输出端经330Ω电阻接数码管a~g及dp段。74HC245提供20mA驱动能力,解决P0口上拉能力弱问题。
- 电源滤波不可省略:在数码管供电VCC处并联100μF电解电容+0.1μF陶瓷电容,抑制动态扫描引起的电压跌落。
| 元件 | 参数 | 作用 |
|---|---|---|
| S8050三极管 | β≥100, Ic=500mA | 放大位选电流,隔离MCU |
| 74HC245 | Vcc=5V, Io=35mA | 增强段码驱动能力 |
| 330Ω电阻(8个) | 精度±5% | 匹配LED段压降(2.0V@20mA),保证亮度一致 |
注意:若原理图中直接用P0口驱动数码管(无74HC245),则必须在P0口外接10kΩ上拉排阻——但此方案在动态扫描时,因P0口内部上拉弱,导致段码暗淡且易受干扰。Protel PCB布线时,数码管位线(P2.0~P2.2)与段码线(P0.0~P0.7)必须远离晶振走线(≥10mm),否则高频噪声会耦合进数码管导致鬼影。
3.2 动态扫描中断服务程序(Timer0定时器)
// Timer0初始化:12MHz晶振,定时0.5ms(初值TH0=0xFE, TL0=0x0C) void Timer0_Init(void) { TMOD |= 0x01; // 方式1,16位定时 TH0 = 0xFE; TL0 = 0x0C; ET0 = 1; // 开启T0中断 TR0 = 1; // 启动定时器 } // 中断服务程序:每0.5ms执行一次 void Timer0_ISR(void) interrupt 1 { static unsigned char pos = 0; TH0 = 0xFE; TL0 = 0x0C; // 重装初值 // 消隐:关闭所有位选,清除段码 P2 = 0xFF; P0 = 0xFF; // 输出当前位段码 P0 = seg_code[seg_buf[pos][0]]; // 百位 switch(pos) { case 0: P2 = 0xFE; break; // 选通第1位(P2.0=0) case 1: P2 = 0xFD; break; // 选通第2位(P2.1=0) case 2: P2 = 0xFB; break; // 选通第3位(P2.2=0) } pos = (pos + 1) % 3; }提示:
P2 = 0xFF在消隐阶段必须执行,否则前一位残留电平会导致“重影”。若发现某位数码管始终偏暗,用示波器测P2.x波形——正常应为方波,占空比33%,若占空比异常(如<20%),检查pos变量是否被其他中断修改(需声明为volatile)。
3.3 抗干扰显示优化:软件消抖与亮度自适应
环境光变化时,固定段码电流会导致白天看不清、夜晚刺眼。本方案采用亮度分级控制:通过ADC读取光敏电阻分压值(接P1.1),映射为3档亮度(高/中/低),动态调整段码输出时间。
unsigned char light_level = 1; // 0=低亮,1=中亮,2=高亮 void AdjustBrightness(void) { unsigned int adc_val; // 假设ADC已初始化,读取P1.1通道 adc_val = GetADCValue(1); // 返回0~255 if(adc_val < 85) light_level = 2; // 暗环境→高亮 else if(adc_val < 170) light_level = 1; // 中等→中亮 else light_level = 0; // 亮环境→低亮 } // 修改Timer0_ISR中的段码输出部分: // 根据light_level调整P0输出时间(通过延时微调) if(light_level == 2) { P0 = seg_code[seg_buf[pos][0]]; _nop_(); _nop_(); _nop_(); } else if(light_level == 1) { P0 = seg_code[seg_buf[pos][0]]; _nop_(); _nop_(); } else { P0 = seg_code[seg_buf[pos][0]]; _nop_(); }注意:此方法不改变电流,仅延长LED导通时间,符合人眼亮度感知对数特性。实测在0~1000lux照度范围内,3档亮度切换无阶跃感。
4. Proteus仿真全流程:从元件库加载到时序波形验证
Proteus 8 Professional是当前主流版本,其元件库对STC90C51和DS18B20的支持需手动配置。网络热词中频繁出现的“proteus下载安装”“proteus元件库”问题,根源在于官方库未包含STC系列——必须导入第三方模型。
4.1 STC90C51与DS18B20模型导入与引脚映射
- 下载
STC90C51.LIB和DS18B20.DSN文件(来自STC官网或Proteus用户社区); - 在Proteus中点击
System → Set Paths,添加LIB路径; - 打开
Library → Library Manager,点击Add导入.LIB文件; - 关键步骤:右键STC90C51元件 →
Edit Properties→ 将Clock Frequency设为12MHz,Program File指向Keil生成的.hex文件; - DS18B20属性中,
Model Type选DS18B20,Package选TO-92,Power Pins勾选VDD(启用外部供电模式,避免寄生供电仿真不准)。
提示:若仿真中DS18B20始终返回85℃(默认上电值),说明未正确连接VDD引脚——Proteus中DS18B20有3个引脚:GND、VDD、DQ,必须将VDD接+5V,否则进入寄生供电模式,而Proteus对该模式时序仿真存在偏差。
4.2 多点DS18B20总线拓扑与上拉电阻设置
在Proteus中绘制单总线时,严禁星型连接(所有DS18B20 DQ线直接汇至MCU),必须采用手拉手菊花链:MCU-DQ → R4.7k → DS18B20-1-DQ → R4.7k → DS18B20-2-DQ → ... → DS18B20-n-DQ。每段DQ线长度在仿真中设为10mm(对应实际20cm),以模拟分布电容效应。
| 连接点 | 电阻值 | 作用 |
|---|---|---|
| MCU与DS18B20-1之间 | 4.7kΩ | 主上拉,确保空闲高电平 |
| DS18B20-1与DS18B20-2之间 | 0Ω(直连) | 避免信号反射 |
| DS18B20-n末端 | 无电阻 | 防止末端反射 |
注意:若仿真中出现“存在脉冲检测失败”,90%原因是上拉电阻位置错误或阻值过大(>10kΩ)。Proteus中可右键电阻 →
Edit Properties→Resistance实时修改验证。
4.3 使用Proteus Logic Analyzer捕获DS18B20时序波形
这是验证单总线通信正确性的黄金方法:
- 在原理图中添加
Logic Analyzer(位于Virtual Instruments库); - 将其通道0连接至DQ线;
- 设置采样率:
10MHz(需捕捉1μs级脉冲); - 触发条件设为
Falling Edge,触发电平2.5V; - 运行仿真,点击
Start后立即暂停,观察波形。
合格波形特征:
- 复位脉冲:低电平宽度480μs±10μs;
- 存在脉冲:DS18B20拉低60~240μs;
- 写0时序:主机拉低15μs后释放,DS18B20拉低60μs;
- 读0时序:主机采样点(下降沿后15μs)处电平为低。
若波形失真,检查Keil中_nop_()数量是否匹配晶振频率——这是Proteus仿真与实物调试差异最大的环节。
5. Protel 99SE PCB设计要点:单面板布线与热设计
Protel 99SE虽是旧版工具,但其规则驱动布线(Auto Router)对单面板设计仍具优势。本项目PCB采用单面设计(降低成本),关键约束是:DS18B20焊盘必须加大,且底部铺铜散热。
5.1 元件布局黄金法则:温度传感器远离热源
在Protel 99SE中,按以下顺序布局:
- STC90C51置于板中心,P0/P2口朝向数码管区域;
- 3个DS18B20呈三角形分布在板边缘,间距≥50mm(避免热辐射干扰);
- 数码管紧邻P2口,位线走线最短;
- 晶振(12MHz)紧贴STC90C51的XTAL1/XTAL2引脚,走线≤5mm,两侧加22pF负载电容。
提示:DS18B20的TO-92封装在Protel库中焊盘尺寸常为Φ1.0mm,但实测焊接时易脱落。应在
Library Editor中修改焊盘:外径Φ2.0mm,内径Φ1.2mm,并在焊盘周围添加泪滴(Teardrop)——Protel中执行Tools → Teardrops,设置Width=0.5mm。
5.2 单面板布线策略与安全间距
单面板无法打过孔,所有走线必须绕行。关键规则:
- 电源线宽度≥20mil(0.5mm),地线加粗至30mil;
- 信号线最小宽度10mil(0.25mm),DS18B20 DQ线全程包地(Ground Plane);
- 禁止90°拐角,全部采用45°或圆弧过渡(
Design → Rules → Routing → Preferred Angle = 45); - DS18B20 DQ线与晶振线间距≥25mil(0.6mm),防止串扰。
| 网络名 | 线宽(mil) | 用途 | 特殊要求 |
|---|---|---|---|
| VCC | 20 | 电源 | 加铺铜 |
| GND | 30 | 地 | 全板铺铜,与DS18B20焊盘连接 |
| DQ | 12 | 单总线 | 全程包地,长度≤100mm |
| SEG_A~G | 10 | 段码 | 与位线垂直布线 |
5.3 热设计验证:红外热像仪实测对比
PCB投产前,必须验证DS18B20测温准确性。方法:
- 将PCB置于恒温箱(设定40℃),用FLIR ONE Pro红外热像仪拍摄PCB表面;
- 读取DS18B20焊盘区域温度(热像仪测温点对准TO-92金属外壳);
- 对比DS18B20读数与热像仪读数,误差应<0.5℃。
若误差>1℃,原因通常是:
- DS18B20焊盘未铺铜(导致热传导慢);
- PCB靠近电源芯片(如7805)未加隔热槽;
- 数码管长时间点亮产生热辐射(解决方案:在数码管与DS18B20间加0.5mm厚聚酰亚胺隔热片)。
注意:Protel 99SE中可在
Keep Out Layer绘制矩形框标记“热敏感区”,禁止在此区域内布放功率器件或大电流走线。
本文还有配套的精品资源,点击获取