[DemoCode下载]

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

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

    while (i)
    {
        DQ = 0;                              //Send a low level reset signal
        CLK_SysTickDelay(480);               //Delay at least 480us
        DQ = 1;                              //Release data line
        CLK_SysTickDelay(60);                //Waiting for 60us
        i = DQ;                              //Detect the presence of pulses
        CLK_SysTickDelay(420);               //Waiting for the device to release the data line
    }
}


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

    for (i = 0; i < 8; i++)
    {
        u8dat >>= 1;
        DQ = 0;                              //Start time slice
        CLK_SysTickDelay(1);                 //Delay waiting
        DQ = 1;                              //Ready to receive
        CLK_SysTickDelay(1);                 //Reception delay

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

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

    return u8dat;
}


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

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

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

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

#define uchar unsigned char
#define uint unsigned int
#define uint8_t unsigned char
#define int16_t unsigned int


sbit DQ=P1^0;

void Delay(uint8_t i)
{

        while(i--) _nop_();
}


void main(void)
{
        while(1)
        {
                DQ=1;
                Delay(6);
                DQ=0;
                Delay(6);

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

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


#define  CMD_SKIP_ROM            0xCC
#define  CMD_CONVERT_T           0x44
#define  CMD_READ_SCRATCHPAD     0xBE


#define uchar unsigned char
#define uint unsigned int
#define uint8_t unsigned char
#define int16_t unsigned int


static void DS18B20_Reset(void);
static void DS18B20_WriteByte(uint8_t u8dat);
static uint8_t DS18B20_ReadByte(void);


void Delay(uint8_t i)
{
        while(i--) _nop_();
}


/**
  * @brief  Read temperature from DS18B20
  * @param  None
  * @return  i16temp: temperature
  */
int16_t DS18B20_ReadTemperature(void)
{
    uint8_t  u8tempH, u8tempL;
    int16_t  i16temp;

    DS18B20_Reset();
    DS18B20_WriteByte(CMD_SKIP_ROM);
    DS18B20_WriteByte(CMD_CONVERT_T);

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

    DS18B20_Reset();
    DS18B20_WriteByte(CMD_SKIP_ROM);
    DS18B20_WriteByte(CMD_READ_SCRATCHPAD);
    u8tempL = DS18B20_ReadByte();            //Read temperature low byte
    u8tempH = DS18B20_ReadByte();            //Read temperature high byte
    i16temp = (u8tempH << 8) | u8tempL;

    return (i16temp);
}



/**
  * @brief  Reset the DS18B20 and check if the device is present
  * @param  None
  * @return None
  */
static void DS18B20_Reset(void)
{
    uint8_t i;
    i = 1;

    while (i)
    {
        DQ = 0;                              //Send a low level reset signal
        Delay(48);               //Delay at least 480us
        DQ = 1;                              //Release data line
        Delay(6);                //Waiting for 60us
        i = DQ;                              //Detect the presence of pulses
        Delay(42);               //Waiting for the device to release the data line
    }
}


/**
  * @brief  Read 1 byte data from DS18B20
  * @param  None
  * @return u8dat: Read data
  */
static uint8_t DS18B20_ReadByte(void)
{
    uint8_t i;
    uint8_t u8dat = 0;

    for (i = 0; i < 8; i++)
    {
        u8dat >>= 1;
        DQ = 0;                              //Start time slice
        _nop_();                 //Delay waiting
        DQ = 1;                              //Ready to receive
        _nop_();                 //Reception delay

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

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

    return u8dat;
}


/**
  * @brief  Write 1 byte of data to the DS18B20
  * @param  u8dat            Write data
  * @return None
  */
static void DS18B20_WriteByte(uint8_t u8dat)
{
    uint8_t i;

    for (i = 0; i < 8; i++)
    {
        DQ = 0;                              //Start time slice
        _nop_();                //Delay waiting

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

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

        

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


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

/*显示温度整数*/
void DispLed_N(uint s)
        {
/*        因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
                P2=~choice[3];
                P0=value[s%10];
                delay();
                P2=~choice[4];
                P0=value[s/10];
                delay();
        }
        
        
/*显示温度小数*/
void DispLed_D(uint s)
        {
/*        因为经过PNP三极管驱动,因此低电平导通三极管,然后由集电极供电给共阳极数码管的阳极。*/
                P2=~choice[0];
                P0=value[s%10];
                delay();
                P2=~choice[1];
                P0=value[s/10];
                delay();
        }        
        
/*显示分割线*/
void div(void)
        {

                P2=~choice[2];
                P0=0xbf;
                delay();
        }

void main(void)
{
        float t=15.0;
        while(1)
        {  
                t = DS18B20_ReadTemperature() * 0.0625;
                 DispLed_N((uint)(t));
                t=t-(uint)(t);
                t=t*100;
                DispLed_D((uint)(t));
          div();
        }

}


使用特权

评论回复
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 | 显示全部楼层
mutable 发表于 2022-10-2 14:28
这算是又一大作么

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:西安公路研究院南京院
简介:主要工作从事监控网络与通信网络设计,以及从事基于嵌入式的通信与控制设备研发。擅长单片机嵌入式系统物联网设备开发,音频功放电路开发。

1889

主题

15608

帖子

197

粉丝