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); //稍微延迟 } }
*/
|