DS18B20温度传感器在90c51上的使用

这个博客名好长

参考了郭天祥的《51单片机》和一个学长的讲解

http://blog.csdn.net/xiaocheng_sky/article/details/50743176


DS18B20是支持一线总线接口的温度传感器,它与微处理器连接时仅需要一条口线即可实现与微处理器与DS18B20的双向通信 。可直接将温度转化为串行数字信号供处理器处理,测温范围在-55°~+125°,温度传感器的精度为用户可编程的9,10,11或12位,分别以0.5℃,0.25℃,0.125℃和0.0625℃增量递增。


与单片机相连:



所以只要控制P1^4口就可以了


工作原理:

DS18B20的所有通信都是以由复位脉冲组成的初始化序列开始的,并采用的是单总线协议。 DS18B20启动后保持低功耗等待状态,当需要执行温度测量(和AD转换)时,总线控制器必须发出[44h]命令。(44H,向DS18B20写入0x44的指令,启动DS18B20进行温度转化,结果保存入内部9字节的RAM。)

温度转换[44h] 

该命令为初始化单次温度转换。温度转换完后,温度转换的数据存储在暂存寄存器RAM的2个字节长度的温度寄存器中,之后DS18B20恢复到低功耗的闲置状态。如果该设备是采用的“寄生电源“供电模式,在该命令执行10uS(最大)后主设备在温度转换期间必须强制拉高数据线(“DS18B20的供电”章节所描述)。如果该设备是采用的外部供电模式,主设备在温度转换命令之后可以执行读取数据时序,若DS18B20正在进行温度转换则会响应0电平,温度转换完成则响应1电平。在“寄生电源”供电模式下,因为在整个温度转换期间总线都是强制拉高的状态,故不会有上述响应。

      【高速暂存缓存器RAM由9个字节存储器组成,温度值存储在前两个字节,读取后将二进制转化为10进制后再乘以0.0625便为所测的实际温度值】

之后写入0xbe的指令,从RAM中读出温度数据。这个指令相当于一个开启读的命令,接下来就是读取的语句。


具体代码:

数据线定义为DQ或者ds。

对于DS18B20的操作基本就是三种类型:初始化,写时序,读时序。

延时函数: (15+15*z)us 的延时

void delay_us(uint z)
{
    for(z;z>0 ; z--)
    {
        _nop_();    _nop_();
        _nop_();    _nop_();
    }   
    _nop_();    _nop_();
}

(1)初始化:


这是学长的讲解和代码。

带返回值,有利于检验。

bit DS18B20_init()
{
    bit ack = 1;
    DQ = 0;         //主机拉低总线
    delay_us(32);   //延时495us
    DQ = 1//释放总线,同时IO口产生的上升沿能被DS18B20所检测到
    delay_us(4);    //延时大于60us,确保接下来DS18B20能发出60~240us的存在脉冲应答
    ack = DQ;      //在此60~240us之内DQ被DS18B20所占用,若存在,则其会发送一个低电平信号,DQ被DS18B20拉低,则ack为0,反之为1
    delay_us(15);  //延时达240us,让DS18B20释放总线
    DQ = 1return(ack);
}

DS18B20检测到I/O口引脚上的升沿后,等待,然后以拉低总线的方式发出脉冲,此时DQ为0,ask被赋值。所以若是返回的ask值为0,DS18B20成功应答。这点学长写反了,我和他说然而他不愿意改哈哈,可能是想坑更多的人吧。若是有人看他的讲解前有幸看了我这个菜鸟的代码, 我想还是比较幸运的。(如果他后来改了就忽略这段话


(2)写时序

来自他的文章:

主机在写时隙向DS18B20写入数据,其中分为写”0”时隙,和写”1”时隙。总线主机使用写“1”时间隙向DS18B20写入逻辑1,使用写“0”时间隙向DS18B20写入逻辑0.所有的写时隙必须有最少60us的持续时间,相邻两个写时隙必须要有最少1us的恢复时间。两种写时隙都通过主机拉低总线产生(见下图)为了产生写1时隙。 
在拉低总线后主机必须在15μs内释放总线。在总线被释放后,由于上拉电阻将总线恢复为高电平。为了产生写”0”时隙,在拉低总线后主机必须继续拉低总线以满足时隙持续时间的要求(至少60μs)。 
在主机产生写时隙后,DS18B20会在其后的15~60us的一个时间段内采样单总线(DQ)。在采样的时间窗口内,如果总线为高电平,主机会向DS18B20写入1;如果总线为低电平,主机会向DS18B20写入0。 
综上所述,所有的写时隙必须至少有60us的持续时间。相邻两个写时隙必须要有最少1us的恢复时间。所有的写时隙(写0和写1)都由拉低总线产生。

这里写图片描述

他的代码,哈哈丧心病狂,主要是我觉得这些没什么好再说的,我也补充不了什么

写字节函数、由低位至高位,向DS18B20写入一个字节的数据。 
无返回值。 
形参byte是待写入的字节数据,读取8次,移位8次,保证每位都传输至DQ

void tempwritebyte(uchar byte)
{
    uchar i;
    for(i=0 ; i<8 ; i++)
    {
        DQ = 0;           //拉低总线,产生写时隙
        _nop_();
        _nop_();          //大于1us的延时
        DQ = 1;           //15us之内释放总线
        _nop_();
        _nop_();          //适当延时
        DQ = byte & 0x01; //将字节低位写入单总线
        delay_us(3);      //在15~60us内等待DS18B20来采集信号
        DQ = 1//释放总线
        byte >>= 1;       //每次讲要读取的数据位移至最低位,
    }
}

(3)读时序

主机发起读时序时,DS18B20仅被用来传输数据给控制器。因此,总线控制器在发出读暂存器指令[0xBE]或读电源模式指令[0xB4]后必须立刻开始读时序,DS18B20可以提供请求信息。除此之外,总线控制器在发出发送温度转换指令[0x44] (或召回EEPROM指令[0xB8])之后读时序,详见DS18B20 的芯片手册上的功能指令。 
所有读时序必须最少60us,包括两个读周期间至少1us的恢复时间。当总线控制器把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持1us,然后总线被释放。DS18B20 通过拉高或拉低总线上来传输”1”或”0”。当传输逻辑”0”结束后,总线将被释放,通过上拉电阻回到上升沿状态。从DS18B20输出的数据在读时序的下降沿出现后15us 内有效。因此,总线控制器在读时序开始后必须停止把I/O口驱动为低电15us,以读取I/O口状态。

这里写图片描述


DS18B20的读时序的代码 
读字节函数、由低位至高位,读取DS18B20所采集到的数据。 
带返回值,可结合前面的写时序,对写、读数据函数进行检验(后面会提到检验过程及效果) 
byte 是读取到的字节数据。其中,此函数读取8次,移位7次(实际移位8次)

uchar tempreadbyte()
{
    uchar i;
    uchar byte;         //byte为要接收到的数据
    for(i=0 ; i<8 ; i++)
    {
        DQ = 0;         //产生读时序
        _nop_();
        _nop_();        //简单延时
        DQ = 1//释放总线,有从机DS18B20占用
        byte >>= 1;     //先进行移位
        if(DQ)          //让DS18B20占用总线,发出采集到的信号
            byte |= 0x80;  //若DQ=1,则让当前byte最高位为1,在下次循环中移位至次高位,最后达到从低位到高位接收的目的;若DQ=0,则可跳过此语句,直接在下次循环对byte进行移位补0。以上操作15us以内完成
        delay_us(3);    //延时60us
        DQ = 1//释放总线
        _nop_(); 
    }
}

具体再具体代码

忽略<>里的内容,文章发表后自动加上去的

主函数:

void main()
{
	int j;
	DS18B20_init();//初始化,这个可以写成int型返回值检测有没有回应
	while(1)
	{
		tempchange();//温度zhun
		for(j=10;j>0;j--)
		{
			dis_temp(get_temp());
		}
	}
	
}


函数:

void tempchange()
{
	DS18B20_init();
	delay(1);
	tempwritebytle(0xcc);//写跳过读ROM指令
	tempwritebytle(0x44);//写温度转化指令
}

关于这个0xcc的指令,


此时I/O口只连接了一个DS18B20。如果要控制多个DS18B20进行温度采集,只要将所有DS18B20的I/O口全部连接在一起就可以了。在具体操作时,通过读取每个DS18B20内部芯片的序列号来识别。


uint get_temp()
{
	uchar a,b;
	DS18B20_init();
	delay(1);
	tempwritebytle(0xcc);
	tempwritebytle(0xbe);//读取暂存寄存器
	a=tempreadbytle();
	b=tempreadbytle();
	temp=b;
	temp<<=8;
	temp=temp|a;//两个字节组合为一个字
	f_temp=temp*0.0625;
	temp=f_temp*10+0.5;//因为temp为整型,乘以10表示取小数点后取一位,加0.5四舍五入
	f_temp=f_temp+0.05;
    return temp;
}

数据存在寄存器的前两位,所以读取两次,将两个二进制整合为一个10进制数字后得到温度temp,再显示到数码管上。

void dis_temp(uint t)
{
	uchar i;
	i=t/100;
	display(0,i);
	i=t%100/10;
	display(1,i+10);//加10为了显示小数点
	i=t%10;
	display(2,i);
}
void display(int wei,int duan)
{
	P2=(P2&0X1F)|0XE0;
	P0=0X00;	  
	P2=(P2&0X1F);

	P2=(P2&0X1F)|0XC0;
	P0=DIG_PLACE[wei];	   
	P2=(P2&0X1F);
    
	P2=(P2&0X1F)|0XE0;
	P0=tab[duan]; 	  
	P2=(P2&0X1F);
	delay(5);
}


定义们:

#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int 
unsigned char tab[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,//没有小数点
                      0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};//有小数点
unsigned char code DIG_PLACE[8] = {
0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
sbit ds=P1^4;
uint temp;
float f_temp;

这个tab是特制的

嗯组合起来可以直接烧录了



比赛成绩,不存在的,我都被打击得转行了。

悲伤。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值