作者:jjmgj 来源:本站
#include<reg52.h>
#include<absacc.h>
#include <string.h>
#include <stdio.h>
#include<math.h>
///////////////////////
/*自定义结构变量说明 */
#define uint unsigned int
#define uchar unsigned char
//sbit DQ=P1^0;//DS2450
sbit lcd_en=P2^7;//液晶片选控制信号线
/*系统数据线和变量定义*/
sbit DQ=P1^1; //DS18b20通信线
uchar tplsb,tpmsb; // 温度值低位、高位字节 缓存区
bit fhao ;//保存温度是正数还是负数
uchar TMP[5]; //四个温度数据的缓存区
uchar code serial_number[4][8]={0x28,0x08,0x85,0x11,0x01,0x00,0x00,0xba, //一号18b20ROM号
0x28,0xbe,0x86,0xe9,0x00,0x00,0x00,0x87, //二号
0x28,0x11,0xc4,0xe9,0x00,0x00,0x00,0x95,//三号
0x28,0xf5,0x12,0x0c,0x01,0x00,0x00,0xc1,//四号
}; //四个18b20的八字节序列号数据
/*************************/
/* 延时t毫秒子程序 */
/* 延迟 tms 在11。0592M晶正时候
/**************************/
void delay(uint t)
{
uchar i;//这里不可以改为uint
while(t--)
{
/* 对于11.0592M时钟,约延时1ms */
for (i=0;i<123;i++)
;
}//
}
//****************************************/
//功能:复位单总线并且检测应答脉冲/
//有响应则返回0,否则进入死循环
//****************************************/
bit TxReset1(void)
{
bit presence; //检测存在脉冲位缓寸位
uchar i; //延迟循环变量,这里也不可以改为uint 类型
DQ = 0; //数据位
/* 拉低约502us */
i = 250; //keilc里通过定时器测定 502us
while (i>0) i--;
DQ = 1; // 产生上升沿释放总线
while(DQ); //检测器件拉低信号,如果没有拉低则等待,拉低则往下走
presence=DQ; //读取总线响应低电平
i=200; //主机接受存在脉冲保证480us
while (i>0) i--; //keil c 的定时器测得约为482us
return (presence);
}
/**********************************/
/* 作用:返回单总线上读取的一位数据/
/**********************************/
bit RdBit(void)
{
uchar i;
bit b;
DQ = 0; //拉低总线开始读时隙
i++; // medwin li 2us
DQ=1; //主机释放总线后, 单线器件立即输出数据
i++;i++; // 读时隙下降沿后15us内,DS18B20输出数据才是有效的,过后就没有效果了
//上面这两句i++ 没有也可以,测试通过 ,有这两句是给单线器件一个准备间隙
//这两句在 medwin 里延时间 4us
b = DQ; //主机读取总线上数据 ,主机必须在15us内 完成: 大于1 us 的拉低总线(开始时隙)
i = 30; //并且释放总线后(单线器件开始输出数据) 读取单线器件输出的数据
while(i>0) i--;//一个读时隙至少持续60us
//i=30 keil c中约为62us
return (b);
}
/***********************************/
/* 读取数据的一个字节
/*作用:从单总线器件读取一个字节
/*所有的单总线协议操作的命令和
/*控制字都是低位字节在前面的
/** *******************************/
uchar RdByte(void)
{
uchar i,j,b;
b = 0;
for (i=1;i<=8;i++)
{
j = RdBit();
b = (j<<7)|(b>>1); //读取一位存储到b的的最高位,8次后得一字节数据
/*按照上面的原则每次读取一位后放到b的最高位 ,8次后获得一个字节 */
}
return(b);
}
/********************************************/
/*本程序实现空制器向单总线写一个字节*********/
/* 写数据的一个字节,满足写1和写0的时隙要求 */
/********************************************/
void WrByte(uchar b)
{
uchar i;
uchar j;
bit btmp;
for(j=1;j<=8;j++)
{
btmp = b&0x01;
b = b>>1; // 取下一位(由低位向高位)
if (btmp)
{
/* 写1 */
DQ = 0;
i++;i++; // 延时,使得15us以内拉高
DQ = 1;
i =35;
while(i>0) i--; // 整个写1时隙不低于60us
//keil c里72us
}
else
{
/* 写0 */
DQ = 0;
i =35; //keil c 里为72us
while(i>0) i--; // 保持低在60us到120us之间
DQ = 1;
i++;
i++;
}
}
}
/******************/
/* 启动温度转换 */
/*****************/
void convert(void)
{
while(TxReset1()); //检测存在脉冲
delay(1); // 延时 延迟时间也可以的
WrByte(0xcc); // skip rom 命令
WrByte(0x44); // convert T 命令
}
/**********************/
/* 读取温度值 ********/
/*保存于两个全局变量中
/**********************/
void RdTemp(void)
{
while(TxReset1()); //检测存在脉冲
delay(1); // 延时1ms 不延迟时间也测试通过
WrByte(0xcc); // skip rom 命令
WrByte(0xbe); // read scratchpad 命令
tplsb = RdByte(); // 温度值低位字节(其中低4位为二进制的“小数”部分)
tpmsb = RdByte(); // 高位值高位字节(其中高5位为符号位)
}
/*************************************************/
/* 本程序的作用是把从DS18B20读出的两字节的二进制数值
/* 合并为一个字节是十进制数值并且返回合并的结果
/**************************************************/
uchar bian_to_dec(void)
{
uchar temp1,temp2,temp3;
uchar t; //存返回结果的变量
temp1=tplsb ;//温度的低8位数据
temp2=tpmsb; //温度高8位数据
temp3=tpmsb;//温度高8位数据
temp3=temp3>>4;//取得温度的符号位数据
//*********************************
//两个字节数据合并处理
//将两个自字节数据合并为一个字节数据
///********************************
if(temp3==0)//温度为正
{
fhao=0;
t=((temp1>>4)|(temp2<<4));
temp1=(temp1&0x0f);//取得温度数值的小数部分
if(temp1>8)
t=t+1;
}
else
{
fhao=1;//温度为负数
temp1=temp1>>4;
temp2=temp2<<4;
t=temp1|temp2;
t=~t+1;//反码加一为原码
}
return t;
}
////////////////////读取一根线上的四个18B20的温度////////////////////
////
//// 功能: 读取P1.0口上的四个18B20的温度,保存在全局数组TMP中
////
////////////////////////////////////////////////////////////////////
void read_4_18b20()
{
uchar i,j;
while(TxReset1()); //返回1 则继续复位,直到检测到低电平的应答脉冲则向下执行
WrByte(0xcc);//SKIP ROM,不发送ROM命令则要发送跳过ROM命令(0xcc)
WrByte(0x44);//命令单总线上的所有器件开始转换
delay(3); //一般转换要750us,这里等待3ms足够
for(j=0;j<4;j++) //读取转换后的四个温度
{
while(TxReset1()); //返回1 则继续复位,直到检测到低电平的应答脉冲则向下执行
//delay(1);
WrByte(0x55);//ROM匹配
for(i=0;i<8;i++)
WrByte(serial_number[j][i]);//ROM匹配
///注意:发送序列号后,只有匹配的18B20才会对接下来的命令响应
WrByte(0xbe); // read scratchpad 命令
tplsb = RdByte(); // 温度值低位字节(其中低4位为二进制的 小数部分
tpmsb = RdByte(); // 高位值高位字节(其中高5位为符号位)
TMP[j]=bian_to_dec(); //读取第二个18b20的温度
}
}
//主程序调用就可以读到比较准确的温度了。
//这里只是拷贝了一个文件,不过这样可以读取一个或者多个DS18B20的温度了,
我也是刚刚学单总线的,希望高手指导。