先了解一些DS18B20的特性:
1.独特的单线接口仅需一个端口引脚进行通讯
2.每个器件有唯一的64位的序列号存在内部存储器中(一个总线上有多个器件时候可以用来区分)
3.供电范围在3.0V ~ 5.5V
4.测温范围在-55 ~ +125 °C
5.温度的分辨率为9到12位,可以被用户选择。
6.12位(分辨率最高情况)的情况下需要最大750ms去转化温度
7.告警搜索命令(只是一个命令。。,别害怕)识别并标记超过程序所限定的温度
测温操作:
温度传感器的精度可以由用户编程改变分别为9,10,11,12位,以0.5°C,0.25°C,0.125°C和0.0625°C增量递增。
上电后,默认为12位的精度。在设置为开始读取温度后,所产生的温度数据以两个字节的形式被存储在高数暂停器的温度寄存器中。
现在看一下温度寄存器格式:
温度和数据的关系:
数据到温度的计算方法就是如上所示。至于格式中的S代表的是正或负(反码)。
操作DS18B20的执行顺序
第一步 初始化
第二步 ROM操作指令
第三步 DS18B20功能指令
初始化就是单片机总线控制器发出复位脉冲,由器件回复一个存在脉冲。存在脉冲则告诉控制器该器件存在且已经准备好!
ROM指令(含义自己感觉出来的,多多请教):
1.SEARCH ROM [F0H] 寻找ROM,它用在多个器件时候进行得到每一个器件的ROM序列。
2.SKIP ROM [CCH] 跳过ROM寻找,很明显可以跳过寻找,又可以正确的操作器件?那就是在只有一个器件挂接的情况下咯。
3.READ ROM [33H] 如果只有一个器件,并且要得到它的序列号,则可以使用此指令而不是 SEARCH ROM
4.MATCH ROM [55H] 在多个器件时候,要操作哪个器件需要进行序列号匹配。如果单器件则不用。
5. ALARM SEARCH [ECH] 警报搜索,在对器件设置了警报之后(最高温度和最低温度),那么如果温度不符合所要求区间则会置一个标志,可进行搜索查询。
功能指令:(接下去会给出暂存器图)
1.CONVERT T [44H] 开始转换温度,存储在高速暂存中。
2.WRITE SCRATCHPAD [4EH] 写暂存器 先TH 再TL 最后配置寄存器
3.READ SCRATCHPAD [BEH] 读暂存器,从0字节开始读到最后一个字节,可有复位命令终止读取。
4.COPY SCRATCHPAD [48H] 把TH TL 配置寄存器 拷贝到EEPROM
5.RECALL SCRATCHPAD [B8H] 从EEPROM 转存到 TH TL 配置寄存器
6.READ POWER SUPPLY 读取电源模式
暂存器图:
读取序列号格式
每只DS18B20都有一个唯一存储在ROM的64位编码。最前8位编码为28H 接着48位是一个唯一的序列号 最后8位是前面56位的CRC编码。
接下来这个程序运行在STC89C52上, 晶振为11.0592
(由于时间紧迫,暂时还没有报警功能,只有读取序列号 和 读取温度 ,之后实现了再补上)
(最近一会在准备英语六级。。。哎~~~~)
#include<reg52.h>
#include<stdlib.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit DQ = P2^2;//和DS18B20通讯的引脚
sbit LED1 = P1^0;
//读取序列号
unsigned char data RomCode[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char crc; //DS18B20 CRC校验
void delayms(uint ms)
{
uint i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 110; j++);
}
void delayus(uint us)
{
uint i;
for(i = 0; i < us; i++);
}
void DS18B20_WriteByte(uchar dat)
{
uchar i;
for(i = 0; i < 8; i++)
{
DQ = 0;
_nop_();
_nop_();
DQ = dat & 0x01;
delayus(6);//94us
DQ = 1;
dat>>=1;
}
}
uchar DS18B20_ReadByte()
{
uchar i, value = 0;
for(i = 0; i < 8; i++)
{
DQ = 0;
value >>= 1;
DQ = 1;
_nop_();_nop_();_nop_();
if(DQ)
{
value |= 0x80;
}
delayus(5); //60us
}
return value;
}
void DS18B20_Init()
{
uchar state = 1;
DQ = 1;
_nop_();
_nop_();
DQ = 0;
delayus(45); //600us
DQ = 1;
delayus(3); //55 us
state = DQ; //返回0:有响应 返回1:没有响应
delayms(1); //最小480us
LED1 = state;
}
void UART_WriteByte(uchar dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
void UART_Init()
{
TMOD = 0x20;
TL1 = 0xfd;
TH1 = 0xfd;
TR1 = 1;
SM0 = 0;
SM1 = 1;
// REN = 1;
// ES = 1;
EA = 1;
}
uchar CRC8()
{
uchar i,x; uchar crcbuff;
crc=0;
for(x = 0; x <8; x++)
{
crcbuff=RomCode[x];
for(i = 0; i < 8; i++)
{
if(((crc ^ crcbuff)&0x01)==0)
crc >>= 1;
else
{
crc ^= 0x18; //CRC=X8+X5+X4+1
crc >>= 1;
crc |= 0x80;
}
crcbuff >>= 1;
}
}
return crc;
}
void main()
{
unsigned short temperature;
uchar j;
float temp;
UART_Init();
DS18B20_Init();
DS18B20_WriteByte(0x33); // 读序列码的操作
for (j = 0; j < 8; j++)
{
RomCode[j] = DS18B20_ReadByte();
}
CRC8();
if(crc == 0) //CRC效验正确
{
for (j = 0; j < 8; j++)
{
UART_WriteByte(RomCode[j]);
}
}
while(1)
{
DS18B20_Init();
DS18B20_WriteByte(0xcc); //跳过ROM检测
DS18B20_WriteByte(0x44); //开始进行温度转换
delayms(1000);
DS18B20_Init();
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0xbe);
temperature = DS18B20_ReadByte();
temperature |= (unsigned short)(DS18B20_ReadByte()<<8);
temperature &= 0x0fff;
temp = temperature * 0.0625;
temperature = temp * 10 + 0.5;
UART_WriteByte((uchar)(temperature>>8));
UART_WriteByte((uchar)(temperature&0xff));
}
while(1);
}
之所以现在会来写博客,
一个原因是,对于过去所学习的东西,将来不一定会用到,或许将来就算用到,也许忘记了,那么可以过来在浏览浏览。
另外一个原因,也许有朋友们一样在被困扰,如果可以帮到大家也挺好的。
马上要大四啦!!!!