同步快速读取8支DS18B20温度的方法
------李杰<?XML:NAMESPACE PREFIX = O />
DS18B20在测温领域,应用非常广泛。当系统要测量多支DS18B20的温度时,如何快速测量,成为程序设计的关键。
DS18B20内部均有一个独立的序列号(ROMCODE),单片机通过ROMCODE可以对一条总线上的多支DS18B20进行控制,读取它们的温度。但要完成这个操作,软件设计异常复杂,同时存在一个致命的缺点:速度太慢!对于一些实时性要求高的测稳场合,根本无法使用。现在介绍一种采用单片机的并口,同步快速读取8支DS18B20的方法。
一、设计原理
电路见图一,8支DS18B20全部与单片机(Lpc932A1)的P0口连接。由排阻RB1(2K)提供上拉,采用1mm的导线,控制距离可达200米。减小RB1的阻值,还可进一步提高控制距离。
对于一支DS18B20,我们要输出或输入各类命令数据时,采用“位寻址”
如:
MOV D0,C ;
MOV C,D0 ;
SETB C ;
而对于8支DS18B20,如果还采用“位寻址”的方法,程序就非常复杂!但我们只需将“位寻址”扩展成“字节寻址”如:
MOV P0,#0FFH
MOV A, P0
即可一次输出或输入8个位数据,从而达到同步读取的目的。详细的程序见下(只给出 读、写子程序)。
八支DS18B20的控制程序
以下程序全部在KEIL C51下编译!
//---------------------------------------------------------------------------------------------------------
//12MHz 下,_NOP_1uS_()执行时间0.1667us LPC932
//---------------------------------------------------------------------------------------------------------
#define NOP_1uS _nop_();_nop_();_nop_();_nop_();_nop_();_nop_()
//**************************************
#define Skip 0xcc //跳过命令
#define Convert 0x44 //转化命令
#define RdDs18b20 0xbe //读温度命令
//********************************************************************
#define DQ P0 //P0口用8个DS18B20
//-------------------------------------------------------------------------------------------------------
//功能:10us 级别延时
//-------------------------------------------------------------------------------------------------------
void Delay10us(unsigned char n){
while(n--) {
NOP_1uS;NOP_1uS;NOP_1uS;
NOP_1uS;NOP_1uS;NOP_1uS;
NOP_1uS;
}
}
//----------------------------------
//功能:总线初始化
//-----------------------------------
bit Init_18B20(void)
{
DQ=0;
Delay10us(50);//延时500us
DQ=0xff;
Delay10us(9);//延时90us
if((DQ & 0x1f) ==0x1f) //0001 1111b=1f
{
return 0; //失败0
}else
{
Delay10us(40);//延时400us
DQ=0xff; //成功!
}
return 1;
}
//-------------------------------------------
//功能:读取18B20 (8个DS18B20)
//入口 *p接收数据的地址指针
//------------------------------------
void Read_18B20(unsigned char *p){
unsigned char i;
for(i=0;i<8;i++) {
DQ=0;
NOP_1uS; //延时1us
DQ=0xff;
NOP_1uS;NOP_1uS;NOP_1uS;
NOP_1uS;NOP_1uS;NOP_1uS; //延时5us
//----------------------------------
*p++=DQ; //并口读入8个位
//----------------------------------
Delay10us(5); //延时40us
DQ=0xff;
}
}
//-----------------------------------
//功能:写18B20
//-----------------------------------
void Write_18B20(unsigned char n)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ=0;
Delay10us(1); //延时13us 左右
DQ= (n&0x01)*0xff;
n=n>>1;
Delay10us(5); //延时50us 以上
DQ=0xff;
}
}
二、 温度合成处理
采用上述方法1次性读取了8支DS18B20的温度数据占用时间不到1秒,但它们在RAM中排列是交叉的,必须用软件合成,才能得到8个的温度值。温度值在Buf中的存放次序(见表一)
表一
Buf[0] | D70 | D60 | D50 | D40 | D30 | D20 | D10 | D00 |
Buf[1] | D71 | D61 | D51 | D41 | D31 | D21 | D11 | D01 |
Buf[2] | D72 | D62 | D52 | D42 | D32 | D22 | D12 | D02 |
Buf[3] | D73 | D63 | D53 | D43 | D33 | D23 | D13 | D03 |
Buf[4] | D74 | D64 | D54 | D44 | D34 | D24 | D14 | D04 |
Buf[5] | D75 | D65 | D55 | D45 | D35 | D25 | D15 | D05 |
Buf[6] | D76 | D66 | D56 | D46 | D36 | D26 | D16 | D06 |
Buf[7] | D77 | D67 | D57 | D47 | D37 | D27 | D17 | D07 |
探头: | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
在8个字节的缓存区中(Buf[0]-Buf[7])中,从D07位开始,纵向依次排列的是8支DS18B20的温度值,此时要设计一个将纵向8位数据转换成横向的数据程序,便可得到温度的数据字节,连续执行2次,便可将DS18B20的高、低字节全部合成标准的温度数据(程序见下)。
#define Ds18b20k 8 //定义8支DS18B20
//------------------------------------------
//数据合并 Buf[0].0,Buf[1].0...=>Dat[0]
//8 个DS18B20合并8个温度
//------------------------------------------
void FormatTemp(unsigned char *pSurce,unsigned char *pTag)
{
code unsigned char CodeMask[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //对应8个DS18B20的位
unsigned char i,j;
for (i=0;i<Ds18b20k;i++)
{
for (j=0;j<8;j++)
{
pTag >>=1;
pTag |=(( pSurce[j] & CodeMask)>0? 1:0)*0x80;
}
}
}
三、结束语
上述的方法,程序设计非常简单,8支DS18B20的读取时间与1支DS18B20的读取时间基本相等,使系统测温非常快速。上述希望使用DS18B20的朋友借鉴!
用户1584993 2010-12-21 11:58
用户1021297 2010-12-21 09:01
用户944075 2010-12-20 17:49
用户1433065 2010-12-20 12:05
用户518141 2008-11-14 20:47