DS18B20设计1款简单的温度监测系统
项目要求:
1.采集环境温度(0~99.9℃)显示在前3位数码管上。
2. 温度值T判断:
当T<25℃时, D1,D2闪烁,蜂鸣器短鸣;
当25℃<T<27℃时,D1闪烁,蜂鸣器长鸣;
当27℃<T<30℃时,只显示温度值;
当30℃<T<32℃时,D3闪烁,蜂鸣器长鸣;
当T>32℃时,D3,D4 闪烁,蜂鸣器短鸣;
3. 用串口将采集的温度数据实时发送至上位机显示。
原理图:
代码:
#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
bit flag;
sbit dula=P2^6;
sbit wela=P2^7;
sbit led1=P1^0;
sbit led2=P1^1;
sbit led3=P1^2;
sbit led4=P1^3;
sbit ds=P2^2;
sbit buzzer=P2^3;
uint alarm1=250;
uint alarm2=270;
uint alarm3=300;
uint alarm4=320;
uchar code table_du[]=
{
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
uint temp;
float f_temp;
void delay_us(uint t)
{
while(t--);
}
void delay_ms(uchar t1)
{
uint i,j;
for(i=t1;i>0;i--)
for(j=110;j>0;j--);
}
void ds_init() //DS18B20初始化
{
ds=1;
delay_us(5);
ds=0;
delay_us(80); //约700us
ds=1;
delay_us(20); //约214us
if(ds==0)
flag=1;
else
flag=0;
delay_us(30); //约311us
}
bit ds_read_bit() //读1位数据
{
bit dat;
ds=0;
_nop_(); //约1us
_nop_();
ds=1;
_nop_();
dat=ds;
delay_us(5); //约67us
return dat;
}
uchar ds_read_byte() //读1字节数据
{
uchar i,j,k;
for(i=0;i<8;i++)
{
j=ds_read_bit();
k=(j<<7)|(k>>1); //将j的最低位移到最高位,k右移1位,然后或操作
} //即将j的值移入k的最高位。下一次就将这1位移入次高位
return k; //经过7次移位操作,将j的值完全移入k,然后返回
}
void ds_write_byte(uchar dat) //单片机向DS18B20中写字节数据
{
uchar i; //用于循环计数
for(i=0;i<8;i++)
{
ds=0; //置0进行读写数据
_nop_(); //延时使数据保持稳定
_nop_();
ds=dat&0x01; //dat与0x01与完后只剩最低位,其他高位全为0
delay_us(6); //延时让DS18B20用足够的时间采样
ds=1; //置1用于数据操作,即加工数据,右移1位
dat=dat>>1; //使次低位变为最低位
}
delay_us(6);
}
void tempconversion(void) //DS18B20开始获取温度并转换
{
ds_init(); //初始化
ds_write_byte(0xcc);//跳过ROM
ds_write_byte(0x44);//开始温度转换命令
}
uint read_temperature() //单片机读取温度,这里必须用uint型
{
uchar a,b; //用于存放高8位和低8位数据
ds_init(); //初始化
ds_write_byte(0xcc); //跳过ROM操作指令,即单片机不用提供64位ROM
ds_write_byte(0xbe);
a=ds_read_byte(); //温度值的低8位,例0000 0000 0101 1010
b=ds_read_byte(); //温度值的高8位,例0000 0000 1010 0101
temp=b;
temp=temp<<8; //temp的低8位左移8位变为temp的高8位 1010 0101 0000 0000
temp=temp|a; //1010 0101 0000 0000|0000 0000 0101 1010
f_temp=temp*0.0625; //温度在寄存器中为12位,分辨率为0.0625℃
temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5用于四舍五入
f_temp=f_temp+0.05;
return temp;
}
void display(uint temp) //数码管显示温度程序
{ //uint可表示0~65535个数
uchar bai, shi, ge; //uchar只能表示0~255个数
bai=temp/100;
shi=temp%100/10;
ge=temp%100%10;
P0=table_du[bai];
dula=1;
dula=0;
P0=0xfe;
wela=1;
wela=0;
delay_ms(5);
P0=table_du[shi]|0x80;
dula=1;
dula=0;
P0=0xfd;
wela=1;
wela=0;
delay_ms(5);
P0=table_du[ge];
dula=1;
dula=0;
P0=0xfb;
wela=1;
wela=0;
delay_ms(5);
}
void alarm(uint s, uchar led) //蜂鸣器报警,LED闪烁
{
uchar i;
i=s;
buzzer=0; //蜂鸣器响
P1=~(led); //控制相应的灯亮
while(i--);
{
display(read_temperature());//用温度显示函数起到延时作用
}
buzzer=1; //蜂鸣器不响
P1=0xff; //控制相应的灯灭
while(i--)
{
display(read_temperature());
}
}
void deal(uint t2) //温度处理函数
{
uchar i;
if(t2<=alarm1) //t2<=25℃
{
alarm(5,0x03); //点亮led1,蜂鸣器发出'滴'响
}
else if((t2>alarm1)&&(t2<=alarm2))
{
alarm(40,0x01);
}
else if((t2>=alarm3)&&(t2<alarm4))
{
alarm(40,0x04);
}
else if(t2>=alarm4)
{
alarm(5,0x0c);
}
else //27℃<t2<30℃,只调用显示函数延时
{
i=40;
while(i--)
{
display(read_temperature());
}
}
}
void init_com(void) //串口初始化
{
TMOD=0x20; //T1定时器工作方式3
PCON=0x00;
SCON=0x50; //确定串行口控制
TH1=0xfd; //装初值,设置波特率为9600
TL1=0xfd;
TR1=1;
}
void comm(char *parr) //串口数据发送函数
{
do
{
SBUF=*parr++; //发送数据
while(!TI); //等待发送完成标志为1
TI=0; //标志清0
}
while(*parr); //保持循环直到字符为'\0'
}
void main() //主函数
{
uchar buff[4],i;
dula=0;
wela=0;
init_com();
while(1)
{
tempconversion(); //温度转换
for(i=10;i>0;i--)
{
display(read_temperature()); //获取温度并显示
}
deal(temp); //进行温度处理
sprintf(buff,"%f",f_temp); //将浮点型温度格式化为字符型
for(i=10;i>0;i--)
{
display(read_temperature()); //温度显示
}
comm(buff); //串口发送数据
for(i=10;i>0;i--)
{
display(read_temperature());//温度显示
}
}
}
参考资料
us级延时函数延时时间对照表
串口初始化设置