找回密码
 立即注册

QQ登录

只需一步,快速开始

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

STC89C52单片机DS18B20程序调试问题求助

[复制链接]
跳转到指定楼层
楼主
最近在学习DS18B20外设时,接触到了单总线协议。按照DS18B20的DataSheet写了一版程序后,发现一直无法正常显示温度,最后发现是延时的问题,但具体原理一直没想明白。

单片机芯片为STC89C52,晶振为11.0592MHz。一个_nop_()约为1.085us。

这是我写的源代码:
  1.                 #include<reg52.h>
  2.                 #include<intrins.h>
  3.                 #define uchar unsigned char
  4.                 #define uint unsigned int
  5.                
  6.                 sbit DX=P2^6;//(P0为数码管输出端口)
  7.                 sbit WX=P2^7;
  8.                 sbit DS18B20_IO=P2^2;
  9.                
  10.                 uchar code Table_D[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  11.                 uchar code Table_W[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
  12.                
  13.                 uchar DS18B20_Reset_OK;
  14.                 uint num;
  15.                
  16.                 void Delay_Us(uint x);
  17.                 void Delay_Ms(uint x);
  18.                 void Display(uint x);
  19.                
  20.                 void DS18B20_Init();
  21.                 void DS18B20_Write_Byte(uchar command);
  22.                 uchar DS18B20_Read_Byte();
  23.                 uint Start_DS18B20();
  24.                
  25.                
  26.                 void main()
  27.                 {
  28.                         while(1)
  29.                         {
  30.                                 num=Start_DS18B20();
  31.                                 Display(num);
  32.                         }
  33.                 }
  34.                
  35.                 void Delay_Us(uint x)//11.0592MHz,一个nop为1.085us
  36.                 {
  37.                         uint a;
  38.                         for(a=x;a>0;a--)
  39.                         {
  40.                                 _nop_();
  41.                         }
  42.                 }
  43.                
  44.                
  45.                 void DS18B20_Init()
  46.                 {
  47.                         DS18B20_IO=1;
  48.                         Delay_Us(2);
  49.                         DS18B20_IO=0;
  50.                         Delay_Us(500);
  51.                         DS18B20_IO=1;
  52.                         Delay_Us(60);
  53.                         if(DS18B20_IO==0)
  54.                         {DS18B20_Reset_OK=1;}
  55.                         else
  56.                         {DS18B20_Reset_OK=0;}
  57.                         Delay_Us(500);
  58.                 }
  59.                
  60.                 void DS18B20_Write_Byte(uchar command)
  61.                 {
  62.                         uchar i,temp;
  63.                         temp=command;
  64.                         
  65.                         for(i=0;i<8;i++)
  66.                         {
  67.                                 DS18B20_IO=0;
  68.                                 _nop_();_nop_();

  69.                                         DS18B20_IO=temp&0x01;
  70.                                 Delay_Us(10);//?????
  71.                                         //Delay_Us(60);

  72.                                 DS18B20_IO=1;
  73.                                 _nop_();_nop_();
  74.                                 temp=temp>>1;
  75.                         }
  76.                         Delay_Us(10);
  77.                 }
  78.                
  79.                 uchar DS18B20_Read_Byte()
  80.                 {
  81.                         uchar i,temp1,temp2;
  82.                         
  83.                         for(i=0;i<8;i++)
  84.                         {
  85.                                 DS18B20_IO=0;
  86.                                 _nop_(); _nop_();
  87.                                 DS18B20_IO=1;
  88.                                 _nop_(); _nop_();
  89.                                 temp1=DS18B20_IO;
  90.                                 temp2=(temp2)>>1|(temp1<<7);
  91.                                 Delay_Us(60);
  92.                         }
  93.                         
  94.                         return temp2;
  95.                 }
  96.                
  97.                 uint Start_DS18B20()
  98.                 {
  99.                         uchar a,b;
  100.                         uint temp=0;
  101.                         DS18B20_Init();
  102.                         DS18B20_Write_Byte(0xcc);
  103.                         DS18B20_Write_Byte(0x44);
  104.                         DS18B20_Init();
  105.                         DS18B20_Write_Byte(0xcc);
  106.                         DS18B20_Write_Byte(0xbe);                        
  107.                         a=DS18B20_Read_Byte();
  108.                         b=DS18B20_Read_Byte();
  109.                         temp=b;
  110.                         temp=(temp<<8)|a;
  111.                         temp=temp*0.0625*10+0.5;
  112.                         
  113.                         return temp;
  114.                 }
  115.                
  116.                
  117.                

  118.                
  119.                 void Delay_Ms(uint x)
  120.                 {
  121.                         uint a,b;
  122.                         for(a=x;a>0;a--)
  123.                         {
  124.                                 for(b=0;b<1000;b++)
  125.                                 {_nop_();}
  126.                         }
  127.                 }
  128.                                 
  129.                
  130.                 void Display(uint x)
  131.                 {
  132.                         P0=0xff;
  133.                         WX=1;
  134.                         WX=0;
  135.                         P0=Table_D[x/100];
  136.                         DX=1;
  137.                         DX=0;
  138.                         P0=Table_W[0];
  139.                         WX=1;
  140.                         WX=0;               
  141.                         Delay_Ms(1);
  142.                         
  143.                         P0=0xff;
  144.                         WX=1;
  145.                         WX=0;
  146.                         P0=Table_D[x%100/10]|0x80;
  147.                         DX=1;
  148.                         DX=0;
  149.                         P0=Table_W[1];
  150.                         WX=1;
  151.                         WX=0;        
  152.                         Delay_Ms(1);
  153.                         
  154.                         P0=0xff;
  155.                         WX=1;
  156.                         WX=0;
  157.                         P0=Table_D[x%100%10];
  158.                         DX=1;
  159.                         DX=0;
  160.                         P0=Table_W[2];
  161.                         WX=1;
  162.                         WX=0;
  163.                         Delay_Ms(1);
  164.                 }
复制代码

现在字节写入那里是:
  1. DS18B20_IO=temp&0x01;
  2. Delay_Us(10);//?????
  3. //Delay_Us(60);
复制代码
运行结果如下:



按照DataSheet,一位数据的读/要持续最少60us,最大120us的时间。



如果我将字节写入部分改成:

  1. DS18B20_IO=temp&0x01;
  2. //Delay_Us(10);
  3. Delay_Us(60);
复制代码
运行结果如下:




我又参考了一下该开发板上外设的DS18B20例程,发现使用的都是非精确延时。
  1. void delayus(uint t)   //微秒级的延时函数
  2. {
  3.         while(t--);
  4. }
复制代码
  1. void ds_write_byte(uchar dat)   //写一个字节函数
  2. {
  3.         uchar i;
  4.         for(i=0;i<8;i++)      //循环8次
  5.         {
  6.                 ds=0;          //把总线拉为低电平
  7.                 _nop_();        //延时一机器周期,约1微秒
  8.                 ds=dat&0x01;    //dat写0x01按位与,目的是先传送dat的最低位
  9.                 delayus(6);      //延时,让整个读时序持续60~120微秒
  10.                 ds=1;          //把总线释放,让ds等于1
  11.                 dat=dat>>1;     //让dat右移一位,准备下一位的写入
  12.         }
  13.                 delayus(6);     //延时,让每个函数之间都有一定的间隔停顿
  14. }
复制代码
  1. void ds_reset()    //单总线初始化函数
  2. {
  3.         ds=1;           //总线先置高,让ds等于1
  4.         delayus(5);      //稍延时
  5.         ds=0;          //主机发送复位脉冲
  6.         delayus(80);    //延时(在480~960ms之间)
  7.         ds=1;          //释放总线,让ds等于1
  8.         delayus(14);    //等待(15~60ms)
  9.         if(ds==0)      //判断总线ds是否等于0
  10.                 flag=1;    //flag等于1表示DS18B20存在
  11.         else
  12.                 flag=0;    //flag等于0表示DS18B20不存在。
  13.         delayus(20);
  14. }
复制代码

可是我用Keil的仿真模式查看了一下延时时间,发现和DataSheet以及注释都对不上,让我有点想不明白。
这两个时间差也不够60us啊,Project Option那晶振频率设的也是11.0592MHz,这个问题确实没搞懂



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:213173 发表于 2021-10-25 06:27 | 只看该作者
  1. //测试条件12.0MHz晶振/12T MCU,如采用11.0592MHz晶振延时时间*1.085倍
  2. #include "reg51.h"

  3. typedef unsigned char uchar;
  4. typedef unsigned int uint;

  5. /*------------------------------------------------
  6. uS延时函数,含有输入参数 unsigned char t
  7. 大致延时长度如下 T=t*2+5us
  8. ------------------------------------------------*/
  9. void Delay_2xtus(uchar t)
  10. {   
  11.         while(--t);
  12. }
  13. /*------------------------------------------------
  14. uS延时函数,含有输入参数 unsigned uint t
  15. 大致延时长度如下 T=t*8+6us
  16. ------------------------------------------------*/
  17. void Delay_8xtus(uint t)
  18. {   
  19.         while(--t);
  20. }
  21. /*------------------------------------------------
  22. uS延时函数,含有输入参数 unsigned char t
  23. 大致延时长度如下 T=t*6+11us
  24. ------------------------------------------------*/
  25. void delay_6xtus(uchar t)
  26. {      
  27.         while(t--);
  28. }
  29. /*------------------------------------------------
  30. uS延时函数,含有输入参数 unsigned int t
  31. 大致延时长度如下 T=t*9+16us
  32. ------------------------------------------------*/
  33. void delay_9xtus(uint t)
  34. {      
  35.         while(t--);
  36. }
  37. /*------------------------------------------------
  38. mS延时函数,含有输入参数 unsigned char t
  39. 大致延时1mS
  40. ------------------------------------------------*/
  41. void Delay_ms(uchar t)
  42. {
  43.         while(t--)
  44.         {
  45.                 Delay_2xtus(243);
  46.                 Delay_2xtus(242);
  47.         }
  48. }

  49. void main()
  50. {
  51.         Delay_2xtus(100);
  52.         Delay_ms(100);
  53.         Delay_8xtus(100);
  54.         delay_9xtus(100);
  55.         delay_6xtus(100);

  56.         while(1);
  57. }
  58. //不同数据类型和写法的延时时间区别
  59. /*
  60.         unsigned char i=10;//2um
  61.         while(--i);//i*2um

  62.         unsigned int i=10;//4um
  63.         while(--i);//i*8us

  64.         unsigned char i=10;//2um
  65.         while(i--);//i*2+2um

  66.         unsigned int i=10;//4um
  67.         while(i--);//i*8+8us
  68. */
复制代码
回复

使用道具 举报

板凳
ID:916650 发表于 2021-10-25 11:23 | 只看该作者

感谢大佬,验证后发现原来的精确延时方法确实有问题
  1.                 void Delay_Us(uint x)//11.0592MHz,一个nop为1.085us
  2.                 {
  3.                         uint a;
  4.                         for(a=x;a>0;a--)
  5.                         {
  6.                                 _nop_();
  7.                         }
  8.                 }
复制代码


之前做的实验对时序的要求没那么严格,导致没发现这种精确延时方法有问题。
将10us的精确延时改成
  1.                 void Delay_Us_10()
  2.                 {
  3.                         _nop_();_nop_();_nop_();
  4.                         _nop_();_nop_();_nop_();
  5.                 }
复制代码

就好了
回复

使用道具 举报

地板
ID:123289 发表于 2021-10-25 16:23 | 只看该作者
这个不难解决,去研读DS18B20手册,特别是它的读写时序部分。再对比一下,你的程序对它的操作时序,能满足手册上的要求吗?
回复

使用道具 举报

5#
ID:916650 发表于 2021-10-25 17:02 | 只看该作者
yzwzfyz 发表于 2021-10-25 16:23
这个不难解决,去研读DS18B20手册,特别是它的读写时序部分。再对比一下,你的程序对它的操作时序,能满足 ...

嗯,您说的很对。最后发现是精确延时函数有问题,导致延时的时间并不是理想的定义的uint x的时间,超过了DataSheet要求的最大值120us,导致最后输出数据紊乱。确实是时序没对好导致的。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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