[DemoCode下载] 在示波器帮助下轻松移植新唐M0的18b20例程到51单片机

[复制链接]
1148|7
 楼主| gaoyang9992006 发表于 2022-8-29 16:38 | 显示全部楼层 |阅读模式
#申请原创# https://bbs.21ic.com/icview-3248814-1-1.html
国产的18B20也是非常好用,轻松教你1分钟移植到M487
@21小跑堂
新唐提供的原例程在上述链接下载,接下来我们让这个例程的库函数统一到51单片机里去。
如何统一呢,其实就是实现延时函数的移植。
由于51单片机通常采用跑空指令延时的方法,因此我们这里要借助示波器即可很好的实现延时脉宽长度的测量,确保相差无几,即可实现完美移植。
原库函数如下所示,使用的是CLK_SysTickDelay()函数,这里我们替换它们即可。
  1. static void DS18B20_Reset(void)
  2. {
  3.     uint8_t i;
  4.     i = 1;

  5.     while (i)
  6.     {
  7.         DQ = 0;                              //Send a low level reset signal
  8.         CLK_SysTickDelay(480);               //Delay at least 480us
  9.         DQ = 1;                              //Release data line
  10.         CLK_SysTickDelay(60);                //Waiting for 60us
  11.         i = DQ;                              //Detect the presence of pulses
  12.         CLK_SysTickDelay(420);               //Waiting for the device to release the data line
  13.     }
  14. }


  15. /**
  16.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Read 1 byte data from DS18B20
  17.   * @param  None
  18.   * [url=home.php?mod=space&uid=266161]@return[/url] u8dat: Read data
  19.   */
  20. static uint8_t DS18B20_ReadByte(void)
  21. {
  22.     uint8_t i;
  23.     uint8_t u8dat = 0;

  24.     for (i = 0; i < 8; i++)
  25.     {
  26.         u8dat >>= 1;
  27.         DQ = 0;                              //Start time slice
  28.         CLK_SysTickDelay(1);                 //Delay waiting
  29.         DQ = 1;                              //Ready to receive
  30.         CLK_SysTickDelay(1);                 //Reception delay

  31.         if (DQ) u8dat |= 0x80;               //Read data

  32.         CLK_SysTickDelay(60);                //Waiting for the end of time
  33.     }

  34.     return u8dat;
  35. }


  36. /**
  37.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Write 1 byte of data to the DS18B20
  38.   * @param  u8dat            Write data
  39.   * [url=home.php?mod=space&uid=266161]@return[/url] None
  40.   */
  41. static void DS18B20_WriteByte(uint8_t u8dat)
  42. {
  43.     uint8_t i;

  44.     for (i = 0; i < 8; i++)
  45.     {
  46.         DQ = 0;                              //Start time slice
  47.         CLK_SysTickDelay(1);                 //Delay waiting

  48.         if (u8dat & 0x01) DQ = 1;            //Send data

  49.         CLK_SysTickDelay(60);                //Waiting for the end of time
  50.         DQ = 1;                              //Restore data line
  51.         CLK_SysTickDelay(1);                 //Recovery delay
  52.         u8dat >>= 1;
  53.     }
  54. }
我们注意到一共有4种时长的延时,1us,60us,420us,480us
1us简单,我们引入头文件 #include<intrins.h>  //包含_nop_()函数定义的头文件,如果不包含这个,可能会被编译器优化掉时长。
然后编写一个替换上面库函数的delay实现替换新唐BSP库函数的基于滴答定时器的延时
  1. void Delay(uint8_t i)
  2. {
  3.         while(i--) _nop_();
  4. }
经过测试,定义如上的延时函数可以在晶振12MHz的情况下给8051提供一个比例为10:1的us级别延时
即Delay(48) 为480us,Delay(42)为420us,Delay(6)约为60us。具体误差很小这里不再说明,大家根据自己的实际情况可以用示波器进行测量。
以下简单的C51程序为我这次测量时候写大家简单函数。
  1. #include<reg51.h>    //包含单片机寄存器的头文件
  2. #include<intrins.h>  //包含_nop_()函数定义的头文件

  3. #define uchar unsigned char
  4. #define uint unsigned int
  5. #define uint8_t unsigned char
  6. #define int16_t unsigned int


  7. sbit DQ=P1^0;

  8. void Delay(uint8_t i)
  9. {

  10.         while(i--) _nop_();
  11. }


  12. void main(void)
  13. {
  14.         while(1)
  15.         {
  16.                 DQ=1;
  17.                 Delay(6);
  18.                 DQ=0;
  19.                 Delay(6);

  20.         }
  21. }
效果如何呢?利用这个方法就是一次点亮了。为了验证这个想法,把我上古年间在大学生跳蚤市场买的二手51开发板都拉出来了。
63811630c7a593dc31.jpg

怎么样,学会了吗?
完成代码如下:
ds18b20.h
  1.       /************************************************************************
  2. 以下是DS18B20的操作程序
  3. ************************************************************************/
  4. sbit DQ=P1^0;


  5. #define  CMD_SKIP_ROM            0xCC
  6. #define  CMD_CONVERT_T           0x44
  7. #define  CMD_READ_SCRATCHPAD     0xBE


  8. #define uchar unsigned char
  9. #define uint unsigned int
  10. #define uint8_t unsigned char
  11. #define int16_t unsigned int


  12. static void DS18B20_Reset(void);
  13. static void DS18B20_WriteByte(uint8_t u8dat);
  14. static uint8_t DS18B20_ReadByte(void);


  15. void Delay(uint8_t i)
  16. {
  17.         while(i--) _nop_();
  18. }


  19. /**
  20.   * @brief  Read temperature from DS18B20
  21.   * @param  None
  22.   * @return  i16temp: temperature
  23.   */
  24. int16_t DS18B20_ReadTemperature(void)
  25. {
  26.     uint8_t  u8tempH, u8tempL;
  27.     int16_t  i16temp;

  28.     DS18B20_Reset();
  29.     DS18B20_WriteByte(CMD_SKIP_ROM);
  30.     DS18B20_WriteByte(CMD_CONVERT_T);

  31.     while (!DQ);                             //Waiting for conversion to complete

  32.     DS18B20_Reset();
  33.     DS18B20_WriteByte(CMD_SKIP_ROM);
  34.     DS18B20_WriteByte(CMD_READ_SCRATCHPAD);
  35.     u8tempL = DS18B20_ReadByte();            //Read temperature low byte
  36.     u8tempH = DS18B20_ReadByte();            //Read temperature high byte
  37.     i16temp = (u8tempH << 8) | u8tempL;

  38.     return (i16temp);
  39. }



  40. /**
  41.   * @brief  Reset the DS18B20 and check if the device is present
  42.   * @param  None
  43.   * @return None
  44.   */
  45. static void DS18B20_Reset(void)
  46. {
  47.     uint8_t i;
  48.     i = 1;

  49.     while (i)
  50.     {
  51.         DQ = 0;                              //Send a low level reset signal
  52.         Delay(48);               //Delay at least 480us
  53.         DQ = 1;                              //Release data line
  54.         Delay(6);                //Waiting for 60us
  55.         i = DQ;                              //Detect the presence of pulses
  56.         Delay(42);               //Waiting for the device to release the data line
  57.     }
  58. }


  59. /**
  60.   * @brief  Read 1 byte data from DS18B20
  61.   * @param  None
  62.   * @return u8dat: Read data
  63.   */
  64. static uint8_t DS18B20_ReadByte(void)
  65. {
  66.     uint8_t i;
  67.     uint8_t u8dat = 0;

  68.     for (i = 0; i < 8; i++)
  69.     {
  70.         u8dat >>= 1;
  71.         DQ = 0;                              //Start time slice
  72.         _nop_();                 //Delay waiting
  73.         DQ = 1;                              //Ready to receive
  74.         _nop_();                 //Reception delay

  75.         if (DQ) u8dat |= 0x80;               //Read data

  76.         Delay(6);                //Waiting for the end of time
  77.     }

  78.     return u8dat;
  79. }


  80. /**
  81.   * @brief  Write 1 byte of data to the DS18B20
  82.   * @param  u8dat            Write data
  83.   * @return None
  84.   */
  85. static void DS18B20_WriteByte(uint8_t u8dat)
  86. {
  87.     uint8_t i;

  88.     for (i = 0; i < 8; i++)
  89.     {
  90.         DQ = 0;                              //Start time slice
  91.         _nop_();                //Delay waiting

  92.         if (u8dat & 0x01) DQ = 1;            //Send data

  93.         Delay(6);                //Waiting for the end of time
  94.         DQ = 1;                              //Restore data line
  95.         _nop_();                 //Recovery delay
  96.         u8dat >>= 1;
  97.     }
  98. }
main.c
  1. /******************************************************************************************************************
  2. main.c 主文件
  3. *******************************************************************************************************************/
  4. #include<reg51.h>    //包含单片机寄存器的头文件
  5. #include<intrins.h>  //包含_nop_()函数定义的头文件
  6. #include"ds18b20.h"

  7.         

  8. uchar value[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //定义0~9编码的数组,后面只需要调用数组
  9. uchar choice[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};  //定义数码管管位置编码数组,调用数组即可点亮对应的字


  10. /*用于扫描显示的延时,延时越长闪烁越严重,此处小于100效果较好,大于100晃动时候可以隐隐约约感觉到闪烁*/
  11. void delay(void)      
  12.    {
  13.       uchar t;
  14.       for(t=0;t<50;t++);
  15.    }

  16. /*显示温度整数*/
  17. void DispLed_N(uint s)
  18.         {
  19. /*        因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
  20.                 P2=~choice[3];
  21.                 P0=value[s%10];
  22.                 delay();
  23.                 P2=~choice[4];
  24.                 P0=value[s/10];
  25.                 delay();
  26.         }
  27.         
  28.         
  29. /*显示温度小数*/
  30. void DispLed_D(uint s)
  31.         {
  32. /*        因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
  33.                 P2=~choice[0];
  34.                 P0=value[s%10];
  35.                 delay();
  36.                 P2=~choice[1];
  37.                 P0=value[s/10];
  38.                 delay();
  39.         }        
  40.         
  41. /*显示分割线*/
  42. void div(void)
  43.         {

  44.                 P2=~choice[2];
  45.                 P0=0xbf;
  46.                 delay();
  47.         }

  48. void main(void)
  49. {
  50.         float t=15.0;
  51.         while(1)
  52.         {  
  53.                 t = DS18B20_ReadTemperature() * 0.0625;
  54.                  DispLed_N((uint)(t));
  55.                 t=t-(uint)(t);
  56.                 t=t*100;
  57.                 DispLed_D((uint)(t));
  58.           div();
  59.         }

  60. }


Poisin, 发表于 2022-8-29 16:42 | 显示全部楼层
楼主skr skr
Bowclad 发表于 2022-9-14 20:57 | 显示全部楼层
这方法不错
 楼主| gaoyang9992006 发表于 2022-9-15 09:48 | 显示全部楼层

是的,这个方法可以轻松实现各种需要时间限制的时序通信操作,比如这种一线制的协议。
鹿鼎计 发表于 2022-9-16 13:52 | 显示全部楼层
合理利用工具可以达到事半功倍的效果
mutable 发表于 2022-10-2 14:28 | 显示全部楼层
这算是又一大作么
 楼主| gaoyang9992006 发表于 2022-10-3 19:48 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:如果你觉得我的分享或者答复还可以,请给我点赞,谢谢。

2053

主题

16414

帖子

222

粉丝
快速回复 在线客服 返回列表 返回顶部