备赛目录
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里,
1-ware单总线是Maxim全资子公司Dallas的一项专有技术。与目前多数标准串行数据通信方式,如SPI / I2C不同,它采用单根信号线,既传输时钟,又传输数据,而且数据传输是双向的。因此对时序要求非常严格,它具有节省I/O口线资源、结构简单、成本低廉、便于总线扩展和维护等诸多优点。
1-ware单总线适用于单个主机系统,能够控制一个或多个从机设备。当只有一个从机位于总线上时,系统可按照单节点系统操作;而当多个从机位于总线上时,则系统按照多节点系统操作。
单总线命令序列如下:
第一步:初始化
第二步:ROM命令(跟随需要交换的数据)
第三步:功能命令(跟随需要交换的数据)
每次访问单总线器件,必须严格遵守这个命令序列,如果出现序列混乱,则单总线器件不会响应主机。但是,这个准则对于搜索ROM命令和报警搜索命令例外,在执行两者中任何一条命令之后,主机不能执行其后的功能命令,必须返回至第一步。
初始化是在干嘛?
建立主机和从机设备的通讯,即主机要搜索到从机,从机要响应主机
与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;
}
写入什么?怎么写入?
有两种类型的写时间槽:“写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;
}
命令写入后,就可以开始读取温度了
这里是如何读取温度的操作时序与命令
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;
}
第一步:初始化
第二步: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;
}
如果觉得内容有用,点个赞么
备赛目录