ds18b20数字温度计测得温度时对时错

2019-07-16 05:58发布

大家好!我自己动手做了一个数字温度计。用的是STC12C2052AD单片机,而温度传感器用的是DS18B20,12M晶振,用C语言写(移植)的程序,但是现在温度可以测出来,只是显示有时是对的,有是错的。规律是:显示正确温度2-3秒,跳成850约一秒,然后又显示正确温度。对这个现象,我真是百思不得其解,如果是时序的问题,那为什么可以测得正确的温度?



还有,资料上说STC12系列的单片机是不分频的,那是不是说比如我用12M的晶振,那么执行一条指令的时间不再是1us,而是1/12  us?还是要通过反汇编再查stc的指令表得知?





DS18B20是数字传感器,读出的是一个16bit的数据,前5bit表示符号,中间八位表示温度的整数部分,我是把中间8位取出来,然后用分离出百、十、个位,送到数码管显示,刚开始用定时器中断扫描数码管,但因这个传感器对时序要求很严格,便改用了软件延时,可是用定时器与用软件延时效果是一样的都是对错对错循还。

是不是在读的时候时序错了呢?读的数据刚好错位了?如果在每次读温度前对它进行读忙呢?是否可以解决?


以下是我的程序,请论坛高手多多指点,在下感激不尽!



(程序可以显示正确的温度,只是会跳动)







#include <reg2051.h>
#include<intrins.h>

#define  uchar unsigned char
#define  uint  unsigned int



void ow_reset(void);
void delay(uint t);
void write_byte(uchar val);
uint read_temp();
uchar read_byte(void);
work_temp(uint tem);
void chuli(uchar wd);
void delayms(uint ms);        
void displays();



uchar wei=0;
uint temp=0;
uchar wendu=0;
uchar b,s,g,x;          //百位,十位,个位,小数
sbit d4=P3^2;         //位选信号端
sbit d3=P3^4;
sbit d2=P3^3;
sbit d1=P3^5;



sbit DQ=P3^7;    //接传感 器

uchar code disdu[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};                            //段选列表
//共阳LED段码表        "0"  "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9" "不亮" "-"
uchar data temp_data[2]={0x00,0x00};             //读出温度暂放

uchar code ditab[16]=
{0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};                   //小数部分直接查表


void main()
{
ow_reset();
write_byte(0xcc);             //Skip ROM
write_byte(0x44);           //发转换命令
            
while(1)
     {
       work_temp(read_temp());
  
       displays();   

}


}


void ow_reset(void)      //复位
{
char presence=1;
while(presence)
{
  while(presence)
   {
    DQ=1;_nop_();_nop_();//从高拉倒低
DQ=0;                                       
delay(50);           //550 us
DQ=1;                                       
delay(6);            //66 us
presence=DQ;  //presence=0 复位成功,继续下一步
}
   delay(45);            //延时500 us
   presence=~DQ;         
}
DQ=1;                  //拉高电平      

}





/****************DS18B20写命令函数************************/
//向1-WIRE 总线上写1个字节
void write_byte(uchar val)
{
  uchar i;
  for(i=8;i>0;i--)
  {
   DQ=1;_nop_();_nop_();                 //从高拉倒低
   DQ=0;_nop_();_nop_();_nop_();_nop_();  //5 us
   DQ=val&0x01;                           //最低位移出
   delay(6);                              //66 us
   val=val/2;                             //右移1位
   }
   DQ=1;
   delay(1);
}


/****************DS18B20读1字节函数************************/
//从总线上取1个字节
uchar read_byte(void)
{
uchar i;
uchar value=0;
for(i=8;i>0;i--)
{
  DQ=1;_nop_();_nop_();
  value>>=1;
  DQ=0;_nop_();_nop_();_nop_();_nop_();        //4 us
  DQ=1;_nop_();_nop_();_nop_();_nop_();        //4 us
  if(DQ)value|=0x80;
  delay(6);                                     //66 us
}
DQ=1;
return(value);
}



uint read_temp()
{
  ow_reset();                  //总线复位
  delay(200);
  write_byte(0xcc);            //发命令
  write_byte(0x44);            //发转换命令
  ow_reset();
  delay(1);
  write_byte(0xcc);            //发命令
  write_byte(0xbe);
  temp_data[0]=read_byte();    //读温度值的第字节
  delay(3);
  temp_data[1]=read_byte();    //读温度值的高字节
  temp=temp_data[1];
  temp<<=8;                                               
  temp=temp|temp_data[0];      // 两字节合成一个整型变量。
  return(temp);                 //返回温度值
}




/****************温度数据处理函数************************/

//二进制高字节的低半字节和低字节的高半字节组成一字节,这个
//字节的二进制转换为十进制后,就是温度值的百、十、个位值,而剩
//下的低字节的低半字节转化成十进制后,就是温度值的小数部分

/********************************************************/
work_temp(uint tem)
{
uchar n=0;
if(tem>6348)                        // 温度值正负判断
{
  tem=65536-tem;
  n=1;
}
x=tem&0x0f;            // 取小数部分的值     

wendu=tem>>4;             // 取中间八位,即整数部分的值
chuli(wendu);   
if(n)
  b=0x0b;      //负温度时最高位显示"-"

}


void delay(uint t)
{     t=t*12;                                //stc12系列单片机不分频,乘以8-12时,延时约10us
  for (;t>0;t--);
}





void delayms(uint ms)        
{
ms=120*2*ms;     //取这个参数显示比较稳定(数码管不闪烁,也有较高亮度)
for(;ms>0;ms--)
;
}





void displays()                      //显示温度
{
P1=disdu[ditab[x]];
d1=0;
delayms(5);
d1=1;



P1=disdu[g];

P1^7=0;      //点亮小数点
d2=0;
delayms(5);
d2=1;



P1=disdu[s];
d3=0;
delayms(5);
d3=1;



P1=disdu[b];
d4=0;
delayms(5);
d4=1;
}






void chuli(uchar wd)         //处埋温度数据
{
b=wd/100;
s=wd%100/10;
g=wd%100%10;
if(b==0)
  b=10;
if(s==0)
  s=10;
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
h414984185
1楼-- · 2019-07-16 10:49
应该是你的温度转换的太频繁了吧!精度为12位的话转换时间为750ms,在这750ms期间读温度的话可能读到的是错误值吧!一般来说温度变化都是比较缓慢的,用不着时时刻刻转换,你设置五秒转换一次,十秒转换一次,一分钟转换一次问题都不大,只是个人看法。
gmr1206
2楼-- · 2019-07-16 12:57
h414984185 发表于 2012-11-13 14:48
应该是你的温度转换的太频繁了吧!精度为12位的话转换时间为750ms,在这750ms期间读温度的话可能读到的是错 ...

谢谢您的回复,问题正如你所说。
hu823849846
3楼-- · 2019-07-16 13:09
h414984185 发表于 2012-11-13 14:48
应该是你的温度转换的太频繁了吧!精度为12位的话转换时间为750ms,在这750ms期间读温度的话可能读到的是错误值吧!一般来说温度变化都是比较缓慢的,用不着时时刻刻转换,你设置五秒转换一次,十秒转换一次,一分钟转换一次问题都不大,只是个人看法。 ...

刚才在弄定时器的数码管动态扫描,加上18b20之后怎么的都不好用,看了你的话茅塞顿开啊,18b20不实时转换就什么问题都没有了,太感谢了
陈必成
4楼-- · 2019-07-16 13:20
 精彩回答 2  元偷偷看……

一周热门 更多>