DS18B20是一种常用的温度传感器,可以实现多点网络式测量,这里简单介绍单个ds18b20的使用。
DS18B20看起来像一个三极管,有三个引脚,1:地,2:数据端,3:电源,DS18B20的通信方式有点特别,仅靠一根线进行通信,而且多个DS18B20也是连在一个线上的,所以通信协议仅靠高低电平实现,而且速度较慢,因为传输数据较少,所以时间还是可以忍受。
简单起见,这里介绍单个DS18B20的使用方法,忽略地址匹配等方法,下面结合程序,说明一下主流程:
unsigned int ds18b20_read_temperature(void)
{
unsigned int temperature;
ds18b20_init(); //初始化(复位)
ds18b20_write_byte(0xCC); //发送命令,跳过ROM
ds18b20_write_byte(0x44); //温度转换
delayms(1000); //给必要的转换时间
ds18b20_init(); //DS1302 复位
ds18b20_write_byte(0xCC); //跳过ROM
ds18b20_write_byte(0xbe); //读取RAM
temperature = ds18b20_read_byte(); //读低八位,LS Byte, RAM0
temperature |= ds18b20_read_byte() << 8; //读高八位,MS Byte, RAM1
return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}
很简单,启动温度转换,等待,读取结果。
下面介绍DS18B20的单线通信方式:
这个要细细研究手册的时序图,才能写好程序。
1.DS18B20的复位:
总线先给一个480us的低电平,等待15-60us,DS18B20会有一个60-240us的低电平响应,注意用时候可能因为软件或硬件的问题,并没有使DS18B20成功初始化,这样程序会进入无限等待的死循环里,这里为了防止死循环的发生,使用最大延时限制,一旦延时到且初始化未成功,就重新初始化。
程序如下:
void ds18b20_init(void)
{
int i;
again: //这里为了方便,用了一个C语言的禁忌指令:goto label
TD = 1; //T 为输出状态
TO = 0; //输出低电平
delayus(500); //延迟480~960 us
TO = 1; //释放总线
TD = 0; //DQ 位输状入态
#define MAX 480 //定义一个最大延时数,防止死循环
for(i=MAX;i>0;i--)
{
if(!ti) break;//检测到低电平,跳到下一步
}
if(i == 0) goto again;//最大延时到,重新检测
for(i=MAX;i>0;i--)
{
if(TI) break;//检测到高电平,跳到下一步
}
if(i == 0) goto again;//最大延时到,重新检测
}
2.向DS18B20写一位:
如果写0,则给60~120us的低电平;如果写1,先给至少1us的低电平,然后给高电平,直至60us。
void write_bit(char b)
{
TD = 1;
TO = 0;//拉低总线
delayus(2); //至少1us
TO = !!b; // !!是为了把非零数转换 为1
delayus(58); //保证60us
TO = 1; //释放总线
}
3.读DS18B20一位:
先给至少1us的低电平,然后在15us内读取,高为1,低为0,在等待,直至60us。
char read_bit(void)
{
char b;
TD = 1;//置位输出
TO = 0;//拉低总线,至少1us
delayus(2);
TO = 1;
TD = 0;//置位输入
delayus(4);//必须在15us内读取
b = TI;
delayus(54);
TD = 1;//置位输出
TO = 1;//释放总线
return b;
}
下面是完整的程序:
编译器:IAR
单片机:ATmega32 或 16
#include "main.h"
//定义 T 引脚
#define TD DDRC_Bit7
#define TO PORTC_Bit7
#define TI PINC_Bit7
//根据时序图,先给至少1us的低电平,
//写1则拉高 直至60us
//写0则继续保持 直至60us
void write_bit(char b)
{
TD = 1;
TO = 0;//拉低总线
delayus(2); //至少1us
TO = !!b; // !!是为了把非零数转换 为1
delayus(58); //保证60us
TO = 1; //释放总线
}
void ds18b20_write_byte(char val)
{
char i;
for(i=0;i<8;i++)
{
write_bit( val&(1<
}
}
//根据时序图,先给至少1us的低电平,
//然后在15us内读取
//高为1 直至60us
//低为0 直至60us
char read_bit(void)
{
char b;
TD = 1;//置位输出
TO = 0;//拉低总线,至少1us
delayus(2);
TO = 1;
TD = 0;//置位输入
delayus(4);//必须在15us内读取
b = TI;
delayus(54);
TD = 1;//置位输出
TO = 1;//释放总线
return b;
}
char ds18b20_read_byte(void)
{
char i;
char value=0; //读出温度
for(i=0;i<8;i++)
{
value |= read_bit() << i;
}
return(value);
}
//根据时序图,先给一个480~960us的低电平,然后释放总线等待DS18B20响应(一个低脉冲)
//为了稳定性,使用延时循环以防止了死循环的发生
void ds18b20_init(void)
{
int i;
again: //这里为了方便,用了一个C语言的禁忌指令:goto label
TD = 1; //T 为输出状态
TO = 0; //输出低电平
delayus(500); //延迟480~960 us
TO = 1; //释放总线
TD = 0; //DQ 位输状入态
#define MAX 480 //定义一个最大延时数,防止死循环
for(i=MAX;i>0;i--)
{
if(!TI) break;//检测到低电平,跳到下一步
}
if(i == 0) goto again;//最大延时到,重新检测
for(i=MAX;i>0;i--)
{
if(TI) break;//检测到高电平,跳到下一步
}
if(i == 0) goto again;//最大延时到,重新检测
}
unsigned int ds18b20_read_temperature(void)
{
unsigned int temperature;
ds18b20_init();
ds18b20_write_byte(0xCC); //跳过ROM
ds18b20_write_byte(0x44); //温度转换
delayms(1000);//给必要的转换时间
ds18b20_init(); //DS1302 复位
ds18b20_write_byte(0xCC); //跳过ROM
ds18b20_write_byte(0xbe); //读取RAM
temperature = ds18b20_read_byte(); //读低八位,LS Byte, RAM0
temperature |= ds18b20_read_byte() << 8; //读高八位,MS Byte, RAM1
return temperature*0.0625; //0.0625=xx, 0.625=xx.x, 6.25=xx.xx
}
/*
int main( void )
{
unsigned int Temp;
while(1)
{
Temp = ds18b20_read_temperature(); //调用读取温度函数
// delayus(100); //稍微延迟
}
}
*/
|