One-wire通信与DS18B20的应用


前言

  本次编程实验以IAP15F2K61S2为单片机主控芯片,头文件为STC15F2K60S2.H。若用于51系列单片机,以reg52.h为头文件,则读者需将程序中可能涉及的定时器初始化程序和LED亮灭程序和数码管显示程序,根据自身所用单片机原理图和手册进行修改。


一、One-wire通信

  One-wire 通信(单总线通信)是 达拉斯公司 的一项专有技术。One-wire 通信采用单根信号线,总线既作为时钟线又作为数据线,且数据传输为双向。

1.名词解释

  1.单总线系统:单总线系统包括一个总线控制器和一个或多个从机。当只有一个从机挂在总线上时,系统为“单点”系统;当有多个从机挂在总线上时,系统为“多点”系统。所有的指令和数据都是从最低有效位开始通过单总线传输。
  2.单总线信号:单总线信号类型:复位脉冲、存在脉冲、写0、写1、读0和读1。所有这些信号,除存在脉冲外,都是由总线控制器发出的。
  3.复位和应答序列:包括复位和存在脉冲。总线控制器和从机间的任何通讯都需要以初始化序列开始,初始化序列见下图。一个复位脉冲跟着一个存在脉冲表明从机已经准备好发送和接收数据。在初始化序列期间,总线控制器拉低总线并保持480us以发出一个复位脉冲,然后释放总线,进入接收状态。单总线由5K上拉电阻拉到高电平。当从机探测到总线上的上升沿后,等待15-60us,然后发出一个由60-240us低电平信号构成的存在脉冲。

复位序列

2.基本通信时序

  One-wire通信基本时序图如下:
读/写时序
  写时序:当总线控制器把数据线从逻辑高电平拉到逻辑低电平的时候,写时序开始。有两种写时序:写1时序和写0时序。所有写时序必须最少持续 60μs,包括两个写周期间至少 1μs 的恢复时间。总线控制器要生成一个写1时序,必须把总线拉到低电平然后释放,在写时序开始后的 15μs内允许总线拉到高电平。总线控制器要生成一个写 0 时序,必须把总线拉到低电平并保持 60μs。总线电平变低后,从机在一个15μs 到 60μs 的窗口内对总线采样。如果线上是高电平,就是写 1,如果线上是低电平,就是写 0。
  读时序:当从从机读取数据时,总线控制器生成读时序。当总线控制器把总线从高电平拉到低电平时,读时序开始。总线必须保持至少 1μs,然后总线被释放;从机通过拉高或拉低总线来输出1或0。输出的数据在读时序的下降沿出现后 15μs 内有效。因此,总线控制器在读时序开始后必须停止把总线驱动为低电平 15μs,以读取I/O 脚状态。在读时序的结尾,总线将被外部上拉电阻拉到高电平。所有读时序必须最少 60μs,包括两个读周期间至少 1μs 的恢复时间。

3.具体通信时序

  通过单总线访问 DS18B20 的协议如下:
    • 初始化
    • ROM 操作命令
    • 存储器操作命令
    • 执行数据

4.ROM指令

  一旦总线控制器探测到一个存在脉冲,它就发出一条ROM指令。如果总线上挂有多只DS18B20,这些指令将基于器件独有的64位ROM片序列码使得总线控制器选出特定要进行操作的器件。这些指令同样也可以使总线控制器识别有多少只,什么型号的器件挂在总线上,同样,它们也可以识别哪些器件已经符合报警条件。ROM指令有5条,都是8位长度。总线控制器在发起一条DS18B20功能指令之前必须先发出一条ROM指令。ROM 指令操作流程图见下图:
ROM指令流程

1.Search ROM [F0h] (搜索 ROM指令)

  当系统上电初始化的时候,总线控制器必须通过识别总线上所有ROM片序列码去得到从机的数目和型号。总线控制器通过搜索ROM指令多次循环搜索ROM编码,以确认所有从机器件。如果总线上只有一只从机,那么可以用较为简单的读取ROM指令(见下文)代替搜索ROM指令。在每次搜索ROM指令之后,总线控制器必须返回步骤1,即初始化。

2.READ ROM [33h] (读取 ROM指令)

  只有在单总线系统为单点系统,只存在单只DS18B20的时候才能使用这条命令。该命令允许总线控制器在不使用搜索ROM指令的情况下读取从机的64位片序列码。如果总线上有不止一只从机,当所有从机试图同时传送信号时就会发生数据冲突。

3.MATH ROM [55h] (匹配 ROM指令)

  匹配ROM指令,后跟64位ROM编码序列,让总线控制器在多点总线上定位一只特定的DS18B20。只有和64位ROM片序列码完全匹配的DS18B20才能响应随后的存储器操作指令。所有和64位ROM片序列码不匹配的从机都将等待复位脉冲。

4.SKIP ROM [CCh] (忽略 ROM指令)

  这条指令允许总线控制器不用提供64位ROM编码就使用功能指令。例如,总线控制器可以先发出一条忽略ROM指令,然后发出温度转换指令[44h](见下文),从而完成温度转换操作。
  注意:当只有一只从机在总线上时,无论如何,忽略ROM指令之后只能跟着发出一条读取暂存器指令[BEh](见下文)。在单点系统情况下使用该命令,器件无需发回64位ROM编码,从而节省了时间。如果总线上有不止一只从机,若发出忽略ROM指令,由于多只从机同时传送信号,总线上就会发生数据冲突。

5.ALARM SEARCH [ECh] (报警搜索指令)

  这条命令的流程和搜索ROM指令相同,然而,只有满足报警条件的从机才对该命令作出响应。只有在最近一次测温后遇到符合报警条件的情况,DS18B20 才会响应这条命令。在每次报警搜索指令周期之后,总线控制器必须返回步骤1,即初始化。

二、DS18B20的应用

  DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20通过One-wire 通信与MCU交换数据。

1.主要特性

主要特性

2.引脚定义和原理图

引脚
  VDD:可选供电脚;
  GND:接地;
  DQ:单总线数据线;
原理图
  由原理图可知,DQ接 P1^4 I/O口。

3.DS18B20存储器

  DS18B20的存储器结构示意图如下。存储器有一个暂存SRAM和一个存储高低报警触发值TH和TL的非易失性电可擦除EEPROM组成。注意当报警功能不使用时,TH和TL寄存器可以被当作普通寄存器使用。所有的存储器指令被详述于DS18B20功能指令节。
  位0和位1为测得温度信息的LSB和MSB。这两个字节是只读的。位2和位3字节是TH和IL的拷贝。位4包含配置寄存器数据,其被详述于DS18B20配置寄存器节。位5,6和7被器件保留,禁止写入;这些数据在读回时全部表现为逻辑1。
  数据通过写暂存器指令[4Eh]写入高速暂存器的2,3和4位;数据必须以位2为最低有效位开始传送。为了完整的验证数据,高速暂存器能够在数据写入后被读取(使用读暂存器指令[BEh])。在读暂存器时,数据以位0为最低有效位从单总线移出。总线控制器传递从暂存器到EEPROM的TH, TL和配置数据必须发出拷贝暂存器指令[48h]。
  EEPROM寄存器中的数据在器件掉电时仍然保存;.上电时, 数据被载入暂存器。数据也可以通过召回EEPROM命令从暂存器载入EEPROM。总线控制器在发出这条命令后发出读时序,DS18B20 返回0表示正在召回中,返回1表示操作结束。
  CRC用于校验数据是否被总线控制器正确读取,在此不作介绍。
存储器

4.DS18B20功能指令

  在总线控制器给欲连接的DS18B20发送一条ROM命令后,跟着可以发送一条DS18B20功能指令。这些命令允许总线控制器读写DS18B20的暂存器,发起温度转换和识别电源模式(后者在此不作介绍)。
功能指令

1.CONVERT T [44h] (温度转换指令)

  这条命令用以启动一次温度转换。温度转换指令被执行,产生的温度转换结果数据以2个字节的形式被存储在高速暂存器中,而后DS18B20保持等待状态。如果DS18B20以外部电源供电,总线控制器在发出该命令后跟着发出读时序,DS18B20 如处于转换中,将在总线上返回0,若温度转换完成,则返回1。

2.WRITE SCRATCHPAD [4Eh] (写暂存器指令)

  这条命令向DS18B20的暂存器写入数据,开始位置在TH寄存器(暂存器的第2个字节),接下来写入IL寄存器(暂存器的第3个字节),最后写入配置寄存器
(暂存器的第4个字节)。数据以最低有效位开始传送。上述三个字节的写入必须发生在总线控制器发出复位命令前,否则会中止写入。

3.READ SCRATCHPAD [BEh] (读暂存器指令)

  这条命令读取暂存器的内容。读取将从字节0开始,一直进行下去,直到第9字节(字节8, CRC)读完,如果不想读完所有字节,控制器可以在任何时间发出复位命令来中止读取。

4.COPY SCRATCHPAD [48h] (拷贝暂存器指令)

  这条命令把TH,IL和配置寄存器(第2、3、4字节)的内容拷贝到EEPROM中。

5.RECALL E2 [B8H] (召回EEPROM指令)

  这条命令把报警触发器的值(TH和TL)以及配置数据从EEPROM拷回暂存器。总线控制器在发出该命令后读时序, DS18B20会输出拷回标识: 0标识正在拷回,1标识拷回结束。这种拷回操作在DS18B20上电时自动执行,这样器件一上电暂存器里马上就存在有效的数据了。

6.READ POWER SUPPLY [B4h] (读电源式指令)

  总线控制器在这条命令发给DS18B20后发出读时序,若是寄生电源模式,DS18B20将拉低总线,若是外部电源模式,DS18B20将会把总线拉高。

5.配置寄存器

  通过R0和R1来设置DS18B20的精度。
配置寄存器

6.温度寄存器

温度寄存器
  测量得到温度T=MSByte*16+LSByte/16。
温度数据关系

7.读出温度数据流程

  初始化,然后总线控制器发出SKIP ROM [CCh] (忽略 ROM指令)(因只有一个DS18B20挂在总线上),然后发出CONVERT T [44h] (温度转换指令)。等待温度变换完成后,再次初始化,然后总线控制器发出SKIP ROM [CCh] (忽略 ROM指令)(因只有一个DS18B20挂在总线上),然后发出READ SCRATCHPAD [BEh] (读暂存器指令),将LSB和MSB读出,进行运算后(T=MSByte*16+LSByte/16)即可得到温度值。

三、编程实现

1.onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

bit init_ds18b20(void);   //初始化
unsigned char Read_DS18B20(void);    //读数据
void Write_DS18B20(unsigned char dat);  //写指令

#endif

2.onewire.c

#include <STC15F2K60S2.H>

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

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
	while(t--);
}

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

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

//DS18B20设备初始化
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(120);
  	DQ = 0;
  	Delay_OneWire(800);
  	DQ = 1;
  	Delay_OneWire(100); 
    initflag = DQ;     
  	Delay_OneWire(50);
  
  	return initflag;
}

3.DS18B20.h

#ifndef __DS18B20_H
#define __DS18B20_H

float rd_temper(); //变换并读出温度

#endif

4.DS18B20.c

#include <STC15F2K60S2.H>
#include "onewire.h"


void ds18b20_delay(int t)
{
	while(t--);
}
float rd_temper()
{
	unsigned char lsb=0,hsb=0;
	int temp_wendu=0;
	float T=0;
	init_ds18b20();   //初始化
	Write_DS18B20(0xcc);   //SKIP ROM [CCh] (忽略 ROM指令)
	Write_DS18B20(0x44);	 //CONVERT T [44h] (温度转换指令)
	
	ds18b20_delay(1000);  //等待温度变换完成
	
	init_ds18b20();      //再次初始化
	Write_DS18B20(0xcc);   //SKIP ROM [CCh] (忽略 ROM指令)
	Write_DS18B20(0xbe);   //READ SCRATCHPAD [BEh] (读暂存器指令)
	
	lsb=Read_DS18B20();    //读出温度数据的低字节
	hsb=Read_DS18B20();    //读出温度数据的高字节
	temp_wendu=(hsb<<8)|lsb;   
	T=temp_wendu/16.0;         //得出实际温度
	return T;
}

5.main.c

#include <STC15F2K60S2.H>
#include "intrins.h"
#include "math.h"
#include "ds18b20.h"
#define outputp0(y,x)  P0=x,P2&=0x1f,P2|=y,P2&=0x1f;
typedef unsigned char u8;
unsigned char Seg_Table[]={
0xc0,					//共阳数码管
0xf9,
0xa4,
0xb0,
0x99,
0x92,
0x82,
0xf8,
0x80,
0x90,
0x7f
};
float wendu=0;
float real_wendu=0;

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

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}
//数码管显示函数
void showbit(u8 pos,dat,dot)  //pos位选,dat要显示的数字,dot表示有无小数点
{
	outputp0(0xc0,0x01<<pos);   //位选
	outputp0(0xe0,Seg_Table[dat]+0x80*dot);  //段选
	Delay1ms();   //延时
	outputp0(0xc0,0xff);
	outputp0(0xe0,0xff);  //消影
}
//测试函数
void show()
{
	u8 show_pos=0,dot=0;
	wendu=rd_temper();
	if(wendu<0)     
		wendu=-wendu;
	real_wendu=wendu*10000;   //显示四位小数,为了便于提取每一位将其乘以10000
	for(show_pos=0;show_pos<7;show_pos++)
	{
		if(show_pos==2)    //显示格式0xx.xxxx,故第二位数码管要显示小数点
			dot=1;
		else
			dot=0;
		showbit(show_pos,(long int)(real_wendu/pow(10,6-show_pos))%10,dot);  //将每一位数据取出并发送给数码管显示
	}
}

void main()
{
	outputp0(0x80,0xff);
	outputp0(0xa0,0x00);
	rd_temper();    
	while(1)
	{
		show();
	}
	
}

注意:上述程序只测量了温度,并未对温度作出上下限的警报,请读者自行思考如何实现温度报警。

四、测试现象

  下载程序后,数码管正常显示测量温度。


总结

  One-wire作为极其重要的通信方式,掌握它的原理和编程是十分有必要的。
  除One-wire通信方式外,还有IIC通信和SPI通信,具体见IIC通信与EEPROM的应用DS1302原理和代码51单片机DS1302可调时钟
  有任何问题和补充,欢迎私信或评论区交流。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值