• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

求助DS18B20读不出正确的数据

先贴上DS18B20的驱动,这个我是照着书抄的,可以确定没抄错,因为是初学所以想先用现成的。

下面的程序是DS18B20.c里的代码,是用来驱动18B20的。我的工程包含多个文件。

#include

#define uchar unsigned char 
#define uint unsigned int

sbit DQ = P1^0;         //DS18B20的DQ脚

void Delay(int num)
{
	for (;num>0;num--);
}

void Init_DS18B20(void)           //初始化18B20
{
	unsigned char x=0;
	DQ = 1;    
	Delay(8);  
	DQ = 0;    
	Delay(80);  
	DQ = 1;    
	Delay(14);
	x=DQ;      
	Delay(20);
}

/******************************************************************************/
unsigned char ReadOneChar(void)         //从18B20读取一个字节
{
	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(4);
	}
	return(dat);
}
/******************************************************************************/
void WriteOneChar(unsigned char dat)          向18B20写入一个字节
{
	unsigned char i=0;
	for (i=8; i>0; i--)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay(5);
		DQ = 1;
		dat>>=1;
	}
}
/******************************************************************************/
unsigned int ReadTemperature(void)                    //读取温度
{
	unsigned char a=0;
	unsigned char b=0;
	unsigned int t=0;
	float tt=0;
	Init_DS18B20();
	WriteOneChar(0xCC); 
	WriteOneChar(0x44); 
	Init_DS18B20();
	WriteOneChar(0xCC); 
	WriteOneChar(0xBE); 
	a=ReadOneChar();  
	b=ReadOneChar(); 
	t=b;
	t<<=8;
	t=t|a;
	tt=t*0.0625;
	t= tt*10+0.5; 
	return(t);
}

uchar printTemperature(void)
{
	unsigned int i=0;
	unsigned char a=0,b=0,c=0;
	i=ReadTemperature();
	a=i/100;
	b=i/10-a*10;
	i = a*10 + b;
	return i;		
}

下面的程序是main.c里的:

#include
#include

#define uint unsigned int
#define uchar unsigned char
extern void Init_UART(void);
extern void UART_T_CHAR(uchar);
extern void UART_T_STRING(uchar *);
extern unsigned int ReadTemperature(void);
extern uchar printTemperature(void);

uchar code string[]="Current Temperature Is:";

void delayms(uint t)
{
	uint i,j;
	for(i=t;i>0;i--)
	for(j=100;j>0;j--);
}

void Init_MCU()
{
	EX0=1;
	EA=1;
}

void main()
{
	uint tempr;       //用于存储当前温度
	uchar temp_char[3]="000";         //存储当前温度的字符数组
	Init_MCU();
	Init_UART();
	
	while(1)
	{
		tempr=ReadTemperature();
		/*tempr=tempr/10;                                         
		temp_char[1]=tempr%10+'0';
		temp_char[0]=(tempr-tempr%10)/10+'0';              
		temp_char[2]='\0';*/                                           //以上4行是将数值型温度数据转换为对应的字符数组,因为现在在测试
		UART_T_STRING(string);                                      //这个程序,暂未使用
		//UART_T_STRING(temp_char);                           //此语句也暂未使用
		TI=1;                                                                  //从此行起到TI=0;是为了测试DS18B20的驱动是否工作正常而临时加入的
		printf("%d\n",tempr);                                         //用printf函数将tempr的数值发送到上位机,如果DS18B20驱动正常,ze
		while(!TI);                                                           //上位机可收到数值,给18B20加温,数值会变化。
		TI=0;
		delayms(5000);
	}
}

void ISP_Download() interrupt 0   //该中断子程序通过使用外中断0,在INT0脚对地短接时将软复位MCU
{                                                   //从而实现不冷启动也能下载程序
	IAP_CONTR=0x60;
}

下面的程序是UART.c里的,用来驱动串口,向上位机发送温度数据,实测以下的代码没有问题

#include
#include

#define uint unsigned int
#define uchar unsigned char
void Init_UART(void)		//初始化串口,12MHZ晶体,9600bps,使用定时器T1,8位自动重装模式,串口模式1.
{
	PCON &= 0x7F;		
	SCON = 0x50;		
	AUXR |= 0x40;		
	AUXR &= 0xFE;		
	TMOD &= 0x0F;		
	TMOD |= 0x20;
	TL1 = 0xD9;		
	TH1 = 0xD9;		
	ET1 = 0;		
	TR1 = 1;
}

void UART_T_CHAR(uchar T_c)//该子程序实现通过串口向上位机发送一个字符的功能
{
	SBUF=T_c;
	while(!TI);
	TI=0;
}

void UART_T_STRING(uchar *string)//该子程序实现通过串口向上位机发送字符串的功能。
{
	TI=1;
	puts(string);
	while(!TI);
	TI=0;
}


程序就是以上了,因为现在处于测试18B20驱动是否正常的阶段,一些代码是临时加上去的,为了测试之用。
问题就是,串口助手收到的数值是-24577,而且不随温度变化,弄了一天,还是不知道怎么回事,我甚至都以为自己买成三极管了。希望各路大神帮忙看一下。
顺便手画一下DS18B20与单片机的连接

全部回复(3)
正序查看
倒序查看
2014-07-29 11:35
看看你的晶振,还有单片机设置的是1T工作模式还是6T  还是12T模式。
0
回复
2014-12-25 14:20
@yueyunno1
看看你的晶振,还有单片机设置的是1T工作模式还是6T 还是12T模式。
正解,你如果用89C52的片子应该更好做
0
回复
45280
LV.4
4
2015-05-03 13:13
18B20 对时间要求比较高,应该是延时的问题,乱糟糟的我也没怎么看。


void Init_DS18B20(void)           //初始化18B20
{
	unsigned char x=0;
	DQ = 1;    
	Delay(8);  
	DQ = 0;    
	Delay(80);  
	DQ = 1;    
	Delay(14);
	x=DQ;      
	Delay(20);
}
这里面的变量x有什么用? 纯属吃饱了撑的,多余!
如果是要检测初始化是否成功的话,那么就少了一句 return(x); 
还要把函数名改为 bit Init_DS18B20() 或者 unsigned char Init_DS18B20()
不需要检测的话,那个变量x就是多余的。
下面我说下我个人的经验,
DS18B20 延时比较多,转换一次需要零点几秒,
很多空延时,效率很低。
如果写成像书本里面那样用在主函数里调用的话是不太稳妥的,
因为一个稍大点完整的程序会有很多各种中断,就好比初始化延时的时候,被中断了,
转去执行中断里面的程序,完了之后返回原来的地方,但是已经超时了,初始化就失败了;
如果是在发送或者接收数据的话,就会出现数据错误,如果产品是通过温度来控制外部其他部件的话,就会出现误动作。
其实18B20,还有另一种更为效率的程序,只不过,真正实用的东西是不会出现在书本上的。
再举个例子,比如按键扫描,书本上都是这么写的,while(!KEY);等待按键释放。
这在实际中是不现实的。如果一个产品设计成这样,会出现很多问题,如果按着按键不放,或者按键出现故障导致一直出现低电平,
那么程序将进入死循环。。  实际使用中一般不会用这种方法的。
还是那句话,真正实用的东西一般不会出现在书本上的,就像教科书里扶老奶奶过马路一个吊样,你去扶一个试试……
以上纯属个人观点。
0
回复