DS18B20 温度传感器实验探索与实践分享
在嵌入式系统开发领域,温度监测是常见的应用场景。本次实验聚焦于 DS18B20 温度传感器,旨在掌握其工作原理、单总线通信方式,以及实现温度采集与数码管显示,同时开启温度报警功能。接下来,就带大家深入了解整个实验过程。
一、实验目的与内容概述
本次实验主要有三大目标:一是掌握数码管的使用方式,实现数据的可视化呈现;二是深入理解 DS18B20 温度传感器的工作原理,包括其独特的单总线传输机制;三是熟练运用单总线通信方式,完成单片机 MCU 与 DS18B20 之间的数据传输。实验内容围绕学习 DS18B20 的单总线传输,通过单片机 I/O 实现温度采集,并将采集到的温度数据在数码管上显示,同时设置温度报警阈值,当温度超过阈值时触发嗡鸣器报警。
二、实验设计与关键模块解析
(一)整体思路
本实验利用数码管动态显示技术,实现温度五个位的同时显示。程序先判断是否输入转换命令,若有则发送读取温度指令,接着依次读取数据的低字节和高字节,并将其合并。随后,将合并后的数据转换为数码管可显示的段码数,存储在数组中。最后,将转换后的数据与预设阈值比较,根据比较结果决定是否报警并显示温度。
(二)程序流程图
(三)主要模块设计与代码分析
- 读温度模块
- 设计思路:依据单总线协议,逐位从传感器数据线读取数据。初始化变量byte存储字节数据,通过八次循环,每次循环读取一位数据。循环中先拉低数据线,再释放并延时等待数据稳定,然后读取数据存入byte相应位置,循环结束返回读取的字节数据。
- 代码分析:
uchar Ds18b20ReadByte()
{
uchar byte, bi;
uint i, j;
for(j=8; j>0; j--)
{
DSPORT = 0;//先将总线拉低1us
i++;
DSPORT = 1;//然后释放总线
i++;
i++;//延时6us等待数据稳定
bi = DSPORT; //读取数据,从最低位开始读取
/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
byte = (byte >> 1) | (bi << 7);
i = 4; //读取完之后等待48us再接着读取下一个数
while(i--);
}
return byte;
}
- 温度转换模块
- 设计思路:datapros函数接收温度值,将其转换为数码管显示格式。先判断温度正负,负数则添加负号并转换为正数补码形式,接着将温度值乘以 0.0625 再乘以 100,进行四舍五入处理。然后将处理后的温度值分解为各个位数,将对应段码存入DisplayData数组,同时提取百位值用于报警判断。
- 代码分析:
void datapros(int temp) // 温度处理函数,将温度值转换为数码管显示数据
{
float tp; // 临时变量,用于存储温度值的转换结果
if(temp < 0) // 如果温度值小于0
{
DisplayData[0] = 0x40; // 显示负号
temp = temp - 1; // 温度值取反并加1
temp = ~temp; // 对温度值取反
tp = temp; // 将结果存储到临时变量tp
temp = tp * 0.0625 * 100 + 0.5; // 将温度值转化为对应的显示值
}
else // 如果温度值大于等于0
{
DisplayData[0] = 0x00; // 不显示负号
tp = temp; // 将温度值存储到临时变量tp
temp = tp * 0.0625 * 100 + 0.5; // 转换温度值为对应的显示值
}
// 分别计算出各个数字的显示编码
DisplayData[1] = smgduan[temp / 10000]; // 显示万位
DisplayData[2] = smgduan[temp % 10000 / 1000]; // 显示千位
DisplayData[3] = smgduan[temp % 1000 / 100] | 0x80; // 显示百位,带小数点
DisplayData[4] = smgduan[temp % 100 / 10]; // 显示十位
DisplayData[5] = smgduan[temp % 10]; // 显示个位
temp1 = temp % 10000 / 100; // 提取温度的百位值,用于后续报警判断
}
- 显示模块
- 设计思路:DigDisplay函数实现数码管动态显示。通过循环控制 6 个数码管,利用switch语句根据循环变量设置位选信号,选择当前显示的数码管。然后将对应显示数据通过P0端口发送,发送后延时控制显示时间,最后清零P0端口避免干扰,利用视觉暂留效应实现同时显示效果。
- 代码分析:
void DigDisplay() // 数码管显示函数,控制数码管的显示
{
u8 i;
for(i = 0; i < 6; i++) // 循环控制6个数码管的显示
{
switch(i) // 控制不同的数码管显示
{
case(0): // 显示第1个数码管
LSA = 0; LSB = 0; LSC = 0;
break;
case(1): // 显示第2个数码管
LSA = 1; LSB = 0; LSC = 0;
break;
case(2): // 显示第3个数码管
LSA = 0; LSB = 1; LSC = 0;
break;
case(3): // 显示第4个数码管
LSA = 1; LSB = 1; LSC = 0;
break;
case(4): // 显示第5个数码管
LSA = 0; LSB = 0; LSC = 1;
break;
case(5): // 显示第6个数码管
LSA = 1; LSB = 0; LSC = 1;
break;
}
P0 = DisplayData[5 - i]; // 将显示数据传递给P0端口
delay(85); // 延时,控制数码管的显示时间
P0 = 0x00; // 清除P0端口,避免干扰
}
}
- 报警模块
- 设计思路:检查温度是否超过 30 度,若超过则蜂鸣器鸣叫 2000 次,每次间隔 10 毫秒。鸣叫结束后,重新读取并显示温度,最后关闭蜂鸣器。
- 代码分析:
if(temp1 >= 30) // 如果温度超过30度,蜂鸣器报警
{
u16 i = 2000;
while(i--) // 蜂鸣器持续鸣叫2000次
{
BEEP = !BEEP; // 切换蜂鸣器状态
delay(10); // 延时控制蜂鸣器鸣叫频率
}
datapros(Ds18b20ReadTemp()); // 重新读取并处理温度
DigDisplay(); // 更新数码管显示
i = 0;
BEEP = 0; // 关闭蜂鸣器
}
三、实现效果展示
经过代码编写与调试,实验取得了预期效果。正常情况下,数码管能够准确显示当前温度值,如图 1 所示。当用手指触碰传感器,使温度超过 30 度时,蜂鸣器立即发出报警声,同时数码管持续显示实时温度,如图
四、实验总结与心得体会
(一)心得体会
通过本次实验,我对单片机编程和硬件交互有了更深入的理解。从温度传感器数据读取到数码管显示,再到报警功能实现,每一个环节都让我体会到嵌入式系统开发的魅力与挑战。同时,也提升了自己解决实际工程问题的能力,尤其是在时序控制和调试方面积累了宝贵经验。
(二)遇到的困难与解决方法
- 编程模型不熟悉:初期因对单片机编程模型陌生,在编写温度读取和处理函数时困难重重。通过查阅数据手册和在线教程,逐步熟悉 51 单片机寄存器和编程模型,改进了相关代码。
- 硬件连接错误:硬件连接不正确导致无法读取温度数据。经仔细检查电路图并多次尝试,确保了 DS18B20 传感器与单片机 I/O 端口的正确连接,使传感器正常工作。
- 延时函数问题:延时函数不精确影响数码管显示和蜂鸣器报警逻辑。通过调整延时函数循环计数,精确控制时间,改善了显示和报警效果。
这次 DS18B20 温度传感器实验不仅是一次技术实践,更是一次学习成长的过程。希望我的分享能对大家在嵌入式系统开发学习中有所帮助,如果你在实验过程中有任何问题或新的想法,欢迎在评论区交流讨论!