当前位置:
文档之家› DS18B20的调试总结和程序
DS18B20的调试总结和程序
DELAY5();
//端口输出
//产生下降沿,至少维持一微秒
//将端口设为输入,等待读取 //在 15US 之Байду номын сангаас读取数据
//延时大概 5US
if(DQ) ch=ch|0x80;
else ch=ch&0x7f;
DELAY9(8);
} return(ch);
//每两个读数据之间间隔要大于 60US //返回读到的数据
初始化时序
初始化时序步骤: 1. 主机将端口设为输出,先发送一个高电平,然后再拉低,维持 480-960US;(推荐 500-600US) 2. 主机将端口设为输入,上拉电阻此时将电平拉高,主机等待 60US-200US;(推荐 100-150US) 3. 主机读取端口数据,低电平则初始化成功;高电平表示初始化失败; 4. 读取数据完毕后,主机等待至少 400US; (推荐 450-500US) 注: 第四步很重要,读取初始化状态后,仍然延时 400US 才可以初始化完毕,否则传感器不能 正常使用; 在这里注意端口需要不停地改变方向;在主机发送时,设为输出,主机接收时,设为输出;
} 以上三段为底层基本函数;DELAY 后面的数字 DELAY1,DELAY5,DELAY9 为延时的微秒时长; DQ 设置为硬件连接的端口,DQ_OUT 为端口方向的设置;
然后就是调用函数了: 当数据线上还有一个 18B20 时,通常步骤如下: 初始化; 跳过 ROM; 温度开始转换命令; 等待温度转换完成;//当使用 18B20 默认的 12 位转换精度,用时 750MS,经检验,一般耗时比理论稍长; 初始化; 跳过 ROM; 读暂存器命令; 将温度数据低八位,高八位依次取出; 初始化;//注:最后仍然要进行初始化 结束; 对应的函数如下:
/****************读取温度命令程序***************************************/
uint TEMP_READ_18B20(){
byte dummy=0; byte TEMH=0,TEML=0; uint TEM_RESULT; dummy=INIT_18B20(); if(dummy==0){
//返回值为 1,表示失败,返回值为 0 表示成功
}
端口写数据时序
1. 主机将电平拉高,稍微延时(推荐值:2US),然后拉低电平,产生一个下降沿,表示写数据开始;低电平维持 至少 1US;(此时推荐 2US)
2. 此时,将要写的 1 或 0 放在数据线上;(从写数据第一步开始到现在,整个过程在 15US 之内完成; 3. 然后主机延时等待至少 50US;(推荐 60US) 4. 主机最后将电平拉高; 5. 每写两位数据之间的间隔要大于 1US;
DELAY9(70);
DQ_OUT=0;
//设置为输入,设为输入 15 到 60US
DELAY9(6);
//等待 18B20 响应,如果为低电平表示初始化成功,维持 60 到 240
//微秒
DQ_RETURN=DQ;
DELAY9(70);
//读完数据后,仍然延时,至少 480US
return(DQ_RETURN);
//将数据按位取出,从 LSB 到 MSB 依次送出
//电平维持 40US 以上,18B20 将在此时将数取出
} DQ=1;
}
//最后将电平重新拉高
读数据时序
1. 主机将电平拉高,稍微延时(推荐 2US),然后将电平拉低,产生一个下降沿,表示读数据;这个低电平至少 维持 1US,此处推荐 2US;
TEM_RESULT=(TEML>>3)+(TEMH<<5); //分辨率为 0.5° 舍弃后面三位数据,并且只有 11 位是温度值,高八位中的前五位是符号位;
读取为 1 时温度为负;读取为 0 时,温度为正;
WRITE_18B20(0x44); //温度开始转换命令
}
return(dummy);
//返回 0 表示成功初始化,开始转换温度
}
注:在开始转换命令和读取温度之间,若 18B20 忙于转换温度,电平为低电位; 转换完毕将电平拉高;若不想用 DELAY 等待温度转换,可读取 DQ 值,为 1 则表示转换完毕,可以开始读 取数据了;
在单片机的使用中,不要用浮点数,全部用整数代替,在数据进行移位作乘法时,一定要注意数据有没有越界, 算出来的数很容易出现错误,并且在出现浮点数时,可以将数据放大到一定的精度,然后在显示时,将小数点 移到对应的位置即可; 在数据做乘法容易越界时,一般将其赋给一个字节多的整数,作为中间变量运算,在确保数据不会越界后,再 将其赋给最后结果;
/********************温度开始转换命令程序*******************************/
byte TEMP_DETECT_18B20(){
byte dummy=2; dummy=INIT_18B20(); if(dummy==0){
//初始化
WRITE_18B20(0XCC); //跳过 ROM,不读地址,直接通讯
/***************从 18B20 取出字符*******************************/ byte READ_18B20(){
byte ch=0; byte i;
for(i=0;i<8;i++){
DQ_OUT=1; DQ=1; DELAY1(); DQ=0; DELAY1(); DQ_OUT=0; ch=ch>>1;
//初始化
WRITE_18B20(0XCC); //跳过 ROM WRITE_18B20(0xBE); //读暂存存储器的值命令 TEML=READ_18B20(); TEMH=READ_18B20(); //读温度的高 8 位和低八位 dummy=INIT_18B20(); //最后初始化,表示读取温度结束 }
单个 18B20 实现温度测试步骤(2013/5/30)
注:该文档所用程序为 FREESCALE JM60 单片机,总线时钟为 8M,若要移植到其它 MCU 上,需要将时间重新调节, 或者更改总线时钟频率的输出;
电路图
DS18B20 工作协议:初始化,存储器操作命令,处理数据;
在关于时序的编写中,for 循环中的 NOP 指令,和单独调用的 NOP 指令所用时间完全不同;NOP 占用 1/总线时 钟的时间;如 JM60 的总线时钟为 8M,则 NOP 指令一定占用 0.125US,而将 NOP 放在 FOR 循环中,由于 FOR 的判断指令,加法指令,以及转子程序等等消耗的时间很长,远远大于一个 NOP 的指令,此时,若要获得执行 代码的精确时间,最好用示波器观察,再得出最直接的结果;
注: 在写步骤中,整个过程端口方向均为输出;
这里对时序要求高,最好用示波器调整出精确的时序; /*****************向 18B20 写数据********************************/ void WRITE_18B20(unsigned char ch){
byte i; for(i=0;i<8;i++) {
/*****************18B20 的初始化程序***************************/
byte INIT_18B20() {
byte DQ_RETURN=2;
DQ_OUT=1;
//引脚设置为输出
DQ=1;
DELAY1();
//稍微延时,即可
DQ=0;
//将电平拉低至少 480uS,最大为 960US
//返回值为温度的十倍,小数点后一位
主函数中调用:
SIGNAL=TEMP_DETECT_18B20();
if(SIGNAL==0){
if(DQ)
//此时端口为 1,则表示转换完成
TEMP_RESULT=TEMP_READ_18B20();
//返回温度的十倍值
若时序错误,很有可能读出的数据位 0XFF;若温度传感器烧坏,容易读到 85°; 使用默认 12 位转换精度,分辨率为 0.0625°,此处不需要这么高的精度因此:
2. 将端口方向设为输入,必须在下降沿之后的 15US 内将端口数据读取;此处推荐端口方向设为输入后,延时 5US, 读取端口数据;
3. 读取数据完毕后,延时 60US 即可; 4. 每两个数据位之间间隔大于 1US;
注: 在这个时序内,要不断改变端口方向; 如果上拉电阻阻值合理设置,可以小于 4.7K 欧姆,利于提高时序速度; 读数据和写数据都是 8 位,从 LSB 开始发送;
TEM_RESULT=(TEML>>3)+(TEMH<<5); //分辨率为 0.5° TEM_RESULT=TEM_RESULT*5;
if((TEMH&0X80)!=0)
//最高位为 1,则为负温度
;;
// TEM_RESULT=~TEMP_RESULT+1;
//温度为负,取补码
return(TEM_RESULT); }
DQ_OUT=1; DQ=1; DELAY1(); DQ=0; DELAY1(); DELAY1();
if((ch&0x01)==1) DQ=1; else DQ=0; ch=ch>>1; DELAY9(8); DQ=1;
//端口设为输出,并给个拉低电平的下降沿 //拉低电平,并维持一微秒以上,表示要发送数据 //在 15US 内将要写的电平写在线上