飞道的博客

单片机Ds18b20温度传感器的学习(附踩雷清单)

301人阅读  评论(0)

主函数
温度传感器可记录温度-55~125摄氏度

#include"reg52.h"
#include"temp.h"//这个头文件要写上,否则会报错!!!
typedef unsigned int u16;
typedef unsigned char u8;
sbit LSA=P2^2;//数码管用74LS138译码器来控制,所以有了这些东西
sbit LSB=P2^3;
sbit LSC=P2^4;
char num=0;//有用。在后面解释
u8 DisplayData[8];//工具数组,接受num转换过来的16进制数,传递给smg段数组
//上面这个数组这个要写成比5大的数因为要显示6位数码管,然后拼写注意一下!
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管段选,从0~9
void delay(u16 i)
{
	//粗延时函数
	while(i--);
}
void datapros(int temp)//参数表别忘了!!!因为你主函数调用这个函数是要传进实参的!!
{
	float tp;//定义温度浮点数。因为数据处理有小数点所以将温度赋给一个浮点型变量
	if(temp<0)
	{//如果从温度传感器里读取的温度是负数
		DisplayData[0]=0x40;//就让数码管显示1个负号在前头
		//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
		temp=temp-1;
		temp=~temp;
		tp=temp;
		temp=tp*0.0625*100+0.5;
		//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
		//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
		//算加上0.5,还是在小数点后面。	
		//读取的温度经一顿转换后变为真正的10进制温度
	}
	else//如果从温度传感器里读取的温度是0或者正数
	{
		DisplayData[0]=0x00;//那就不用在数码管最前头显示一个负号了
		tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量
		//如果温度是正的那么,那么正数的原码就是补码它本身
		temp=tp*0.0625*100+0.5;
		//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点
		//后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就
		//算加上0.5,还是在小数点后面。
	}
	DisplayData[1]=smgduan[temp/10000];//因为数码管我们只用右边的6位,而且我们让temp多×了100,所以这里/10000
	//所以这里剥离temp的百位给DisplayData数组存着  数组下标为0的数字你已经占用了,这里必须为1开始
	DisplayData[2]=smgduan[temp%10000/1000];//剥离temp的十位给DisplayData数组存着
	DisplayData[3]=smgduan[temp%1000/100]|0x80;	//注意这些数字要写对!
	//剥离temp的个位给DisplayData数组存着,因为还要显示小数点,所以
	//我们必须让数码管的dp位亮着,就0x80(因为dp位为数码管段选位的最高位)即可。
	DisplayData[4] = smgduan[temp % 100 / 10];//剥离temp的小数点后一位给DisplayData数组存着
	DisplayData[5] = smgduan[temp % 10];//剥离temp的小数点后二位给DisplayData数组存着

}
void DigDisplay()
{
	u8 i;
	for(i=0;i<6;i++)//这个要改成6,因为你要显示6位数码管!!!!!!!
	{
		switch(i)//位选,选择点亮的数码管
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位
			case(3):
				LSA=1;LSB=1;LSC=0; break;//显示第3位
			case(4):
				LSA=0;LSB=0;LSC=1; break;//显示第4位
			case(5):
				LSA=1;LSB=0;LSC=1; break;//显示第5位		
		}
		P0=DisplayData[5-i];//发送disp数组里存着的num剥离出的位给P0管,注意,这里是5-i,因为
		//数码管第0位是在最右侧,第7位在最左侧,所以遵循”千百十个小数点后1小数点后2“这样的从左至右顺序来让
		//数码管显示数字
		delay(100);//间隔1us扫描一次
		P0=0x00;//数码管消隐
		//从P0=DisplayData....到P0=0x00;这里,写在for循环里switch外!!!!记下
	}
	
}
int main()
{
	while(1)
	{
		datapros(DS18b20ReadTemp());//数据处理函数,实参是读取温度传感器里的温度
		//调用datapros()函数的实参这个位置的函数读取温度值读取完毕,返回温度给datapro()
		DigDisplay();//数码管显示函数
	}

}

temp.c文件

#include"temp.h"  
//#include "reg52.h"
void Delay1ms(uint y)
{
	uint x;
	for(;y>0;y--)
	{
		for(x=110;x>0;x--);
	}
}
//较为精确的延时1ms的函数
//下面为温度传感器初始化函数
uchar Ds18b20Init()
{//代码模拟温度传感器的初始化时序
	uchar i;
	DSPORT=0;//将总线(数据线)拉低480us~960us
	i=70;//为了延时642us,通过下面的while(i--);
	while(i--);
	DSPORT=1;//然后拉高总线,如果DS18B20温度传感器做出反应将会在15us~60us后将总线拉低
	i=0;//下面还用到这个i
	while(DSPORT)//等待DS18B20温度传感器自己拉低总线电位
	//如果温度传感器存在,证明可以自己拉低总线电位,则直接跳过while循环
	//返回一个1即可,证明温度传感器存在。否则就在while循环里返回一个0,证明不存在。
	{
		Delay1ms(1);//实参设置为1,就延时1个ms
		i++;
		if(i>5)//等待5ms(自定义愿意等待多少多长时间判定为超时),若5ms后温度传感器还没有作出反应,则初始化失败,证明
		//温度传感器不存在或者坏了。
		{
			return 0;//初始化失败
		}
	}
	return 1;//初始化成功,注意return1的位置!!别写while循环里!!
}//漏了个},注意
void Ds18b20WriteByte(uchar dat)
{//向温度传感器写入一个字节的数据的函数
//代码模拟温度传感器写入时序
	uint i=0,j;	//i=0是习惯,不初始化i也行
	for(j=0;j<8;j++)
	{
		DSPORT=0;//每写入一位数据之前,先把总线拉低1us(时序就是这样的)
		i++;
		//注意DSPORT的拼写!!!!
		DSPORT=dat&0x01;//然后写入一个数据,从最低位开始。只能一个一个位写入
		//温度传感器。所以你必须先让dat的其他位为0,然后根据循环8次让位一个一个写入
		i=6;//因为下面要用到i,你必须设定i
		while(i--);//延时68us,时序图上写着延时最少60us
		DSPORT=1;//然后释放(恢复)总线(拉高总线)。至少给总线1us的时间让总线拉高
		//才能接着写入第二个数值(执行一行代码就是1us,所以不必再写个延时代码huo
		//函数
		dat>>=1;//因为这一位写完了,你要写dat的下一位数据给温度传感器(dat传进
		//来的时候是8位),你就要给dat移位,把写完的这位给移走(写入位是从低位到
		//高位写(规定))
	}	
}
uchar Ds18b20ReadByte()
{
	//读取温度传感器的一个字节的函数
	uchar byte,bi;//下面解释定义两个无符号字符型的目的
	uint i,j;
	for(j=8;j>0;j--)//这个循环和写入函数那个循环含义一致
	//也是一位一位读(加起来相当于读了一个字节),从低位到高位读
	{
 		DSPORT=0;//先将总线拉低1us(时序图规定)
		i++;//执行一行代码就是1us
		DSPORT=1;//然后释放(恢复)总线(时序图规定)
		i++;
		i++;//大约延时6us等待数据稳定
		bi=DSPORT;//读取数据,从最低位开始读取。(根据时序图事实,此时DSPORT可能是0或者1)
		byte=(byte>>1)|(bi<<7);
		//先将byte右移一位,然后和左移7位后的bi或运算,移动byte后高位补0
		//举个例子,如果byte读取的是0000 0000,然后移位是0000 0000,然后bi是1,左移七位
		//就变成了1000 0000,然后这俩相或,存储在byte中,就变成了1000 0000
		//然后再循环下来,bi=1,byte先右移1位让之前存储在byte的字节给移开把位置
		//让给现在读取的位。然后bi又左移7位,然后再相或,byte就变成了1100 0000,
		//如此循环,读取的位顺着byte>>1就往低位走了,符合从最低位开始读取的规则。
		i=4;//读取完之后等待58us(下面的while循环可以实现)再接着读取下一个数
		while(i--);
	}
	return byte;//读取完毕,返回读取的一个字节
}
void Ds18b20ChangeTemp()
{//温度传感器数据转温度函数,让温度传感器开始转换温度
	Ds18b20Init();//初始化温度传感器
	Delay1ms(1);//根据需要延时1ms
	Ds18b20WriteByte(0xcc);//根据需要,跳过ROM操作命令
	Ds18b20WriteByte(0x44);//发送一个温度转换命令给温度传感器
	//Delay1ms(100);	//等待转换成功,而如果你是一直刷着的话,就不用这个延时了
}
void Ds18b20ReadTempCom()//函数名拼写问题。。。。所以会有警告,给老子注意!!!!!!!!!
{//发送读取温度传感器里的温度的命令
	Ds18b20Init();//初始化温度传感器
	Delay1ms(1); //根据需要延时1ms
	Ds18b20WriteByte(0xcc);//根据需要,跳过ROM操作命令
	Ds18b20WriteByte(0xbe);//发送读取温度传感器里的温度的命令
}
int DS18b20ReadTemp()
{//读取温度传感器里的温度。注意这些函数的功能!!!!
	int temp=0;
	uchar tmh,tml;//规定,只能这么分开存温度值,而且要接受读取温度传感器里的温度数据
	Ds18b20ChangeTemp();//先发送让温度传感器数据转成温度的命令
	//注意函数的拼写和变量的拼写!!!
	Ds18b20ReadTempCom();//等待数据转换成温度后发送读取温度传感器里温度的命令
	tml=Ds18b20ReadByte();//读取16位温度值,先读取温度的低8位给tml
	tmh=Ds18b20ReadByte();//再读取高8位给tmh
	temp=tmh;
	temp<<=8;//先让返回的温度值(真正的温度)接收高8位的温度二进制值
	//然后给把这高8位左移8位变成真正的高8位,以提供位置接收温度二进制值低8位
	temp|=tml;//或一下就可以了,很方便省事。也能保证高8位的安全,高8位数据不被篡改
	return temp;//读取温度值读取完毕,返回温度给主函数调用的地方。
}

temp.h文件

#ifndef _temp_H_
#define _temp_H_
#include"reg52.h"//这个别丢,很重要
#ifndef uchar //这少了c
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif
//两个重定义,ifndef 如果没有则定义的意思,然后下面就define,define完了别忘了endif
//来终止if(或说define),这个格式务必记好!!!
sbit DSPORT=P3^7;//定义温度传感器使用的IO口,这里DSPORT是温传器的名字
void Delay1ms(uint );
uchar Ds18b20Init();//温度传感器初始化函数
void Ds18b20WriteByte(uchar com);//写入温度传感器的数据函数
uchar Ds18b20ReadByte();//读取温度传感器里的一字节的数据函数
void Ds18b20ChangeTemp();//变换温度传感器数据的函数
void Ds18b20ReadTempCom();//发送读取温度传感器里的温度的命令
int DS18b20ReadTemp();//读取温度传感器里温度的数据函数
//这里定义为int是方便主函数的调用。
//以上声明全局函数
#endif

注意函数名的拼写,这里函数名又臭又长。
如果函数名在头文件、头文件附属c文件、主函数c文件不一致,则会报错:

*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
SEGMENT: ?PR?DS18B20READTEMCOM?TEMP
*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL
SYMBOL: DS18B20READTEMPCOM
MODULE: temp.obj (TEMP)
*** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL
SYMBOL: DS18B20READTEMPCOM
MODULE: temp.obj (TEMP)
ADDRESS: 05F1H
翻译:
***警告L16:未调用段,忽略覆盖过程

段:公关? DS18B20TEMPCOM ? TEMP

***警告L1:外部符号未解析

象征:DS18B20READTEMPCOM

模块:temp.obj(临时)

***警告L2:引用外部未解析

象征:DS18B20READTEMPCOM

模块:temp.obj(临时)

地址:05 f1h

这是头文件附属c文件和头文件两个文件的某个函数名没对应一致所产生的警告
气死,找这个bug找了半天!


转载:https://blog.csdn.net/weixin_45910408/article/details/105870763
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场