[转]1wire总线的应用-DS18B20温度采集工芯片的应用
/*
作者:李金浩
QQ:67260745
E-mail:LTSoft918@163.com
---------------------------
DS18b20默认设置为12位.乘0.0625就可以得到实际的温度
开发环境:6MHZ,SST89C58 in keil C 7.01 Mon,平台:恒坚HJ51/AVR开发系统
断开DS18b20的VCC引脚,温度则为85℃可用来测试是否正常
*/
#define DSDIP P3_2//P3^2作为1线采集端口
unsigned char c1,c10,c100,cDec,mark;//定义全局变量分别返回个,十,百,符号位
//0~9,如果带小数点,则高位加8就可以了,也就是8*16
//LED中的数据为共阳极显示
code unsigned char LedChar[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,
0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
//LED共阴极显示
/*const char LedChar[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0xbF,0x86,0xdB,0xcF,0xe6,0xeD,0xfD,0x87,0xfF,0xeF};*/
//1~8号LED数据管地址号
code unsigned char Led[]={0x01,0x02,0x04,0x08,
0x10,0x20,0x40,0x80};
void display(unsigned char showbit,LedNum);
void ShowNum(unsigned char numbit,num1,num10,num100,mark);
//---------------------------------------------
//6MHZ情况下
/*
delay(1);//60uS
delay(2);//106uS
delay(11);//526uS
void delay8us(void);
void delay34us(void);
//void delay14us(void);
*/
//------------------------------------------------
//------------------------------------------------
void delay(unsigned char times)
{
//不精确延时,误差很大
unsigned char i;
for(;times>0;times--)
for(i=0;i<255;i--);
}
//------------------------------------------------
//------------------------------------------------
void delay34us(void)
{
unsigned char i;
for(i=0;i<200;i--);
}
/*------------------------------------------------
ds18b20功能实现部分
通过c1,c10,c100,cDec,mark;全局变量返回个,十,百,符号位
unsigned char RestDS(void);//复位
unsigned char ReadDS(void);//读取1个字节
void writeDS(unsigned char val)//写入1个字节
float ReadTemp(void)//读取温度
------------------------------------------------*/
/*-------------------------
始化复位
--------------------------*/
unsigned char RestDS(void)
{
unsigned char isexist;
DSDIP=0;
delay(11);//526uS
DSDIP=1;
//等待15~60us
delay34us();
isexist=DSDIP;//取得ds18b20是否存在
delay(2);//106uS
return(isexist);
}
/*-------------------------------
Read a byte
---------------------------------*/
unsigned char ReadDS(void)
{
unsigned char i,t,value=0;
for(i=8;i>0;i--)
{
value>>=1;
DSDIP=0;
t++;//2us
DSDIP=1;
t++;//2us
t++;//2us
if(DSDIP) value|=0x80;
t++;//2us;//读取时间间隙,在于1us
}
return(value);
}
/*-----------------------------
Write a byte
-------------------------------*/
void writeDS(unsigned char val)
{
unsigned char i;
for(i=8;i>0;i--)
{
DSDIP=0;
DSDIP=val&0x01;//每次写1位,通过val右移得到
delay34us();//延时34us(15~60us采样时间)
DSDIP=1;//释放总线
val>>=1;//计算的同时会产生一个2us的时间间隙
}
// delay8us();//2次写的时间间隙要大于1us
}
/*---------------------------------
Read ds18b20 ID
----------------------------------*/
unsigned char ReadID(void)
{
unsigned char ID;
RestDS();//复位ds18b20
writeDS(0x33);//读ROM:0x33指令
ID=ReadDS();
return(ID);
}
/*----------------------------------------------------
ds18b20读取温度
通过c1,c10,c100,cDec,mark;全局变量返回个,十,百,符号位
函数本身返回一个float类型的dTemp温度值
----------------------------------------------------*/
float ReadTemp(void)
{
unsigned int temp;
unsigned char lowbit,highbit;
float dTemp=0;
RestDS();//复位ds18b20
writeDS(0xcc);//跳过ROM
writeDS(0x44);//发出温度转换命令
//------
RestDS();
writeDS(0xcc);//跳过ROM
writeDS(0xBE);//读暂存存贮器
lowbit=ReadDS();//取得低8位
highbit=ReadDS();//取得高8位
temp=highbit<<8;
temp=temp+lowbit;//合成16位的二进制数
/*
判断前5位,是否为:
1:负
0:正
*/
mark=1;//1:表示为正温度 0:负温度(mark为全局变量)
if((highbit>>3)!=0)
{
//为负则求反+1
temp=~temp+1;
mark=0;
}
//---------
dTemp=temp*0.0625;//得到带小数点的实际温度
temp=dTemp;//temp为int型,dTemp为float型,强制去掉小数
/*全局变量分别返回个,十,百,符号位*/
c100=temp/100;//得到百位
c10=(temp-c100*100)/10;//得到十位
c1=temp-c100*100-c10*10;//得到个位
cDec=(dTemp-temp)*10;//得到小数位
return(dTemp);
}
//-------------------main()-----------------------
void main(void)
{
unsigned char dsID;
while (1)
{
dsID=ReadID();
ReadTemp();//取得ds18b20温度
ShowNum(mark,c100,c10,c1,cDec);//显示采集到的温度
}
}
/*-----------------------------------------------------------------
显示函数
showmark,num100,num10,num1,numDec
符号位 百位 十位 个位 小数位
-----------------------------------------------------------------*/
void ShowNum(unsigned char showmark,num100,num10,num1,numDec)
{
unsigned char DT=50;
display(1,numDec);//小数位
delay(DT);
display(2,num1+10);//个位
delay(DT);
display(3,num10);//十位
delay(DT);
display(4,num100);//百位
delay(DT);
//只有当为负温度时才显示符号位
if(showmark==0)
{
display(5,0xBF);//符号位(负)
delay(DT);
}
}
/*
单位输出
showbit:选择输出的LED管子
LedNum:要输出的数据
*/
void display(unsigned char showbit,LedNum)
{
P2_7=0;//P2_7不知道干什么用,恒坚没有告诉我,根据实际情况估计是片选信号
P0=Led[showbit-1]; //给P2_6一个脉冲,选择在哪个LED上显示
P2_6=1;
P2_6=0;
//-------------
P0=LedChar[LedNum];//给P2_5一个脉冲,将要显示的数据显示缓冲区中
P2_5=1;
P2_5=0;
}