找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3293|回复: 2
打印 上一主题 下一主题
收起左侧

DS18B20仿真后,LCD显示的温度和实际模拟温度不一致,跪求大佬指教啊

[复制链接]
跳转到指定楼层
楼主
仿真的实验现象图已经放在后面了,大佬帮我看看问题啊

现在就是LCD显示的温度和实际模拟温度不一致,





/**************************************************/
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define delayNop(); {_nop_();_nop_();_nop_();_nop_();};

uchar code table[]=" ERROR!!!       ";
uchar code table1[]="xianzaiwendu    ";
uchar code table2[]="Temp=    .  Cent";
uchar code table3[10]="0123456789";

sbit lcd_rs=P1^0;
//sbit lcd_rw=P1^1;
sbit lcd_en=P2^5;
sbit DQ=P2^2;
uchar num,time;
void delay(uint t)
{
unsigned char n;
   while(t--)
   {
     for(n = 0; n<250; n++)
    {
      _nop_();
      _nop_();
     _nop_();
      _nop_();
    }
   }
}

void write_com(uchar com)    //写命令
{
////lcd_rw=0;
//delay(5);
        lcd_rs=0;
        lcd_en=0;
        _nop_();
        _nop_();
        P0=com;
        delayNop();
        lcd_en=1;  
        delay(1);
        lcd_en=0;
}

void write_date(uchar date)      //写数据
{
//lcd_rw=0;
// delay(5);
  lcd_rs=1;
  lcd_en=0;
  _nop_();
  _nop_();

   P0=date;        
   delayNop();
        lcd_en=1;                                                         
        delay(1);
        lcd_en=0;               
}

void init()       //初始化函数
{
// dula=0;
// wela=0;
lcd_en=0;  //可以试试不加这一句看结果怎样
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}

uchar init_DS18bB20()
{
        bit flag;
        DQ=1;                                          //人为拉高
        for(time=0;time<2;time++);                        //稍微延时6US;
        DQ=0;                                                        //认为拉低
        for(time=0;time<200;time++);                          //延时600US给单片机检测
        DQ=1;                                                                   //被上拉电阻拉高        (仿真里面没有上拉,有没有都需要人为拉高)
        for(time=0;time<20;time++);                           // 延时60US检测
        flag=DQ;                                                                //这时又被DS18B20拉低,
        for(time=0;time<200;time++);                   //延时600US检测时间
        return flag;                     //返回0表示存在

}

void Write_Byte(uchar dat)                 //写一个字节,单片机向DS18B20写命令,确定DS18B20的工作方法之类的
{
unsigned char i=0;
        for (i=0; i<8; i++)
                 {
                  DQ =1;         // 先将数据线拉高
                  _nop_();             //等待一个机器周期         
                  DQ=0;          //将数据线从高拉低时即启动写时序      
                  DQ=dat&0x01;   //利用与运算取出要写的某位二进制数据,
                       //并将其送到数据线上等待DS18B20采样        
                 for(time=0;time<10;time++)        
                     ;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
                  DQ=1;          //释放数据线,也就是被上拉电阻拉高,反正就是要把这个口释放,然后来执行下一个命令                    
                  for(time=0;time<1;time++)
                          ;//延时3us,两个写时序间至少需要1us的恢复期
                  dat>>=1;       //将dat中的各二进制位数据右移1位
                 }
          for(time=0;time<4;time++)
                      ; //稍作延时,给硬件一点反应时间
}

uchar Read_Byte()
{
        uchar i=0;
        uchar dat;//用来储存读出的一个字节,默认为0
        for(i=0;i<8;i++)
        {
                DQ=1;
                _nop_();
                DQ=0;        //读命令一定得是低电平
                dat>>=1;   //读取数据是从高位开始读,dat默认是0,也就是0000 0000,
                                 //  这是下标是指向最高位的,所以得先右移一位让出一个位置
                _nop_();        //需要>1US;
                DQ=1;                //又被上拉电阻拉高
           for(time=0;time<2;time++);
                if(DQ==1)                   //由DQ发送的信号来决定,发送的是高电平还是低电平
                        dat|=0x80;           //高电平就或0x80,1000 0000
                else
                        dat|=0x00;         //低电平就或,0x00
                for(time=0;time<5;time++);//延时10US左右,因为需要在15US内完成读取
                }                                 
        return dat;
}

void Readyread()//做好读温度准备。。。。可以加在主函数里面,但是分出来比较清晰明了
{
        init_DS18bB20();
        Write_Byte(0xcc);        //跳过读序号
        Write_Byte(0x44);   //启动温度转换
        for(time=0;time<100;time++);
        init_DS18bB20();           //再初始化一下
        Write_Byte(0xcc);  //跳过读序号
        Write_Byte(0xbe);  //都温度寄存器,前两个分别是温度的,低,高位
}

void display()                                                //显示第一行说明
{
        write_com(0x80);
        for(num=0;num<16;num++)
        {
                 write_date(table[num]);
         //        delay(1);
        }  
                while(1);
}

void display1()                                        //显示第二行说明
{
        write_com(0x80);
        for(num=0;num<16;num++)
        {
                write_date(table1[num]);
          //        delay(1);
        }


}

void display2()
{
        write_com(0x80+0x40);
        for(num=0;num<16;num++)
        {
                  write_date(table2[num]);
                  //delay(1);
        }
}
                                                
void display_temp(uchar x)          //显示温度整数部分
{
        uchar bai,shi,ge;
        bai=x/100;
        shi=(x%100)/10;
        ge=x%10;
        write_com(0x80+0x46);
        write_date(table3[bai]);
        write_date(table3[shi]);
        write_date(table3[ge]);



}

void display1_temp(uchar x)          //显示温度小数部分
{
        write_com(0x80+0x4a);
        write_date(table3[x]);
}



void main()
{
        uchar TL;//储存暂存器的温度最高位
        uchar TH;//储存暂存器的温度最低位
        uchar TN; //储存温度整数部分
        uchar TD; //储存温度小数部分
        init();
        if(init_DS18bB20()==1)
                display();
        display1();
        display2();
        while(1)
        {
                Readyread();
                TL=Read_Byte();
                TH=Read_Byte();
                TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
                                          //这样得出的是温度的整数部分,小数部分被丢弃了
            TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,
                                          //这样得到的是温度小数部分的第一位数字(保留1位小数)

                display_temp(TN);
                display1_temp(TD);
                _nop_(); _nop_();
        }
               
}

51hei图片_20191227184425.png (57.36 KB, 下载次数: 42)

51hei图片_20191227184425.png
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:584814 发表于 2019-12-30 17:07 | 只看该作者
              TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
                                          //这样得出的是温度的整数部分,小数部分被丢弃了
            TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,
                                          //这样得到的是温度小数部分的第一位数字(保留1位小数)
改成这个试试:
TN=TH<<=8|TL;
TN=TN*0.0625*1000+0.5;
TD=TN%10;TN=TN/10;
另外,以上程序都不会处理零下的温度。
回复

使用道具 举报

板凳
ID:213173 发表于 2019-12-31 11:00 | 只看该作者
楼主的程序基本没有问题,关键是参考的程序MCU时钟与楼主选用的不同导致时序误差而产生读取错误。

  1. #include<reg51.h>
  2. #include<intrins.h>
  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. #define delayNop(); {_nop_();_nop_();_nop_();_nop_();};

  6. uchar code table[]=" ERROR!!!       ";
  7. uchar code table1[]="xianzaiwendu    ";
  8. uchar code table2[]="Temp=    .  Cent";
  9. uchar code table3[10]="0123456789";

  10. sbit lcd_rs=P1^0;
  11. //sbit lcd_rw=P1^1;
  12. sbit lcd_en=P2^5;
  13. sbit DQ=P2^2;
  14. uchar num,time;

  15. void DelayUs2x(uchar t)
  16. {   
  17.         while(--t);
  18. }

  19. void delay(uint t)
  20. {
  21. unsigned char n;
  22.    while(t--)
  23.    {
  24.      for(n = 0; n<250; n++)
  25.     {
  26.       _nop_();
  27.       _nop_();
  28.      _nop_();
  29.       _nop_();
  30.     }
  31.    }
  32. }

  33. void write_com(uchar com)    //写命令
  34. {
  35.         //lcd_rw=0;
  36.         //delay(5);
  37.         lcd_rs=0;
  38.         lcd_en=0;
  39.         _nop_();
  40.         _nop_();
  41.         P0=com;
  42.         delayNop();
  43.         lcd_en=1;  
  44.         delay(1);
  45.         lcd_en=0;
  46. }

  47. void write_date(uchar date)      //写数据
  48. {
  49.         //lcd_rw=0;
  50.         // delay(5);
  51.         lcd_rs=1;
  52.         lcd_en=0;
  53.         _nop_();
  54.         _nop_();
  55.        
  56.         P0=date;        
  57.         delayNop();
  58.         lcd_en=1;                                                         
  59.         delay(1);
  60.         lcd_en=0;               
  61. }

  62. void init()       //初始化函数
  63. {
  64.         // dula=0;
  65.         // wela=0;
  66.         lcd_en=0;  //可以试试不加这一句看结果怎样
  67.         write_com(0x38);
  68.         write_com(0x0c);
  69.         write_com(0x06);
  70.         write_com(0x01);
  71. }

  72. uchar init_DS18bB20()
  73. {
  74.         bit flag;
  75.         DQ=1;                                          //人为拉高
  76.         DelayUs2x(5);   //稍做延时                       //稍微延时6US;
  77.         DQ=0;                                                        //认为拉低
  78.         DelayUs2x(200); //精确延时 大于 480us 小于960us
  79.         DelayUs2x(200);
  80.         DQ=1;                                                                   //被上拉电阻拉高        (仿真里面没有上拉,有没有都需要人为拉高)
  81.         DelayUs2x(50); //15~60us 后 接收60-240us的存在脉冲                         // 延时60US检测
  82.         flag=DQ;                                                                //这时又被DS18B20拉低,
  83.         DelayUs2x(25); //稍作延时返回                   //延时600US检测时间
  84.         return flag;                     //返回0表示存在
  85. }

  86. void Write_Byte(uchar dat)                 //写一个字节,单片机向DS18B20写命令,确定DS18B20的工作方法之类的
  87. {
  88.         unsigned char i=0;
  89.         for (i=0; i<8; i++)
  90.         {
  91.                 DQ =1;         // 先将数据线拉高
  92.                 _nop_();             //等待一个机器周期         
  93.                 DQ=0;          //将数据线从高拉低时即启动写时序      
  94.                 DQ=dat&0x01;   //利用与运算取出要写的某位二进制数据,
  95.                 //并将其送到数据线上等待DS18B20采样        
  96.                 DelayUs2x(25);        
  97.                 //延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
  98.                 DQ=1;          //释放数据线,也就是被上拉电阻拉高,反正就是要把这个口释放,然后来执行下一个命令                    
  99. //                for(time=0;time<1;time++)
  100. //                ;//延时3us,两个写时序间至少需要1us的恢复期
  101.                 dat>>=1;       //将dat中的各二进制位数据右移1位
  102.         }
  103.         DelayUs2x(25);
  104.          //稍作延时,给硬件一点反应时间
  105. }

  106. uchar Read_Byte()
  107. {
  108.         uchar i=0;
  109.         uchar dat;//用来储存读出的一个字节,默认为0
  110.         for(i=0;i<8;i++)
  111.         {
  112.                 DQ=1;
  113.                 _nop_();
  114.                 DQ=0;        //读命令一定得是低电平
  115.                 dat>>=1;   //读取数据是从高位开始读,dat默认是0,也就是0000 0000,
  116.                 //  这是下标是指向最高位的,所以得先右移一位让出一个位置
  117.                 _nop_();        //需要>1US;
  118.                 DQ=1;                //又被上拉电阻拉高
  119. //                for(time=0;time<2;time++);
  120.                 if(DQ==1)                   //由DQ发送的信号来决定,发送的是高电平还是低电平
  121.                 dat|=0x80;           //高电平就或0x80,1000 0000
  122.                 else
  123.                 dat|=0x00;         //低电平就或,0x00
  124.                 DelayUs2x(25);//延时10US左右,因为需要在15US内完成读取
  125.         }                                 
  126.         return dat;
  127. }

  128. void Readyread()//做好读温度准备。。。。可以加在主函数里面,但是分出来比较清晰明了
  129. {
  130.         init_DS18bB20();
  131.         Write_Byte(0xcc);        //跳过读序号
  132.         Write_Byte(0x44);   //启动温度转换
  133.         for(time=0;time<100;time++);
  134.         init_DS18bB20();           //再初始化一下
  135.         Write_Byte(0xcc);  //跳过读序号
  136.         Write_Byte(0xbe);  //都温度寄存器,前两个分别是温度的,低,高位
  137. }

  138. void display()                                                //显示第一行说明
  139. {
  140.         write_com(0x80);
  141.         for(num=0;num<16;num++)
  142.         {
  143.                 write_date(table[num]);
  144.                 //        delay(1);
  145.         }  
  146.         while(1);
  147. }

  148. void display1()                                        //显示第二行说明
  149. {
  150.         write_com(0x80);
  151.         for(num=0;num<16;num++)
  152.         {
  153.                 write_date(table1[num]);
  154.                 //        delay(1);
  155.         }
  156. }

  157. void display2()
  158. {
  159.         write_com(0x80+0x40);
  160.         for(num=0;num<16;num++)
  161.         {
  162.                 write_date(table2[num]);
  163.                 //delay(1);
  164.         }
  165. }
  166.                                                 
  167. void display_temp(uchar x)          //显示温度整数部分
  168. {
  169.         uchar bai,shi,ge;
  170.         bai=x/100;
  171.         shi=(x%100)/10;
  172.         ge=x%10;
  173.         write_com(0x80+0x46);
  174.         write_date(table3[bai]);
  175.         write_date(table3[shi]);
  176.         write_date(table3[ge]);
  177. }

  178. void display1_temp(uchar x)          //显示温度小数部分
  179. {
  180.         write_com(0x80+0x4a);
  181.         write_date(table3[x]);
  182. }
  183. void main()
  184. {
  185.         uchar TL;//储存暂存器的温度最高位
  186.         uchar TH;//储存暂存器的温度最低位
  187.         uchar TN; //储存温度整数部分
  188.         uchar TD; //储存温度小数部分
  189.         init();
  190.         if(init_DS18bB20()==1)
  191.         display();
  192.         display1();
  193.         display2();
  194.         while(1)
  195.         {
  196.                 Readyread();
  197.                 TL=Read_Byte();
  198.                 TH=Read_Byte();
  199.                 TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
  200.                 //这样得出的是温度的整数部分,小数部分被丢弃了
  201.                 TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,
  202.                 //这样得到的是温度小数部分的第一位数字(保留1位小数)
  203.                
  204.                 display_temp(TN);
  205.                 display1_temp(TD);
  206.                 _nop_(); _nop_();
  207.         }       
  208. }
复制代码



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表