Demo14:DS18B20温度传感器

一、实验现象

        通过DS18B20温度传感器,数码管显示检测的温度值(温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃)。最后一位显示刷新温度次数。

二、核心知识点 - DS18B20时序

初始化时序

        单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us(该时间的时间范围可以从480 到960 微妙),以产生复位脉冲。接着主机释放总线,外部的上拉电阻将单总线拉高,延时15~60 us,并进入接收模式。接着DS18B20 拉低总线60~240 us,以产生低电平应答脉冲,若为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要480 微妙

写时序

        写时序包括写0 时序和写1 时序。所有写时序至少需要60us,且在2 次独立的写时序之间至少需要1us 的恢复时间,两种写时序均起始于主机拉低总线。写1 时序:主机输出低电平,延时2us,然后释放总线,延时60us。写0时序:主机输出低电平,延时60us,然后释放总线,延时2us

读时序

        单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2 次独立的读时序之间至少需要1us 的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us 之内采样总线状态

典型温度读取过程

复位→发SKIP ROM 命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送SKIP ROM 命令(0XCC)→发读存储器命令(0XBE)→连续读出两个字节数据(即温度)→结束。

三、项目结构

main.c

/**************************************************************************************
实验名称:DS18B20温度传感器实验
接线说明:
实验现象:
插上DS18B20温度传感器,数码管显示检测的温度值。最后一位显示刷新温度次数。
注意事项:
1、使用可编程12位(还有9~12)。温度是12位分辨率时,温度值转换数字需要750ms
2、ds18b20_read_temperture()应该超过24ms(超过肉眼24ms,看到数码管一闪一闪)
3、这里用500降低刷新温度函数,500*100us*5 = 250ms,  debug温度刷新周期2.8s 
4、_nop_()函数一个周期大概1us

***************************************************************************************/
#include "public.h"
#include "smg.h"
#include "ds18b20.h"
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{
    u8 i = 0;
    int temp_value;
    u8 temp_buf[6];
    u8 refreshCount = 0;

    ds18b20_init();//初始化DS18B20

    while (1)
    {
        if (i % 500 == 0)
        {
            //间隔一段时间读取温度值,间隔时间要大于温度传感器转换温度时间
            i = 1;//重置  否则等超过512溢出后又更新
            temp_value = ds18b20_read_temperture() * 10; //保留温度值小数后一位
            refreshCount++;
            if (refreshCount == 16)
            {
                refreshCount = 0;
            };
        }

        if (temp_value < 0) //负温度
        {
            temp_value = -temp_value;
            temp_buf[0] = 0x40; //显示负号
        }
        else
        {
            temp_buf[0] = 0x00; //不显示
        }
        temp_buf[1] = gsmg_code[temp_value / 1000]; //百位
        temp_buf[2] = gsmg_code[temp_value % 1000 / 100]; //十位
        temp_buf[3] = gsmg_code[temp_value % 1000 % 100 / 10] | 0x80; //个位+小数点
        temp_buf[4] = gsmg_code[temp_value % 1000 % 100 % 10]; //小数点后一位
		temp_buf[5]	= gsmg_code[refreshCount];//刷新次数
        smg_display(temp_buf, 3);
        i++;
    }
}

smg.c

#include "smg.h"

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
				0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : dat:要显示的数据
				   pos:从左开始第几个位置开始显示,范围1-8
* 输    出    	 : 无
*******************************************************************************/
void smg_display(u8 dat[],u8 pos)
{
	u8 i=0;
	u8 pos_temp=pos-1;

	for(i=pos_temp;i<8;i++)
	{
	   	switch(7-i)//位选
		{
			case 0: LSC=1;LSB=1;LSA=1;break;
			case 1: LSC=1;LSB=1;LSA=0;break;
			case 2: LSC=1;LSB=0;LSA=1;break;
			case 3: LSC=1;LSB=0;LSA=0;break;
			case 4: LSC=0;LSB=1;LSA=1;break;
			case 5: LSC=0;LSB=1;LSA=0;break;
			case 6: LSC=0;LSB=0;LSA=1;break;
			case 7: LSC=0;LSB=0;LSA=0;break;
		}
		SMG_A_DP_PORT=dat[i-pos_temp];//传送段选数据
		delay_10us(100);//延时一段时间,等待显示稳定
		SMG_A_DP_PORT=0x00;//消音
	}
}

smg.h

#ifndef _smg_H
#define _smg_H

#include "public.h"

#define SMG_A_DP_PORT	P0	//使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

extern u8 gsmg_code[17];

void smg_display(u8 dat[],u8 pos);

#endif

ds18b52.c

#include "ds18b20.h"
#include "intrins.h"

/*******************************************************************************
* 函 数 名         : ds18b20_reset
* 函数功能		   : 复位DS18B20  
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void ds18b20_reset()
{
	DS18B20_PORT=0;	//拉低DQ
	delay_10us(75);	//拉低750us
	DS18B20_PORT=1;	//DQ=1
	delay_10us(2);	//20US
}

/*******************************************************************************
* 函 数 名         : ds18b20_check
* 函数功能		   : 检测DS18B20是否存在
* 输    入         : 无
* 输    出         : 1:未检测到DS18B20的存在,0:存在
*******************************************************************************/
u8 ds18b20_check()
{
	u8 time_temp=0;

	while(DS18B20_PORT&&time_temp<20)	//等待DQ为低电平
	{
		time_temp++;
		delay_10us(1);	
	}
	if(time_temp>=20)return 1;	//如果超时则强制返回1
	else time_temp=0;
	while((!DS18B20_PORT)&&time_temp<20)	//等待DQ为高电平
	{
		time_temp++;
		delay_10us(1);
	}
	if(time_temp>=20)return 1;	//如果超时则强制返回1
	return 0;
}

/*******************************************************************************
* 函 数 名         : ds18b20_read_bit
* 函数功能		   : 从DS18B20读取一个位
* 输    入         : 无
* 输    出         : 1/0
*******************************************************************************/
u8 ds18b20_read_bit()
{
	u8 dat=0;
	
	DS18B20_PORT=0;
	_nop_();_nop_();
	DS18B20_PORT=1;	
	_nop_();_nop_(); //该段时间不能过长,必须在15us内读取数据
	if(DS18B20_PORT)dat=1;	//如果总线上为1则数据dat为1,否则为0
	else dat=0;
	delay_10us(5);
	return dat;
} 

/*******************************************************************************
* 函 数 名         : ds18b20_read_byte
* 函数功能		   : 从DS18B20读取一个字节
* 输    入         : 无
* 输    出         : 一个字节数据
*******************************************************************************/
u8 ds18b20_read_byte()
{
	u8 i=0;
	u8 dat=0;
	u8 temp=0;

	for(i=0;i<8;i++)//循环8次,每次读取一位,且先读低位再读高位
	{
		temp=ds18b20_read_bit();
		dat=(temp<<7)|(dat>>1);
	}
	return dat;	
}

/*******************************************************************************
* 函 数 名         : ds18b20_write_byte
* 函数功能		   : 写一个字节到DS18B20
* 输    入         : dat:要写入的字节
* 输    出         : 无
*******************************************************************************/
void ds18b20_write_byte(u8 dat)
{
	u8 i=0;
	u8 temp=0;

	for(i=0;i<8;i++)//循环8次,每次写一位,且先写低位再写高位
	{
		temp=dat&0x01;//选择低位准备写入
		dat>>=1;//将次高位移到低位
		if(temp)
		{
			DS18B20_PORT=0;
			_nop_();_nop_();
			DS18B20_PORT=1;	
			delay_10us(6);
		}
		else
		{
			DS18B20_PORT=0;
			delay_10us(6);
			DS18B20_PORT=1;
			_nop_();_nop_();	
		}	
	}	
}

/*******************************************************************************
* 函 数 名         : ds18b20_start
* 函数功能		   : 开始温度转换
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void ds18b20_start()
{
	ds18b20_reset();//复位
	ds18b20_check();//检查DS18B20
	ds18b20_write_byte(0xcc);//SKIP ROM
    ds18b20_write_byte(0x44);//转换命令	
}

/*******************************************************************************
* 函 数 名         : ds18b20_init
* 函数功能		   : 初始化DS18B20的IO口 DQ 同时检测DS的存在
* 输    入         : 无
* 输    出         : 1:不存在,0:存在
*******************************************************************************/ 
u8 ds18b20_init()
{
	ds18b20_reset();
	return ds18b20_check();	
}

/*******************************************************************************
* 函 数 名         : ds18b20_read_temperture
* 函数功能		   : 从ds18b20得到温度值
* 输    入         : 无
* 输    出         : 温度数据
*******************************************************************************/
float ds18b20_read_temperture()
{
	float temp;
	u8 dath=0;
	u8 datl=0;
	u16 value=0;
	//1、复位→发SKIP ROM 命令(0XCC)→发开始转换命令(0X44)→延时
	ds18b20_start();
	ds18b20_reset();//2、复位
	ds18b20_check();  //这步有必要吗?
	ds18b20_write_byte(0xcc);//3、发送SKIP ROM 命令(0XCC)
    ds18b20_write_byte(0xbe);//4、发读存储器命令(0XBE)
	//5 、连续读出两个字节数据(即温度)→结束
	datl=ds18b20_read_byte();//低字节
	dath=ds18b20_read_byte();//高字节
	value=(dath<<8)+datl;//合并为16位数据

	if((value&0xf800)==0xf800)//判断符号位,负温度
	{
		value=(~value)+1; //数据取反再加1
		temp=value*(-0.0625);//乘以精度	
	}
	else //正温度
	{
		temp=value*0.0625;	
	}
	return temp;
}

ds18b52.h

#ifndef _ds18b20_H
#define _ds18b20_H

#include "public.h"

//管脚定义
sbit DS18B20_PORT=P3^7;	//DS18B20数据口定义


//函数声明
u8 ds18b20_init();
float ds18b20_read_temperture();

#endif

public.c

#include "public.h"

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);
}

public.h

#ifndef _public_H
#define _public_H

#include "reg52.h"

typedef unsigned int u16;	//对系统默认数据类型进行重定义
typedef unsigned char u8;


void delay_10us(u16 ten_us);
void delay_ms(u16 ms);

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值