工大创客馆-焊接科技网欢迎您

banner

通过实例,一步步指导你设定DS18B20时序关键,解决测温显示错误问题---(测温系统第二篇)

/
上一篇我们建立了DS18B20测温系统的最简模型,并且给出了完整的源程序。这对掌握用单片机进行测温很有用。其实DS18B20有很多值得体会地方,否则容易测温不准或显示不准。为什么呢?首先DS18B20本身是一个单总线系统,对测温时序要求很严格;第二是把温度怎样转换到显示系统里,第三是把温度显示出来,分好百位、十位、个位小点儿等等。后两项内容相对说来还是比较简单,也比较固定的,大家可以参考一些资料,应该能建立起来,我们也给出的最简模型,可以用心体会,但是对于DS18B20本身,可以说是整个测温工作最难的,也最容易出现错误,因此我们这一部分系统讨论DS18B20的问题,也就是时序问题。
 
首先,大家一定要明确DS18B20的难度就是由它的特点决定的。那么我们对DS18B20的特点应该了解,简述为:DS18B20 是一种新型的“一线器件” , 其体积更小、 且适用电压更宽、 更经济。 DALLAS 半导体公司的数字化温度传感器 DS18B20 是世界上第一片支持“一线总线”接口的温度传感器。 温度测量范围为 -55~+125 摄氏度, 可编程为 9 位~12 位转换精度, 测温分辨率可达 0. 0625摄氏度。 DS1 8B20数字温度计是DALLAS公司生产的1-Wire, 即单总线器件, 具有线路简单, 体积小的特点。 但这种单总线,意味着没有时钟线,只有一根通信线。单总线读写数据是靠控制起始时间和采样时间来完成,所以时序要求很严格,这也是DS18B20驱动编程的难点。
 
可以看到,DS18B20驱动编程的难点就是时序是否正确设定的问题。
 
 
 
 
 
 
整个 DS18B20 单线通信功能是分时完成的, 因此它有严格的时隙概念,时序是否正确设定,就是时隙设定是否合理,它的通信设定都是以初始化序列开始典型过程为:复位→发SKIP ROM命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送SKIP ROM命令(OXCC)→发读存储器命令(OXBE)→连续读出两个字节数据(即温度)→结束。具体的要点我们给出自己总结的三个时序图(见图1-3),具体的,大家参考网上资料,书籍或DS18B20的技术手册来体会图形时序的含义(一定要看,结合程序一定要懂)。
 
 
 
 
 
 
 
 
 
下面,我们结合具体源程序、Keil uVision5进行调试与设定来讲述,让大家明白DS18B20的时序设定问题。
 
这次我们以四位数码管为例,给出了完整的源程序并给出了四位数码管显示示意图(见图4),第一位是代表着温度的正负号;后面显示测温的具体数字。
 
 
 
 
 
 
 
首先我们来看图1,是初始化,要求时序必须是将总线拉低480us~960us。对应的程序为:void ds18b20_reset(void)------delay_10us(75),此时程序正常显示,通过实在频率可以分析出延时642us,如果你的设计参数如果与临界值有很大距离,可以通过计算来设定,但如果数值要求范围很小,就应该通过工具加以验证。
下面我们讲述验证的相信过程,分别已参数75 和50为例进行:
 
调试过程如下:
打开Keil uVision5,首先设置要调试的延时函数前后设置断点。(设置方法为单击该行最左边的空白处或右键选择添加断点),如图5 所示。
接着先点击调试按钮,再点击运行按钮,开始运行记录一下sec的时间,当延时参数为70时,用时分别为0.00039600(即396us)、397us、1043us,如图6-7所示。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
验证的结果为:
当延时参数为75时:
延时1043-397=646us,
当延时参数为50时:
863-397=466us,
可以看到,466us没有达到初始化所要求的480us~960us,因此不能够正常显示温度,如图8 所示。
 
 
在源程序中,我们用括号标注几个关键点的持续测试结果。可以看到这些关键点的持续时序设置不当,那么这个测温就没法正确显示。你也可以在源程序上调试程序时增大或减小相关参数,看看显示结果,我们通过实践得到,常见的一共有三处,参数的变化会直接影响测温结果,这三处就是最为关键地方,也就是DS1 8B20时序的关键所在。
 
 
附源程序及调试点:
 
#include "reg51.h"
#include "intrins.h"                     
#define DIGTAL P0 
#define POSITION P2 
#define uchar unsigned char
#define u8 unsigned char
#define uint unsigned int
#define u16 unsigned int
sbit     DS18B20_PORT=P3^2;                        
sbit     DIN=P0^7; 
uint code DIGTALL[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
uint code DIGTALLL[10]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //显示小数点
 
void delay_10us(u16 ten_us)//延时函数
{
while(ten_us--);
}
void delay_ms(u16 ms)//延时函数
{
u16 i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
 
void ds18b20_reset(void)//初始化程序初始化成功返回1,失败返回0
{
DS18B20_PORT=0;
delay_10us(70);//改成50,显示温度数值不对,且不随着变化(对应的关键点:主机输出低电平,保持低电平时间至少480us,,以产生复位脉冲)
DS18B20_PORT=1;
delay_10us(2);//改成20,仍正常
}
 
u8 ds18b20_check(void)//检查
{
u8 time_temp=0;
while(DS18B20_PORT&&time_temp<20)
{
time_temp++;
delay_10us(1);//改成10,仍正常
}
if(time_temp>=20)return 1;
else time_temp=0;
while((!DS18B20_PORT)&&time_temp<20)
{
time_temp++;
delay_10us(1);
}
if(time_temp>=20)return 1;
return 0;
}
 
u8 ds18b20_read_bit(void)
{
u8 dat=0;
DS18B20_PORT=0;
delay_10us(1);//改成5,显示温度数值不对,且不随着变化(对应的关键点:在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据)
DS18B20_PORT=1;
if(DS18B20_PORT)dat=1;
else dat=0;
delay_10us(5);//改成1或50,仍正常
return dat;
 
u8 ds18b20_read_byte(void)//读取一个字节
{
u8 i=0;
u8 dat=0;
u8 temp=0;
for(i=0;i<8;i++)
{
temp=ds18b20_read_bit();
dat=(temp<<7)|(dat>>1);
}
return dat;
}
 
void ds18b20_write_byte(u8 dat)//向18B20写入一个字节
{
u8 i=0;
u8 temp=0;
for(i=0;i<8;i++)
{
temp=dat&0x01;
dat>>=1;
if(temp)
{
DS18B20_PORT=0;
delay_10us(1);//改成10,显示温度数值不对,且不随着变化(对应的关键点:主机输出低电平延时2us,然后释放总线)
DS18B20_PORT=1;
delay_10us(6);//改成26,仍正常数值,点显示不稳,总抖动
}
else
{
DS18B20_PORT=0;
delay_10us(6);//改成26,仍正常数值,点显示不稳,总抖动
DS18B20_PORT=1;
delay_10us(1);//改成16,仍正常
}
}
}
 
void ds18b20_start(void)//开始
{
ds18b20_reset();
ds18b20_check();
ds18b20_write_byte(0xcc);   
 ds18b20_write_byte(0x44);
}
 
u8 ds18b20_init(void)//初始
{
ds18b20_reset();
return ds18b20_check();
}
 
float ds18b20_read_temperture(void)//读取温度
{
float temp;
u8 dath=0;
u8 datl=0;
u16 value=0;
ds18b20_start();
ds18b20_reset();
ds18b20_write_byte(0xcc);
ds18b20_write_byte(0xbe);
datl=ds18b20_read_byte();
dath=ds18b20_read_byte();
value=(dath<<8)+datl;
temp=value*0.0625*100+0.5;
return temp;
}
 
void main()
{
int i=0;
int temp_value;
ds18b20_init();
 
while(1)
{
i++;
if(i%50==0)
temp_value=ds18b20_read_temperture();
 
POSITION=1;
DIGTAL=DIGTALL[10];
delay_10us(3);
DIGTAL=0xff;
delay_10us(3);
 
POSITION=2;
DIGTAL=DIGTALL[temp_value % 10000 / 1000];
delay_10us(3);
DIGTAL=0xff;
delay_10us(3);
 
POSITION=4;
DIGTAL=DIGTALLL[temp_value% 1000 / 100];
delay_10us(3);
DIGTAL=0xff;
delay_10us(3);
 
POSITION=8;
DIGTAL=DIGTALL[temp_value% 10];
delay_10us(3);
DIGTAL=0xff;
delay_10us(3);
}
}
 
 
 
 
 
 
敬告:本内容为制作人独立制作,非经制作人书面授权,请不要转载发布!