一、项目介绍
温度检测是工业自动化、生产线等众多领域中常见的应用场景之一,能及时准确地监测温度对于保障生产安全和提高生产效率有着非常重要的作用。而在现代的电子制造行业中,使用单片机和传感器等电子元器件进行温度检测已经成为了一个比较成熟的技术方案。
本项目选择STC89C52单片机和DS18B20数字温度传感器,通过读取传感器输出的温度值,经过计算和处理后,并将结果显示在数码管上,实现环境温度的实时监测和显示。其中,STC89C52单片机为主控芯片,负责接收和处理数字温度传感器的数据,并通过数码管将温度值进行显示。
二、整体设计
【1】设计思路
使用 STC89C52 单片机和 DS18B20 数字温度传感器,通过 I/O 口进行连接,读取传感器输出的温度值。通过计算和处理后,将温度值在数码管上进行显示。其中,STC89C52 单片机为主控芯片,负责接收和处理数字温度传感器的数据,并通过数码管将温度值进行显示。
【2】硬件连接
硬件方面,需要使用 STC89C52 单片机和 DS18B20 数字温度传感器。其中,STC89C52 单片机通过 P1 口连接4位数码管的动态扫描信号线,并与 DS18B20 传感器的 DQ 线相连。DS18B20需要使用一个2.2K欧姆上拉电阻和一个10K欧姆下拉电阻。
【3】软件设计
在软件方面,主要进行以下操作:
(1)初始化函数
初始化串行总线,设置为推挽输出,并将数码管段选端口初始化为高电平输出,数码管位选端口初始化为低电平输出。
(2)读取温度值函数
通过发送读取命令,从 DS18B20 数字温度传感器中读取温度值。
(3)温度值计算函数
根据 DS18B20 数字温度传感器的温度值计算方法,将读取到的数值进行转换,得到实际温度值。
(4)数码管显示函数
将温度值分离出整数和小数部分,然后经过数码管驱动程序,通过数码管进行显示。
三、具体代码实现
【1】DS18B20温度读取
DS18B20 是一种数字温度传感器,采用单总线接口进行通讯。它可以在较长的距离内实现温度值的准确测量,并且不需要调零或校准,被广泛应用于各种计算机控制系统、电子设备和温度控制应用中。其分辨率为 12 位,温度范围为 -55 度 Celsius 到 +125 度 Celsius。
下面代码实现的功能是:读取DS18B20温度再通过串口打印出来。
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P1^0; // DS18B20 数字温度传感器数据线连接到 P1.0 引脚
// DS18B20 数据传输函数
void DS18B20_WriteByte(uchar dat);
uchar DS18B20_ReadByte();
void DS18B20_Start();
void DS18B20_End();
void DS18B20_Delay(uint i);
// 初始化函数
void init();
// 串口初始化函数
void uart_init();
// 串口发送函数
void send_string(char *s);
void main()
{
uchar temp_h, temp_l;
uint temp;
init();
uart_init(); // 串口初始化
while(1)
{
DS18B20_Start(); // 启动传输
DS18B20_WriteByte(0xCC); // 忽略 ROM 指令
DS18B20_WriteByte(0x44); // 发送温度转换指令
DS18B20_End(); // 结束传输
DS18B20_Start(); // 启动传输
DS18B20_WriteByte(0xCC); // 忽略 ROM 指令
DS18B20_WriteByte(0xBE); // 发送读取指令
// 读取温度值
temp_l = DS18B20_ReadByte(); // 读取低位温度值
temp_h = DS18B20_ReadByte(); // 读取高位温度值
// 计算温度值
temp = (temp_h << 8) + temp_l;
temp = (float)temp / 16;
send_string("The temperature is: ");
send_string(temp);
send_string("\r\n");
DS18B20_End(); // 结束传输
}
}
// DS18B20 数据传输函数
void DS18B20_WriteByte(uchar dat)
{
uchar i;
for (i = 0; i < 8; i++)
{
DQ = 0; // 写时序开始
DQ = dat & 0x01; // 写数据
DS18B20_Delay(1); // 延时 1us
DQ = 1; // 写时序结束
dat >>= 1;
}
}
uchar DS18B20_ReadByte()
{
uchar i, dat = 0;
for (i = 0; i < 8; i++)
{
DQ = 0; // 读时序开始
DS18B20_Delay(1); // 延时 1us
dat >>= 1;
if(DQ)
dat |= 0x80;
DS18B20_Delay(5); // 延时 5us
DQ = 1; // 读时序结束
}
return dat;
}
void DS18B20_Start()
{
DQ = 1;
DS18B20_Delay(1);
DQ = 0;
DS18B20_Delay(480);
DQ = 1;
DS18B20_Delay(60);
}
void DS18B20_End()
{
DQ = 1;
DS18B20_Delay(1);
}
void DS18B20_Delay(uint i)
{
while(i--);
}
// 初始化函数
void init()
{
TMOD |= 0x20; // 定时器 1 工作在模式 2
TH1 = 0xfd; // 设置波特率,4800 bps
TL1 = 0xfd;
TR1 = 1; // 启动定时器
}
// 串口初始化函数
void uart_init()
{
SCON = 0x50; // 8 位数据,可变波特率,允许接收
ES = 1; // 允许串口中断
EA = 1; // 允许总中断
}
// 串口发送函数
void send_string(char *s)
{
while(*s)
{
SBUF = *s;
while(!TI);
TI = 0;
s++;
}
}
【2】读取温度数码管显示
数码管是一种数码显示装置,通常由一个数码管的阵列组成,可以用来显示数字、字母和一些特殊符号。广泛应用于各种电子装置中,如计算器、时钟、温度计、电压表、档位指示器等。数码管通常可分为共阳极和共阴极两种类型,其中共阳极的数码管是将阳极连接在一起,通过控制对应的阴极接口以实现显示数字,而共阴极则是将阴极连接在一起,通过控制对应的阳极接口以实现显示。
数码管的显示原理是通过不同的电信号按照一定的逻辑在数码管内部的小灯泡上点亮不同的线段,从而形成所需的数字、字母或符号。要实现数码管的显示控制,需要使用微控制器或其他数字电路实现对数码管各个位的控制,在采集到数据后将其转换为可显示的信息,并将其显示在相应的数码管上。
下面是通过DS18B20 温度传感器读取温度再通过数码管显示温度:
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ = P1^0; // DS18B20 数字温度传感器数据线连接到 P1.0 引脚
sbit DIO = P2^0; // 数码管数据总线 DIO 连接到 P2.0 引脚
sbit RCLK = P2^1; // 数码管存储总线 RCLK 连接到 P2.1 引脚
sbit SRCLK = P2^2; // 数码管移位总线 SRCLK 连接到 P2.2 引脚
// DS18B20 数据传输函数
void DS18B20_WriteByte(uchar dat);
uchar DS18B20_ReadByte();
void DS18B20_Start();
void DS18B20_End();
void DS18B20_Delay(uint i);
// 初始化函数
void init();
// 串口初始化函数
void uart_init();
// 串口发送函数
void send_string(char *s);
// 数码管显示函数
void display(uchar num);
void main()
{
uchar temp_h, temp_l;
uint temp;
init();
uart_init(); // 串口初始化
while(1)
{
DS18B20_Start(); // 启动传输
DS18B20_WriteByte(0xCC); // 忽略 ROM 指令
DS18B20_WriteByte(0x44); // 发送温度转换指令
DS18B20_End(); // 结束传输
DS18B20_Start(); // 启动传输
DS18B20_WriteByte(0xCC); // 忽略 ROM 指令
DS18B20_WriteByte(0xBE); // 发送读取指令
// 读取温度值
temp_l = DS18B20_ReadByte(); // 读取低位温度值
temp_h = DS18B20_ReadByte(); // 读取高位温度值
// 计算温度值
temp = (temp_h << 8) + temp_l;
temp = (float)temp / 16;
// 数码管显示温度
display(temp);
send_string("The temperature is: ");
send_string(temp);
send_string("\r\n");
DS18B20_End(); // 结束传输
}
}
// DS18B20 数据传输函数
void DS18B20_WriteByte(uchar dat)
{
uchar i;
for (i = 0; i < 8; i++)
{
DQ = 0; // 写时序开始
DQ = dat & 0x01; // 写数据
DS18B20_Delay(1); // 延时 1us
DQ = 1; // 写时序结束
dat >>= 1;
}
}
uchar DS18B20_ReadByte()
{
uchar i, dat = 0;
for (i = 0; i < 8; i++)
{
DQ = 0; // 读时序开始
DS18B20_Delay(1); // 延时 1us
dat >>= 1;
if(DQ)
dat |= 0x80;
DS18B20_Delay(5); // 延时 5us
DQ = 1; // 读时序结束
}
return dat;
}
void DS18B20_Start()
{
DQ = 1;
DS18B20_Delay(1);
DQ = 0;
DS18B20_Delay(480);
DQ = 1;
DS18B20_Delay(60);
}
void DS18B20_End()
{
DQ = 1;
DS18B20_Delay(1);
}
void DS18B20_Delay(uint i)
{
while(i--);
}
// 初始化函数
void init()
{
TMOD |= 0x20; // 定时器 1 工作在模式 2
TH1 = 0xfd; // 设置波特率,4800 bps
TL1 = 0xfd;
TR1 = 1; // 启动定时器
}
// 串口初始化函数
void uart_init()
{
SCON = 0x50; // 8 位数据,可变波特率,允许接收
ES = 1; // 允许串口中断
EA = 1; // 允许总中断
}
// 串口发送函数
void send_string(char *s)
{
while(*s)
{
SBUF = *s;
while(!TI);
TI = 0;
s++;
}
}
// 数码管显示函数
void display(uchar num)
{
uchar code table[] = {
0x3f, // '0'
0x06, // '1'
0x5b, // '2'
0x4f, // '3'
0x66, // '4'
0x6d, // '5'
0x7d, // '6'
0x07, // '7'
0x7f, // '8'
0x6f, // '9'
};
uchar i;
for (i = 0; i < 8; i++)
{
RCLK = 0;
DS = table[num % 10]; // 取出个位数码
num /= 10; // 取下一位数
SRCLK = 1;
SRCLK = 0;
}
RCLK = 1;
RCLK = 0;
}