#include <STC15F2K60S2.H>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define MAXNUM 4
sbit DS = P4^5;
union{ //定义共用体temp用于存放从DS18B20读入的数据,Keil C51采用大端格式,c[1]是高地址.
uchar c[2]; //其中存放读取温度数值的低字节;c[0]是低地址,其中存放读取温度数值的高字节.
uint x; //这样根据大端格式的要求,即数据的高字节存储在低地址中,数据的低字节存放在高地址中,
}temp; //x便刚好是读出的温度数值.
uchar num=0; //num记录当前单总线上DS18B20的个数
uchar z=0;
uchar idata RomID_temp[8]; //匹配DS18B20时临时记录要匹配DS18B20的序列号
uchar idata ID[4][8]={0}; //用于记录各DS18B20的ROM序列号
uchar idata flag; //温度的正负号标志,为1表示温度值为负值,为0表示温度值为正值
uint cc,xs; //变量cc中保存温度值整数部分,xs保存温度值小数部分的第一位
//////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void Delay900us() //@12.000MHz
{
unsigned char i, j;
i = 11;
j = 126;
do
{
while (--j);
} while (--i);
}
void Delay30us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 87;
while (--i);
}
void Delay9us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 24;
while (--i);
}
void Delay65us() //@12.000MHz
{
unsigned char i, j;
i = 1;
j = 191;
do
{
while (--j);
} while (--i);
}
void Delay6us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 15;
while (--i);
}
void Delay50us() //@12.000MHz
{
unsigned char i, j;
i = 1;
j = 146;
do
{
while (--j);
} while (--i);
}
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 23;
j = 205;
k = 120;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10ms() //@12.000MHz
{
unsigned char i, j;
i = 117;
j = 184;
do
{
while (--j);
} while (--i);
}
///********************* 单总线写1字节函数 ***********************/
//void WriteDS18B20(uchar value) //--- 写DS18B20命令函数 ---
//{
// write_byte(value);
//}
//void ReadDS18B20(void) //--- 读DS18B20存储器里的数据函数 ---
//{
// //Buffer[1]=read_byte(); //读低字节
// //Buffer[0]=read_byte(); //读高字节
//}
//////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
/********************* DS18B20复位函数 ***********************/
uchar DS_init(void){
unsigned char presence =0;
DS=0; Delay900us(); //根据DS18B20的复位时序.先把总线拉低555us
DS=1; Delay30us(); //再释放总线,65us后读取DS18B20发出的信号
presence=DS; //如果复位成功,则presence的值为0;否则为1
return (presence); //返回0则初始化成功,否则失败
}
/********************* 单总线读1字节函数 ***********************/
uchar read_byte(void){
uchar i,j,dat=0;
for(i=0;i<8;i++){ //作8个循环,读出的8位组成一个字节
DS=0; Delay6us(); //先将总线拉低us,
DS=1; Delay9us(); //再释放总线,产生读起始信号,延迟9us后读取总线上DS18B20发出的值
j=DS; Delay65us(); //一位读完后,延迟65us后读下一位
dat=(j<<7)|(dat>>1); //读出的数据最低位在一个字节的最低位,这样刚好一个字节在DAT里
}
return(dat);
}
/********************* 单总线读2位函数 ***********************/
uchar read_2bit(void){
uchar i=0,j=0;
DS=0; Delay6us(); //先将总线拉低6us,
DS=1; Delay9us(); //再释放总线,产生读起始信号,延迟9us后读取总线上DS18B20发出的值
j=DS; Delay65us(); //一位读完后,延迟65us后读下一位
DS=0; Delay6us(); //先将总线拉低6us,
DS=1; Delay9us(); //再释放总线,产生读起始信号,延迟9us后读取总线上DS18B20发出的值
i=DS; Delay65us(); //一位读完后,延迟65us后读下一位
i=j*2+i; //将读出的两位放到变量i中,其中第一个读出的位处于i的第1位;而第二个读出的位处于i的第0位
return(i);
}
/********************* 单总线写1字节函数 ***********************/
void write_byte(uchar dat){
uchar i;
Delay900us();
for(i=0;i<8;i++){
DS = 0;
Delay6us(); //作8个循环,写入的8位组成一个字节
DS = dat&0x01; //向总线上放入要写的值
Delay50us(); //延迟105us,以使DS18B20能采样到要写入的值
DS = 1; //释放总线,准备写入下一位
Delay6us();
dat>>=1; //将要写的下一位移到dat的最低位
}
}
/********************* 单总线写1位函数 ***********************/
void write_bit(bit dat){
DS=0; //先将总线拉低
Delay6us();
DS=dat; //向总线上放入要写的值
Delay50us(); //延迟105us,以使DS18B20能采样到要写入的值
DS = 1; //释放总线
}
/********************* 搜索ROM序列号函数 ***********************/
uchar search_rom(void){
uchar k,l=0,chongtuwei,m,n,a;
uchar _00web[MAXNUM]={0};
do {
while(DS_init()); //复位所有DS18B20
write_byte(0xf0); //单片机发布搜索命令
for(m=0;m<8;m++) {
uchar s=0; //s用来记录本次循环得到的1个字节(8位)序列号
for(n=0;n<8;n++) {
k=read_2bit(); //读第m*8+n位的原码和反码,保存在k中
k=k&0x03; //屏蔽掉k中其它位的干扰,为下一步判断作准备
s>>=1; //s右移一位,即把上一次循环得到的位值右移一位,
//这样执行完一次n为变量的循环,便可得到一个字节的ROM号
if(k==0x01){ //k为01,表明读到的数据为0,即所有器件在这一位都为0,所以向总线上写0
write_bit(0); //同时对s的值不进行操作,即这位的序列号记为0
}
else if(k==0x02){ //k为02,表明读到的数据为1,即所有器件在这一位都为1,所以向总线上写1
s=s|0x80; //记录下此位的值,即s的最高位置1
write_bit(1);
}
else if(k==0x00){
chongtuwei=m*8+n+1; //记录下这个冲突位发生的位置;之所以加1是为了让_00web数组中的第一位保持0不变,
//便于判断搜索循环是否结束;
if(chongtuwei>_00web[l]){//如果冲突位比标志00位的位高,即发现了新的冲突位,那么这位写0
write_bit (0);
_00web[++l]=chongtuwei; //依次记录位比冲突标志位高的冲突位在_00web数组中
}
else if(chongtuwei<_00web[l]){ //如果冲突位比标志00位的位低,那么把ID中这位所在的字节右移n位,
//从而得到这位先前已经写过的值,如果为0,说明这位先前写的是0,那么继续写0,
// 如果这位先前写的是1,那么继续写1
a=(ID[num-1][m]>>n)&0x01;
s=s|(a<<7); //记录下此位的值
write_bit(a);
}
else if(chongtuwei==_00web[l]) {//如果冲突位就是标志00位,那么s的最高位置1,即这位记为1,同时向总线上写1;
//之所以不写0,是因为前面已经写过0,再写0,就得不到遍历的效果.
s=s|0x80;
write_bit (1);
l=l-1; //改变标志00位的位置,即向前推一个00位,并且是往低位方向推
}
}
else if(k==0x03) //k为03,表明总线上没有DS18B20,函数结束,同时返回零值
{return(0);}
}
ID[num][m]=s;
}
num++; //DS18B20的个数加1
}while((_00web[l]!=0)&&(num<MAXNUM));//如果冲突位记录数组已经前推到0值或是DS18B20的数目已经超过最大允许数目,
//就退出循环
return(1); //搜索完毕,返回1值
}
/********************* 读取温度函数 ***********************/
void Read_Temperature_rom(void){
uchar i;
while(DS_init()); //复位DS18B20
write_byte(0x55); //匹配ROM
for(i=0;i<8;i++) //发出64位ROM编码
write_byte(RomID_temp[i]);
write_byte(0x44); //开始测量温度
Delay500ms();
while(DS_init()); //复位DS18B20
write_byte(0x55); //匹配ROM
for(i=0;i<8;i++) //发出64位ROM编码
write_byte(RomID_temp[i]);
write_byte(0xBE); //发读温度命令
temp.c[1]=read_byte(); //读低字节
temp.c[0]=read_byte(); //读高字节
}
/*
44H--温度转换
BEH--都暂存器
4EH--写暂存器
48H--复制暂存器
B8H--重读E2RAM
B4H--读电源
33H--读出ROM
55H--匹配ROM
F0H--搜索ROM
CCH--跳过ROM
ECH--警