【蓝桥杯】DS18B20温度传感器

备赛目录

目录

    • 1、DS18B20简介
    • 2、通信协议
      • 2.1初始化时序
      • 2.2写入数据
      • 2.3读取数据
    • 3、读取温度

1、DS18B20简介

DS18B20数字温度计提供9位到12位摄氏度的温度测量,并具有非易失性用户可编程上下触发点的报警功能。DS18B20 包括寄生电源电路、64 位 ROM 和单线接口电路、暂存器、EEPROM、8 位 CRC 生成器和温度传感器等。DS18B20通过一条1线总线进行通信,根据定义,该总线只需要一条数据线(和地面)就可以与一个中央微处理器进行通信。64 位 ROM 中存放的 48 位序列号用于识别同一单线上连接的多个 DS18B20,以实现多点测温。它的工作温度范围为-55°C到+125°C,在-10°C到+85°C的范围内精确到±0.5°C。此外,DS18B20可以直接从数据线获得电力(“寄生虫电力”),消除了对外部电源的需要。
简单来说,DS18B20是通过一条总线进行数据的读写,并能多个设备同时工作,其工作范围最好在-10~+85°C,数据存储在暂存器和ROM里,
【蓝桥杯】DS18B20温度传感器_第1张图片

2、通信协议

1-ware单总线是Maxim全资子公司Dallas的一项专有技术。与目前多数标准串行数据通信方式,如SPI / I2C不同,它采用单根信号线,既传输时钟,又传输数据,而且数据传输是双向的。因此对时序要求非常严格,它具有节省I/O口线资源、结构简单、成本低廉、便于总线扩展和维护等诸多优点。
1-ware单总线适用于单个主机系统,能够控制一个或多个从机设备。当只有一个从机位于总线上时,系统可按照单节点系统操作;而当多个从机位于总线上时,则系统按照多节点系统操作。

单总线命令序列如下:
第一步:初始化
第二步:ROM命令(跟随需要交换的数据)
第三步:功能命令(跟随需要交换的数据)

每次访问单总线器件,必须严格遵守这个命令序列,如果出现序列混乱,则单总线器件不会响应主机。但是,这个准则对于搜索ROM命令和报警搜索命令例外,在执行两者中任何一条命令之后,主机不能执行其后的功能命令,必须返回至第一步。

2.1初始化时序

初始化是在干嘛?
建立主机和从机设备的通讯,即主机要搜索到从机,从机要响应主机
【蓝桥杯】DS18B20温度传感器_第2张图片
与DS18B20的所有通信都从一个初始化序列开始,该初始化序列包括来自主服务器的复位脉冲和来自DS18B20的存在脉冲。
这一点如图13所示。当DS18B20响应于复位发送存在脉冲时,它向主服务器指示它在总线上并准备好操作。在初始化过程中,总线主线通过将1线总线拉至最低480µs来传输(TX)复位脉冲。然后,总线主机释放总线并进入接收模式(RX)。当总线被释放时,5kΩ上拉电阻器将1线总线拉高。当DS18B20检测到这个上升边缘时,它等待15µs到60µs,然后通过将1线总线拉至60µs到240µs来发送存在脉冲。
换句话说,初始化开始需要拉低总线,至少持续480us~960us,然后释放总线产生一个上升沿,(目的是搜索总线上的设备)。总线上的DS18B20读取到这个上升沿后,等待15us到60us后拉低总线,持续60us到240us向主机发送存在脉冲(响应主机)。至此初始化完成。


//初始化,返回0则成功,返回1失败
bit DS_Init(void)
{
  bit ack;

  //禁止总中断
  EA = 0;
  //拉低总线
  DSIO = 0;
  //持续大概480~960us
  Delay800us();
  //释放总线
  DSIO = 1;
  //DS18B20等待60us,会拉低总线,大概60~240us主动释放总线
  Delay60us();
  //读取存在脉冲
  ack = DSIO;
  //等待存在脉冲结束
  while(!DSIO);
  //应该写一个超时判断的
  EA = 1;
  //返回0成功,返回1失败
  return ack;
}

2.2写入数据

写入什么?怎么写入?
【蓝桥杯】DS18B20温度传感器_第3张图片
有两种类型的写时间槽:“写1”时间槽和“写0”时间槽。
总线主线使用写入1时隙将逻辑1写入DS18B20,使用写入0时隙将逻辑0写入DS18B20。
所有写入时隙的持续时间必须至少为60µs,每个写入时隙之间的最小为1µs恢复时间。
这两种类型的写入时隙都是由主机将1线总线拉低时启动的(参见图14)。要生成Write1时间槽,在将1线总线拉低后,总线主线必须在15µs内释放1线总线。当总线释放时,5kΩ上拉电阻将总线拉高。要生成写入0时间槽,在将1线总线拉低后,总线主线必须在时间槽内继续保持低水平(至少60µs)在主节点启动写入时间槽后,DS18B20在从15µs到60µs的窗口期间对1线总线进行采样。如果采样窗口期间总线高,则将1写入DS18B20。如果总线很低,则将0写入DS18B20

//向DS18B20写入一个字节(8位)
void DS_Write(unsigned char dat)
{
  unsigned char mask;//用于位选

  //禁止总中断
  for(mask = 0x01;mask!=0;mask <<=1)
  {
    //写入数据先拉低总线,产生一个2us的低电平脉冲
    DSIO = 0;
	Delay2us();
    //输出一bit值
	if(dat&mask) DSIO = 1;
	else DSIO = 0;
	//等待60us让DS18B20接收到这个值
	Delay60us();
	//写入一bit后拉高总线
	DSIO = 1;
  }
  //允许总中断
  EA = 1;
}

2.3读取数据

命令写入后,就可以开始读取温度了
【蓝桥杯】DS18B20温度传感器_第4张图片
这里是如何读取温度的操作时序与命令
DS18B20只能在主发出读取时隙时向数据传输给主服务器。因此,主服务器必须在发出读刮板BEh或读电源B4h]命令后立即生成读时隙,以便DS18B20能够提供所请求的数据。此外,主服务器可以在发出转换T[44h]或RecallE2[B8h]命令后生成读取时隙,以查找DS18B20功能命令部分中解释的操作状态。所有读取时隙的持续时间必须至少为60µs,时隙之间至少有一个1µs恢复时间。读取时隙由主设备将1线总线拉至最低1µs,然后释放总线启动(参见图14)。在主服务器启动读取时隙后,DS18B20将开始在总线上传输一个1或0。DS18B20通过离开总线传输1,通过拉总线传输0。当传输一个0时,DS18B20将在时间段结束时释放总线,并且总线将被上拉寄存器拉回其高空闲状态。来自DS18B20的数据对于启动读取时间槽的下降边后的15µs有效。因此,主必须释放总线,然后从槽开始的15µs总线内采样总线状态。图15说明了对于一个读取时隙,TINIT、TRC和t样本的总和必须小于15µs。图16显示,通过保持TINIT和TRC尽可能短,并在15µs周期结束的读取时间段定位主样本时间,系统定时裕度最大化。

如果觉得阅读很累,建议直接看代码注释

//读取出一个字节的数据
unsigned char DS_Read(void)
{
  unsigned char mask,dat = 0;
  //禁止总中断
  EA = 0;
  for(mask = 0x01;mask!=0;mask<<=1)
  {
    //读出数据先拉低总线,产生一个2us的低电平脉冲
    DSIO = 0;
	Delay2us();
	//结束低电平脉冲,等待DS输出数据
	DSIO = 1;
	Delay2us();
	//如果输出一个1,或运算在这个位置保存这个值,否则还是0
	if(DSIO)
	dat = dat|mask;
	Delay60us();
  }
  EA = 1;
  return dat;
}

3、读取温度

第一步:初始化
第二步:ROM命令(跟随需要交换的数据)
第三步:功能命令(跟随需要交换的数据)

初始化完成后将写入命令,当然DS18B20可不止这些命令,
1、 0XCC——跳过ROM
为什么要跳过?什么时候可以跳过?下面官方的解释
主服务器可以使用此命令同时处理总线上的所有设备,而不发送任何ROM代码信息。例如,主服务器可以通过发出SkipROM命令和转换T[44h]命令,使总线上的所有DS18B20s同时执行温度转换。请注意,只有当总线上有一个从属设备时,读取刮刮板[BEh]命令才可以遵循跳过ROM命令。在这种情况下,通过允许主服务器从从读取而不发送设备的64位ROM代码来节省时间。如果有多个从属设备,则跳过ROM命令和读取刮刮板命令将导致总线上的数据冲突,因为多个设备将尝试同时传输数据。
总的来说就是,只有一个单总线设备时,跳过Rom可以节省时间;
2、0X44——温度转化命令
3、0XBE——读取温度命令

#include
void Delay800us()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 9;
	j = 151;
	do
	{
		while (--j);
	} while (--i);
}

void Delay60us()		//@11.0592MHz
{
	unsigned char i, j;

	i = 1;
	j = 162;
	do
	{
		while (--j);
	} while (--i);
}

void Delay2us()		//@11.0592MHz
{
	unsigned char i;

	i = 3;
	while (--i);
}

//初始化,返回0则成功,返回1失败
bit DS_Init(void)
{
  bit ack;

  //禁止总中断
  EA = 0;
  //拉低总线
  DSIO = 0;
  //持续大概480~960us
  Delay800us();
  //释放总线
  DSIO = 1;
  //DS18B20等待60us,会拉低总线,大概60~240us主动释放总线
  Delay60us();
  //读取存在脉冲
  ack = DSIO;
  //等待存在脉冲结束
  while(!DSIO);
  //应该写一个超时判断的
  EA = 1;
  //返回0成功,返回1失败
  return ack;
}
//向DS18B20写入一个字节(8位)
void DS_Write(unsigned char dat)
{
  unsigned char mask;//用于位选

  //禁止总中断
  for(mask = 0x01;mask!=0;mask <<=1)
  {
    //写入数据先拉低总线,产生一个2us的低电平脉冲
    DSIO = 0;
	Delay2us();
    //输出一bit值
	if(dat&mask) DSIO = 1;
	else DSIO = 0;
	//等待60us让DS18B20接收到这个值
	Delay60us();
	//写入一bit后拉高总线
	DSIO = 1;
  }
  //允许总中断
  EA = 1;
}

//读取出一个字节的数据
unsigned char DS_Read(void)
{
  unsigned char mask,dat = 0;
  //禁止总中断
  EA = 0;
  for(mask = 0x01;mask!=0;mask<<=1)
  {
    //读出数据先拉低总线,产生一个2us的低电平脉冲
    DSIO = 0;
	Delay2us();
	//结束低电平脉冲,等待DS输出数据
	DSIO = 1;
	Delay2us();
	//如果输出一个1,或运算在这个位置保存这个值,否则还是0
	if(DSIO)
	dat = dat|mask;
	Delay60us();
  }
  EA = 1;
  return dat;
}
//启动一次温度转换,返回值为是否成功
bit DS_Start()
{
  bit ack;

  ack = DS_Init();//初始化,获取18B20应答
  if(ack==0)
  {
     DS_Write(0xcc);//跳过rom操作
	 DS_Write(0x44);//启动一次温度转换
  }
  return ~ack;//ack==0表示操作成功,所以取反
																		  
}
//读取温度数据
bit DS_GetTemp(int *temp)
{ 
  bit ack; 
  unsigned char LSB, MSB;//16bit温度值的低字节和高字节
  ack = DS_Init();//初始化,获取18B20应答

  if(ack==0)
  {
     DS_Write(0xcc);//跳过rom操作
	 //先读取到的是低字节的低位,读完了第一个字节后,再读高字节的低位,直到两个字节全部读取完毕。
	 DS_Write(0xbe);//发送读命令
	 LSB = DS_Read();//读取低八位
	 MSB = DS_Read();//读取高八位
	 //整合LSB和MSB,得到一个十六位的数据
	 *temp = ((unsigned int) MSB << 8) + LSB;
  }

  return ~ack;
}

蓝桥杯会提供一份官方驱动,不过需要对延时做一点处理,这里只写了.C,头文件就交给各位了,应该没问题吧,

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "reg52.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
    unsigned char i;
	while(t--)
	{
	  for(i=0;i<12;i++);//这里是添加的代码
	}
}

//通过单总线向DS18B20写一个字节
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//从DS18B20读取一个字节
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}
//DS18B20温度采集程序:整数
u8 Read_Temp_d(void)
{
    u8 low,high;
  	char temp;  //这是一个有符号的数
  
  	init_ds18b20();
  	Write_DS18B20(0xCC);
  	Write_DS18B20(0x44); //启动温度转换
  	Delay_OneWire(200);

  	init_ds18b20();
  	Write_DS18B20(0xCC);
  	Write_DS18B20(0xBE); //读取寄存器

  	low = Read_DS18B20(); //低字节
  	high = Read_DS18B20(); //高字节
  
  	temp = high<<4;   //只取了整数部分和符号位
  	temp |= (low>>4);
  
  	return temp;
}
//温度采集,含小数
float ReadTemp_Float(void)
{
  u16 temp;
  float temperature;
  u8 LSB,HSB;

  init_ds18b20();
  //写入温度转换指令
  Write_DS18B20(0xcc);//跳过ROM
  Write_DS18B20(0x44);//开始温度转换
  Delay_OneWire(200);

  init_ds18b20();
  Write_DS18B20(0xcc);//跳过ROM
  Write_DS18B20(0xBE);//读取寄存器

  LSB = Read_DS18B20();
  HSB = Read_DS18B20();

  temp = ((HSB&0X0F)<<8)|LSB;
  temperature = temp*0.0625;

  return temperature;

}

如果觉得内容有用,点个赞么

备赛目录

你可能感兴趣的:(备考蓝桥杯,蓝桥杯,fpga开发,职场和发展)