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

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

(仿真+程序+原理图)

功能介绍

具体功能:

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

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

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

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

​演示视频:

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

#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原理图、仿真视频等。具体内容如下,全网最全! !

资料获取请观看前面演示视频!

点赞分享一起学习成长。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/512892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如果查看iPhone的GPU

摘要 了解你的显卡对于在电脑上玩现代图形要求高的游戏非常重要。本文介绍了如何轻松查看你的显卡型号以及为什么显卡在玩电脑游戏时如此关键。 引言 随着电脑游戏的发展&#xff0c;现代游戏对硬件性能的要求越来越高。十年前发布的显卡已经无法满足当前游戏的需求。因此&…

《书生·浦语大模型全链路开源开放体系》学习笔记

书生浦语大模型全链路开源开放体系-学习笔记 大模型成为发展通用人工智能的重要途径专用模型通用大模型 书生大模型开源历程InternLM2回归语言建模的本质主要亮点性能全方位提升强大的内生计算能力 从模型到应用典型流程全链条开源开放体系数据数据集获取预训练微调XTuner 评测…

函数参数缺省和内联函数【C++】

文章目录 函数参数缺省函数参数缺省的条件和要求 内联函数内联函数的工作原理内联函数的定义方法内联函数的要求解决方法&#xff1a;直接在.h中定义内联函数的函数体 内联函数再Debug模式下默认是不展开的 函数参数缺省 顾名思义&#xff1a;可以少传一个/多个参数给函数&…

基于springboot+vue+Mysql的企业客户信息反馈平台

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

Runes 协议创始人 Casey 发布了 24 个创世符文的名称的 idea

作者&#xff1a;Runes 中文社区 X/推&#xff1a;RunesCC 来看看 ChatGPT 对这些名字的解释&#xff0c;可以看出 Casey 的创世符文所追求的&#xff0c;是对不同文化、社会现象、人类情感的探索和思考&#xff0c;让不同的群体都能在这些 meme 中找到共鸣。 TRIPPLE•NIPPLE…

MySQL数据库(数据库连接池)

文章目录 1.批处理应用1.基本介绍2.批处理演示1.创建测试表2.修改url3.编写java代码 3.批处理源码分析 2.数据库连接池1.传统连接弊端分析2.数据库连接池基本介绍1.概念介绍2.数据库连接池示意图3.数据库连接池种类 3.C3P0连接池1.环境配置1.导入jar包2.将整个lib添加到项目中3…

真·面试题总结——JVM虚拟机

JVM虚拟机 JVM虚拟机规范与实现 JVM虚拟机规范 JVM虚拟机实现 JVM的常见实现 JVM虚拟机物理架构 JVM虚拟机的运转流程 JVM类加载过程 JVM类加载器及类加载器类型 JVM类加载器双亲委派机制 JVM运行时数据区的内存模型 JVM运行时数据区的内存模型&#xff1a;程序计数器…

蓝桥杯 - 玩具蛇

解题思路&#xff1a; dfs public class Main {static final int N 4;static int[][] visited new int[N][N];static int count;public static void main(String[] args) {for (int i 0; i < N; i) { //16种位置开始的可能for (int j 0; j < N; j) {dfs(i, j, 1);}…

稀碎从零算法笔记Day37-LeetCode:所有可能的真二叉树

今天的每日一题&#xff0c;感觉理解的还不够深&#xff0c;有待加深理解 题型&#xff1a;树、分治、递归 链接&#xff1a;894. 所有可能的真二叉树 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一个整数 n &#xff0c;请你找出所有…

深入理解MySQL:拼接字符串、查询、删除表和创建索引的关键命令

MySQL是一种功能强大的关系型数据库管理系统&#xff0c;广泛应用于各种类型的应用程序中。本文将介绍MySQL中一些常用的关键命令&#xff0c;包括拼接字符串、查询、删除表和创建索引&#xff0c;帮助读者更好地理解和利用MySQL数据库。 mysql拼接字符串 在MySQL中&#xf…

C++ AVL树(旋转)

我们之前学习了搜索二叉树&#xff0c;我们知道普通的搜索二叉树会有特殊情况出现使得二叉树的两枝极其不平衡形成我们通俗说的歪脖子树&#xff1a; 这样的树一定会使得我们的增删查的效率变低&#xff1b;为了避免这种极端的情况出现&#xff0c;在1962年有两位伟大的俄罗斯数…

kubadm部署 kubernetes-1.29版本

一、集群节点准备 ip主机名称操作系统192.168.1.160master-1Centos-7.9192.168.1.161node-1Centos-7.9 二、安装前主机环境准备 &#xff08;所有主机都需要进行&#xff09; 1、配置主机名解析 echo "192.168.1.160 master-1" >> /etc/hosts echo "1…

C++符号清洗、Swift符号清洗, 编译还原

C 符号清洗&#xff08;编译还原&#xff09; C 由于函数重载的原因&#xff0c;针对每个函数符号&#xff0c;假如了name mangling的机制。导致堆栈适合机制阅读&#xff0c;因为每个函数符号都是独一无二的&#xff0c;但是这并非程序员易读的文字。 比如我们有这个符号cra…

又一AI工具开源!企业应该如何搭上这趟AI快车

大模型技术在近两年来飞速发展&#xff0c;企业对大模型的认知更加理性、务实。大模型本身不会直接产生价值&#xff0c;但在大模型基础架构之上开发出的AI应用&#xff0c;带来技术创新及业务增长&#xff0c;成为企业真正关心的问题。 基于大模型开发的又一个AI工具诞生&…

XenCenter 2024 导入虚拟机

导入虚拟机 虚拟机位置 导入到那一个服务器 导入虚拟机存放存储位置 虚拟机网卡配置 SR修复功能&#xff0c;看自己需求 虚拟机恢复确认最终配置 恢复好的虚拟机 虚拟机模板转换

源浩流体设备与您相约2024年第13届生物发酵展

参展企业介绍 温州源浩流体设备科技有限公司是一家集设计、开发、制造、销售、服务于一体的高科技企业&#xff0c;公司主要生产各种不锈钢阀门、管件、卫生级流体设备(卫生级换向阀,卫生级减压阀,卫生级罐底阀)等。现为温州市泵阀协会会员&#xff0c;ISO9000 2008版质量质量…

视频号视频下载小程序,让你随心保存你喜爱的视频!

今天给大家推荐一个非常实用的小程序&#xff0c;它就是专为下载视频号视频而设计的&#xff01; 微信视频号的兴起&#xff0c;让越来越多的优质、有趣的视频在平台上涌现&#xff0c;我们经常会遇到一些想要保存、回看的视频&#xff0c;但却无法轻易下载到手机或电脑中。这…

Linux基础篇:操作系统进程的基本概念与进程管理基础操作

Linux基础篇&#xff1a;操作系统进程的基本概念与进程管理基础操作 进程的定义&#xff1a; 进程是计算机系统中正在运行的程序的实例。 每个进程都有自己的内存空间、执行状态、资源和上下文。 进程是操作系统进行资源分配和调度的基本单位。 进程描述&#xff1a; 每个进…

LeetCode 63. 不同路径 II

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到右下角…

华为CCE部署RabbitMQ中间件操作文档

1、创建有状态&#xff08;StatefulSet&#xff09;部署 中间件一般为有状态部署&#xff0c;有状态部署与无状态部署区别参考文档&#xff1a;K8S有无状态部署-CSDN博客 1.1、基本信息 注意&#xff1a; 应用名称命名规则&#xff1a;&#xff08;命名规则最好统一&#xff…