单片机
返回首页

51单片机系列——单总线通信方式——DS18B20温度检测的设计

2021-12-24 来源:eefocus

这个电路仿真的原理是因为:根据普中科技上的编程(一模一样),但用proteus7.8仿真的时候却仿真不出来,经过小编的一段时间的思考解决了用软件仿真DS18B20温度检测的电路。我先讲仿真电路图与源码分享给大家。


仿真电路图:
图1

temp.h //温度检测模块头文件


#ifndef __TEMP_H_

#define __TEMP_H_


#include

//---重定义关键词---//

#ifndef uchar

#define uchar unsigned char

#endif


#ifndef uint 

#define uint unsigned int

#endif


//--定义使用的IO口--//

sbit DSPORT=P3^7;


//--声明全局函数--//

void Delay1ms(uint );

uchar Ds18b20Init();

void Ds18b20WriteByte(uchar com);

uchar Ds18b20ReadByte();

void  Ds18b20ChangTemp();

void  Ds18b20ReadTempCom();

int Ds18b20ReadTemp();


#endif


temp.c //温度检测模块的驱动函数库文件


#include'temp.h'

#include


/*******************************************************************************

* 函 数 名         : Delay1ms

* 函数功能     : 延时函数

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

void Delay1ms(uint y)  

{

 uint x;

 for( ; y>0; y--)

 {

  for(x=110; x>0; x--);

 }

}

/*延时500us函数*/

void delay500us(void)   //误差 0us

{

    unsigned char a,b;

    for(b=71;b>0;b--)

        for(a=2;a>0;a--);

}

/*延时80us函数*/

void delay80us(void)   //误差 0us

{

    unsigned char a,b;

    for(b=11;b>0;b--)

        for(a=2;a>0;a--);

}

/*延时48us函数*/

void delay48us(void)   //误差 0us

{

    unsigned char a,b;

    for(b=9;b>0;b--)

        for(a=1;a>0;a--);

}

/*延时6us函数*/

void delay6us(void)   //误差 0us

{

    unsigned char a;

    for(a=1;a>0;a--);

    _nop_();  //if Keil,require use intrins.h

}



/*******************************************************************************

* 函 数 名         : Ds18b20Init

* 函数功能     : 初始化

* 输    入         : 无

* 输    出         : 初始化成功返回1,失败返回0

*******************************************************************************/

uchar Ds18b20Init()

{

 uchar i;

 DSPORT = 0;    //将总线拉低480us~960us

    delay500us();

 DSPORT = 1;   //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低

 i = 0;

 while(DSPORT) //等待DS18B20拉低总线

 {

  delay80us();

  i++;

  if(i>5)//等待>5MS

  {

   return 0;//初始化失败

  }

 

 }

 return 1;//初始化成功

}


/*******************************************************************************

* 函 数 名         : Ds18b20WriteByte

* 函数功能     : 向18B20写入一个字节

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

void Ds18b20WriteByte(uchar dat)

{

 uint i, j;

 for(j=0; j<8; j++)

 {

  DSPORT = 0;         //每写入一位数据之前先把总线拉低1us

  i++;

  DSPORT = dat & 0x01;  //然后写入一个数据,从最低位开始

  delay80us();

  DSPORT = 1; //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值

  dat >>= 1;

 }

}


/*******************************************************************************

* 函 数 名         : Ds18b20ReadByte

* 函数功能     : 读取一个字节

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

uchar Ds18b20ReadByte()

{

 uchar byte, bi;

 uint i, j; 

 for(j=8; j>0; j--)

 {

  DSPORT = 0;//先将总线拉低1us

  i++;

  DSPORT = 1;//然后释放总线

     delay6us();   //误差 0us

  bi = DSPORT;  //读取数据,从最低位开始读取

  /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/

  byte = (byte >> 1) | (bi << 7);        

  delay48us();   //误差 0us

  DSPORT = 1;

 }    

 return byte;

}


/*******************************************************************************

* 函 数 名         : Ds18b20ChangTemp

* 函数功能     : 让18b20开始转换温度

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

void  Ds18b20ChangTemp()

{

 Ds18b20Init();

 Delay1ms(1);

 Ds18b20WriteByte(0xcc);  //跳过ROM操作命令   

 Ds18b20WriteByte(0x44);     //温度转换命令

 //Delay1ms(100); //等待转换成功,而如果你是一直刷着的话,就不用这个延时了  

}


/*******************************************************************************

* 函 数 名         : Ds18b20ReadTempCom

* 函数功能     : 发送读取温度命令

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

void  Ds18b20ReadTempCom()

 Ds18b20Init();

 Delay1ms(1);

 Ds18b20WriteByte(0xcc);  //跳过ROM操作命令

 Ds18b20WriteByte(0xbe);  //发送读取温度命令

}


/*******************************************************************************

* 函 数 名         : Ds18b20ReadTemp

* 函数功能     : 读取温度

* 输    入         : 无

* 输    出         : 无

*******************************************************************************/

int Ds18b20ReadTemp()

{

 int temp = 0;

 uchar tmh, tml;

 Ds18b20ChangTemp();     //先写入转换命令

 Ds18b20ReadTempCom();   //然后等待转换完后发送读取温度命令

 tml = Ds18b20ReadByte();  //读取温度值共16位,先读低字节

 tmh = Ds18b20ReadByte();  //再读高字节

 temp = tmh;

 temp <<= 8;

 temp |= tml;

 return temp;

}


main.c //主函数


/**************************************************************************************

*                DS18B20温度传感器实验              *

实现现象:下载程序后,在温度传感器接口处,按照丝印方向插好温度传感器,数码管就会显示

   检测的温度值,

注意事项:                      

***************************************************************************************/


#include 'reg52.h'    //此文件中定义了单片机的一些特殊功能寄存器

#include'temp.h' 


typedef unsigned int u16;   //对数据类型进行声明定义

typedef unsigned char u8;


sbit LSA=P2^2;

sbit LSB=P2^3;

sbit LSC=P2^4;


char num=0;

u8 DisplayData[8];

u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


/*******************************************************************************

* 函 数 名         : delay

* 函数功能     : 延时函数,i=1时,大约延时10us

*******************************************************************************/

void delay(u16 i)

{

 while(i--); 

}


/*******************************************************************************

* 函 数 名         : datapros()

* 函数功能     : 温度读取处理转换函数

* 输    入         : temp

* 输    出         : 无

*******************************************************************************/

void datapros(int temp)   

{

    float tp;  

 if(temp< 0)    //当温度值为负数

   {

  DisplayData[0] = 0x40;    //   -

  //因为读取的温度是实际温度的补码,所以减1,再取反求出原码

  temp=temp-1;

  temp=~temp;

  tp=temp;

  temp=tp*0.0625*100+0.5; 

  //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点

  //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就

  //算加上0.5,还是在小数点后面。

 

   }

  else

   {   

  DisplayData[0] = 0x00;

  tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量

  //如果温度是正的那么,那么正数的原码就是补码它本身

  temp=tp*0.0625*100+0.5; 

  //留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点

  //后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就

  //算加上0.5,还是在小数点后面。

 }                

 DisplayData[1] = smgduan[temp / 10000];

 DisplayData[2] = smgduan[temp % 10000 / 1000];

 DisplayData[3] = smgduan[temp % 1000 / 100] | 0x80;

 DisplayData[4] = smgduan[temp % 100 / 10];

 DisplayData[5] = smgduan[temp % 10];

}


/*******************************************************************************

* 函数名         :DigDisplay()

* 函数功能   :数码管显示函数

* 输入           : 无

* 输出           : 无

*******************************************************************************/

void DigDisplay()

{

 u8 i;

 for(i=0;i<6;i++)

 {

  switch(i)  //位选,选择点亮的数码管,

  {

   case(0):

    LSA=0;LSB=0;LSC=0; break;//显示第0位

   case(1):

    LSA=1;LSB=0;LSC=0; break;//显示第1位

   case(2):

    LSA=0;LSB=1;LSC=0; break;//显示第2位

   case(3):

    LSA=1;LSB=1;LSC=0; break;//显示第3位

   case(4):

    LSA=0;LSB=0;LSC=1; break;//显示第4位

   case(5):

    LSA=1;LSB=0;LSC=1; break;//显示第5位 

  }

  P0=DisplayData[5-i];//发送数据

  delay(100); //间隔一段时间扫描 

  P0=0x00;//消隐

 }  

}


/*******************************************************************************

* 函 数 名       : main

* 函数功能   : 主函数

* 输    入       : 无

* 输    出      : 无

*******************************************************************************/

void main()

 while(1)

 {

  datapros(Ds18b20ReadTemp());  //数据处理函数

  DigDisplay();//数码管显示函数  

 }  

}


仿真后的结果:下图分别是显示正数/负数温度:

图2
图3

为什么用普中科技的程序在仿真软件上显示的结果就不理想呢?
小编经过反复的软件仿真验证发现:软件仿真时对时序的要求极高,例如在编程DS18B20的读写函数和初始化函数时,它们的时序应满足下图:
图4
图5
图6

从三张图中看出需要延时函数的处理。


**结论:**普中科技在编写读写和初始化函数时,延时大都通过while(i){i–;}或几个i++,来完成延时的,如果你尝试使用一下Debug调试一下,会发现这种延时并不准确,相差还很大。在硬件实战时这种不准确的延时也许影响不大(有时候可能还需要这样的做)。

但在软件仿真时,不准确的延时是绝对不允许的。


解决延时不准确的方法:建议使用“单片机小精灵v1.3完美破解”软件来实现编写精确的延时函数,在编程初始化和读写函数时采用调用延时函数的方式,就可以解决这个问题啦。


**补充:**其他单总线通信方式的还有:

图7

以上这些是小编学习时遇到的问题及最后的解决方法,希望对大家有所帮助,如果发现有不对的地方请指出。

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 用NE555制作定时器

    相关电子头条文章