基于51单片机多路温度检测—8路、4路

基于51单片机多路温度检测

(仿真+程序+原理图)

功能介绍

具体功能:

1.通过对多路DS18B20温度传感器的数据采集;

2.温度采集并将数值显示在LCD显示屏上;

3.可通过按键设置温度报警值;

4.逐个显示传感器的温度,当LCD显示温度超过设定值时,系统声光报警;

#include <reg52.h>
#include <intrins.h>
#define MAXNUM 8 //定义最多有8个 DS18B20

sbit DQ=P2^3;    //定义DS18B20数据线

sbit RS=P2^0;	 //液晶端口控制线端口定义
sbit RW=P2^1;	 //液晶端口控制线端口定义
sbit E= P2^2;	 //液晶端口控制线端口定义

sbit keyenter =P3^2;
sbit keyup    =P3^3;
sbit keydown  =P3^4;

sbit led=    P1^6;
sbit buzzer= P1^7;



unsigned char code lcd0[]={"SEARCH ROMING..."};
unsigned char code lcd1[]={"SEARCH ROM OK!"};
unsigned char code lcd2[]={"The total is:"};
unsigned char code lcd3[]={"No.( ):"}; 
unsigned char code lcd4[]={'0','1','2','3','4','5','6','7','8','9','.',0xdf,0x43,' '};
unsigned char code setinfo[]={"Set Alarm Point:"};
unsigned char code pointinfo[]={"Alarm:"};
signed char tempalarm=0;


//0xdf在1602中是“℃”符号的左上角那个圆,0X43是大写的"C" 他们一起构成了”℃“这个符号

unsigned char dat[6];//用来显示温度的参数					  
unsigned char temp_l,temp_h,negetiveflag=0,temp_over,t; 
unsigned char num=0;
unsigned int i;
bit keyflag=0;
idata unsigned char al[MAXNUM];
idata unsigned char ID[MAXNUM][8];

signed char alarm=30; //默认为30摄氏度报警

/***********************液晶模块**********************************/
void delaylcd(void)//延时程序
{
	unsigned char y;
	for(y=0;y<250;y++);
}

void LCD_write_com(unsigned char com)//液晶写命令函数
{
	delaylcd();
    RS=0; //RS为1 写命令
    RW=0;
	E=0;
	E=1;
    P0=com;
   	E=0;
	delaylcd();
}

void LCD_write_data(unsigned char dat)//液晶写数据函数
{
	delaylcd();
	RS=1;   //RS为1 写数据
	RW=0;
	E=0;
	E=1;
	P0=dat;
	E=0;
	delaylcd();
}
void lcdinit(void)//初始化
{
	LCD_write_com(0x01); //液晶清屏 
	LCD_write_com(0x38); //1602”功能设置命令字“ 显示2行 每行字体用5*8 ASCII显示	8位数据接口
	LCD_write_com(0x0c); //显示控制,开始显示,不显示游标,游标不闪烁	
	LCD_write_com(0x06); //输入方式为增量输入,不移屏幕
}

/************************ds18b20****************************/
void delay_nus(unsigned int n)//延时 程序 一次8+6(进出)=14us
{
	while(n--);
}

void reset(void)  //ds18b20初始化复位操作
{
	 unsigned char x=0;
	 DQ = 1;          	//DQ复位
	 delay_nus(8);  	//稍做延时
	 DQ = 0;          	//单片机将DQ拉低
	 delay_nus(80); 	//精确延时 大于 480us
	 DQ = 1;          	//拉高总线
	 delay_nus(10);
	 x=DQ;            	//稍做延时后 如果x=0则初始化成功 x=1则初始化失败
	 delay_nus(5);
}

void write_bit(unsigned char dat)	//DS18B20 写一位 操作
{
  	DQ = 0;
	_nop_();
    _nop_();
 	DQ = dat&0x01;
    delay_nus(5);
 	DQ = 1;
}

void write_byte(unsigned char dat)//写一个字节
{
 	unsigned char i,j;
 	for (i=8; i>0; i--)
 	{
		j=dat&0x01;
  		write_bit(j);
		dat>>=1;
    }
}

unsigned char read_2bit(void)//读二位 子程序
{
	unsigned char i;
	unsigned char dat = 0;
	for (i=2;i>0;i--)
	{
		DQ = 0; // 给脉冲信号
		dat<<=1;
		DQ = 1; // 给脉冲信号
		if(DQ)
		dat|=0x01;
		delay_nus(4);
	}
 	return(dat);
}

unsigned char read_byte(void)//读一个字节 子程序
{
	unsigned char i=0;
	unsigned char dat = 0;
	for (i=8;i>0;i--)
	{
		DQ = 0; // 给脉冲信号
		dat>>=1;
		DQ = 1; // 给脉冲信号
		if(DQ)
		dat|=0x80;
		delay_nus(4);
	}
 	return(dat);  
}



void delay_nms(unsigned int n)
{
	unsigned int j=0;
	unsigned char i=0;
	for(j=0;j<n;j++)
	{
		for(i=0;i<120;i++)
		{
			_nop_();
		}
	}
}

void read_temp(unsigned char num_data)//读取温度 子程序 参数表示读第几个传感器
{
	unsigned char f;	
	reset();
	write_byte(0xcc);//发送跳过ROM号命令
	write_byte(0x44);//发送温度转换命令
	delay_nms(2000);		
	reset();
	write_byte(0x55);//发送匹配ROM号命令
	for(f=0;f<8;f++) //8字节ROM号
	{
		write_byte(ID[num_data][f]);//发匹配ROM
	}
	delay_nus(100);
	write_byte(0xbe);//读寄存器命令
	delay_nus(100);
	temp_l=read_byte();
	temp_h=read_byte();
}

 
void temp_convert(void)//温度转换
{
	negetiveflag=0;
	negetiveflag=temp_h&0x80;
	if(negetiveflag)
	{
		negetiveflag=1;
		temp_h=~temp_h;
  		if(temp_l==0)
		{
		 	temp_h++;  //若低8位全为0且温度为负,取补时就要向高位进1
		}
  		temp_l=~temp_l+1; 
	}
	temp_h<<=4;
	temp_l>>=4;
	temp_over=temp_h|temp_l;
	tempalarm=temp_over;
	if(negetiveflag==1)
	{
		 tempalarm=tempalarm*(-1);
	}
}

/*******************显示***************************/
void search_cartoon(void)//搜索ROM动画
{
	lcdinit();
	LCD_write_com(0x80);//液晶第一行地址
    for(i=0;i<16;i++)
	{
		LCD_write_data(lcd0[i]);
	}
	LCD_write_com(0xc0);//液晶第二行地址
    for(i=0;i<16;i++)
	{
		LCD_write_data(0xff);//显示类似进度条的黑点
		delay_nms(num*80);
	}		 
}

void display_alarm_normal(signed char alarm_data)//显示报警温度
{
	unsigned int data_b,data_temp,l,datx[6]={0};
	data_b=alarm_data;
	negetiveflag=0;

    LCD_write_com(0x80); 
	for(l=0;l<6;l++)
	{
		LCD_write_data(pointinfo[l]);
	}   

	if(alarm_data>=0)
	{
		data_b=alarm_data/100;//百位//
	}
	else
	{
		negetiveflag=1;
		alarm_data=alarm_data*(-1);//变成正温度
	}

	data_temp=alarm_data%100;//对100取余,也就是十位数和个位数

	datx[0]=data_temp/10;//十位
	datx[1]=data_temp%10;//个位
	datx[2]=13;//空格符号
	datx[3]=13;//空格符号
	datx[4]=11;//摄氏度符号
	datx[5]=12;//摄氏度符号

	LCD_write_com(0x88);

	if(negetiveflag==1)
	{
		LCD_write_data(0x2d);//显示"-"  “负号”
	}
	else
	{
		LCD_write_data(lcd4[data_b]);//如果大于0就显示百位数,否则百位数就显示“负号”
	}

	for(l=0;l<6;l++)//显示报警值和摄氏度符号
	{
	  LCD_write_data(lcd4[datx[l]]);
	}	
}

void display_total(void)	  //显示搜索到的DS18B20传感器数目
{
	lcdinit();
	LCD_write_com(0x80);//第一行地址
    for(i=0;i<14;i++)
	{
		LCD_write_data(lcd1[i]);
	}
	LCD_write_com(0xc0);//第二行地址
    for(i=0;i<13;i++)
	{
		LCD_write_data(lcd2[i]);
	}
	LCD_write_data(lcd4[num]);
	delay_nms(2000);
	lcdinit();					//清屏,准备显示温度
	display_alarm_normal(alarm);//显示报警温度
}



void display_ds18b20(i)//显示编号为i的DS18B20的温度//
{
	unsigned int data_b,data_temp,l;
	data_b=temp_over/100;//百位//
	data_temp=temp_over%100; 
	dat[0]=data_temp/10;//十位//
	dat[1]=data_temp%10;//个位//
	dat[2]=13; //空格
	dat[3]=13; //空格
	dat[4]=11; //摄氏度符号
	dat[5]=12; //摄氏度符号

	LCD_write_com(0xc0);
	for(l=0;l<7;l++)
	{
		LCD_write_data(lcd3[l]);
	}
	LCD_write_com(0xc4);
	LCD_write_data(lcd4[++i]);
	LCD_write_com(0xc8);

	if(negetiveflag==1)
	{
		LCD_write_data(0x2d);
	}
	else
	{
		LCD_write_data(lcd4[data_b]);
	}

	for(l=0;l<6;l++)
		LCD_write_data(lcd4[dat[l]]);
	delay_nms(1000);
}




void display_alarm(signed char alarm_data)//显示报警温度
{
	unsigned int data_b,data_temp,l;
	data_b=alarm_data;
	negetiveflag=0;
	if(alarm_data>=0)
	{
	 data_b=alarm_data/100;//百位//
	}
	else
	{
	 negetiveflag=1;
	 alarm_data=alarm_data*(-1);//变成正温度
	}

	data_temp=alarm_data%100;//对100取余,也就是十位数和个位数

	dat[0]=data_temp/10;//十位
	dat[1]=data_temp%10;//个位
	dat[2]=13;//空格符号
	dat[3]=11;//摄氏度符号
	dat[4]=12;//摄氏度符号

	if(keyflag==1)//刚刚进入设置报警温度
	{
	    lcdinit();
		LCD_write_com(0x80);//第一行地址
	    for(l=0;l<16;l++)
		{
			LCD_write_data(setinfo[l]);
		}
	
		LCD_write_com(0xc0);//第二行地址
		for(l=0;l<8;l++)
		{
			LCD_write_data(pointinfo[l]);
		}
	}
	

	LCD_write_com(0xc7);

	if(negetiveflag==1)
	{
		LCD_write_data(0x2d);//显示"-"  “负号”
	}
	else
	{
		LCD_write_data(lcd4[data_b]);//如果大于0就显示百位数,否则百位数就显示“负号”
	}

	for(l=0;l<5;l++)//显示报警值和摄氏度符号
	{
	  LCD_write_data(lcd4[dat[l]]);
	}	
}


/***********************自动搜索ROM*****************************/
void search_rom(void)//搜索ROM
{ 
	unsigned char k=0,l=0,chongtuwei=0,m=0,n=0;
	unsigned char s=0;
	unsigned char zhan[MAXNUM];
	unsigned char ss[64];
	do
	{
		reset();
		write_byte(0xf0);  //搜索ROM命令	
		for(m=0;m<8;m++)
		{
			for(n=0;n<8;n++)
			{
				k=read_2bit();//读两位数据
				k=k&0x03;   
				s>>=1;
				if(k==0x01)//01读到的数据为0 写0 此位为0的器件响应
				{   		
					write_bit (0);
	    			ss[(m*8+n)]=0;
				}
				else if(k==0x02)//读到的数据为1 写1 此位为1的器件响应
				{
					s=s|0x80;
					write_bit (1);
					ss[(m*8+n)]=1;
				}
				else if(k==0x00)//读到的数据为0  有冲突位 判断冲突位 
				{				//如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
					chongtuwei=m*8+n+1;					
					if(chongtuwei>zhan[l])
					{						
						write_bit (0);
						ss[(m*8+n)]=0;												
						zhan[++l]=chongtuwei;						
					}
					else if(chongtuwei<zhan[l])
					{
						s=s|((ss[(m*8+n)]&0x01)<<7);
						write_bit (ss[(m*8+n)]);
					}
					else if(chongtuwei==zhan[l])
					{
						s=s|0x80;
						write_bit (1);
						ss[(m*8+n)]=1;
						l=l-1;
					}
				}
				else
				{
					goto loop;
				}
			}
			ID[num][m]=s;		
		}
		num++;
	}
	while(zhan[l]!=0&&(num<MAXNUM));		
loop:
	search_cartoon();
	display_total();

}



void main (void)
{
	unsigned char i=0,t=0;
	delay_nms(50);
	IT0=0;
	EX0=1;
	EA=1;

    search_rom();//搜索ROM并且存储,把18B20的每一个ROM读取出来,方便下次调用


	reset();
		
	while(1) 
	{ 
		if(keyflag==0)
		{
			  for(i=0;i<num;i++)	//每一个 ds18b20 循环显示
			  {
					if(keyflag==1) break;
					read_temp(i);   //读编号 i 的ds18b20 的温度
					if(keyflag==1) break;
					temp_convert(); //调用温度转换
					if(keyflag==1) break;
				    if(tempalarm>alarm)//报警判断
					{
					  for(t=0;t<3;t++)
					  {
					  	 buzzer=0;//打开报警蜂鸣器
						 led=0;   //打开报警指示灯
						 delay_nms(100);
						 buzzer=1;//关闭报警蜂鸣器
						 led=1;   //关闭报警指示灯
						 delay_nms(100);
					  }
					}
		        	display_ds18b20(i);//显示 编号 i 的温度		
		      }
		}		  

		else//设置按键按下 进行按键扫描动作
		{ 
		   display_alarm(alarm);
		   keyflag=0;
		   while(1)
		   {
		   	 if(keyenter==0&&keyflag==0)//进入设置以后,再按设置按键,就退出设置,重新显示每一个通道温度
				{
				  delay_nms(200);
				  if(keyenter==0)
				  {
					while(keyenter==0);	 
					lcdinit();
					display_alarm_normal(alarm);//显示报警温度
					break;//退出按键扫描
				  }
				}
			if(keyup==0)//
				{
				  delay_nms(200);
				  if(keyup==0&&alarm<125)
				  {
					 alarm++;//报警温度加1
				  }
				  display_alarm(alarm);
				}
		   if(keydown==0&&alarm>-55)//
				{
				  delay_nms(200);
				  if(keydown==0)
				  {
					alarm--;//报警温度减1
				  }
				  display_alarm(alarm);
				}
				delay_nms(50);
		   }
		   EX0=1;	
		}
			      
	}//while(1)结束  
}

void key_init0(void) interrupt 0
{
	if(keyenter==0)
	{
	  delay_nms(10);
	  if(keyenter==0)
	  {
	  	EX0=0;
		keyflag=1;
	  }
	}
	
}

硬件设计

使用元器件:

单片机:AT89C51;

(注意:单片机是通用的,无论51还是52、无论stc还是at都一样,引脚功能都一样。程序也是一样的。)

设计资料

01 仿真图

本设计使用proteus7.8和proteus8.9两个版本设计,向下兼容,无需担心!具体如图!

设置温度报警值

循环检测

02 原理图

本系统原理图采用Altium Designer19设计,具体如图!

03 程序

本设计使用软件keil4和keil5两个版本编程设计,无需担心!具体如图!

04 4路报警

4路温度采集是在8路的基础的上改的,直接烧录原来的程序就可以。

05 设计资料

全部资料包括仿真源文件 、程序(含注释)、AD原理图、仿真视频等。具体内容如下,全网最全! !

 

下面是开源51单片机设计资料

​大家共同学习进步:

链接:https://pan.baidu.com/s/1zjb1YdpN_bZubXyQljvHmQ?pwd=jlcl

提取码:jlcl

点赞分享,一起学习进步!一起成长。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值