JackCin's blog JackCin's blog
首页
  • 页面

    • Html
    • CSS
  • 核心

    • JavaScript基础
    • JavaScript高级
  • 框架

    • Vue
  • jQuery
  • Node
  • Ajax
Linux
  • 操作系统
  • 数据结构与算法
  • 51单片机
  • CC2530
  • 网站
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

JackCin

前端小菜鸡(✪ω✪)
首页
  • 页面

    • Html
    • CSS
  • 核心

    • JavaScript基础
    • JavaScript高级
  • 框架

    • Vue
  • jQuery
  • Node
  • Ajax
Linux
  • 操作系统
  • 数据结构与算法
  • 51单片机
  • CC2530
  • 网站
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 51单片机

    • 51单片机及补充知识
    • LED
    • 独立按键
    • 数码管
    • LCD1602液晶显示器
    • 矩阵按键
    • 定时器
    • 串口
    • LED点阵屏
    • 蜂鸣器
    • AT24C02存储器
    • AD与DA
    • DS18B20温度传感器
      • 一、DS18B20
        • 1、引脚及其电路
        • 2、内部结构框架图
        • 3、储存器结构
      • 二、单总线
        • 1、单总线介绍
        • 2、电路规范
      • 三、时序结构
        • 1、初始化
        • 2、发送一位(Bit)
        • 3、接收一位(Bit)
        • 4、接收和发送一个字节
      • 四、操作流程
      • 五、数据帧及温度存储格式
      • 六、DS18B20温度读取代码
    • DS1302时钟
    • LCD1602液晶显示屏
    • 红外遥控
    • 呼吸灯与直流电机调速(PWM)
  • 单片机
  • 51单片机
JackCin
2023-09-13
目录

DS18B20温度传感器

# DS18B20温度传感器

# 一、DS18B20

  • DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点
  • 测温范围:-55°C 到 +125°C
  • 通信接口:1-Wire(单总线)
  • 其它特征:可形成总线结构、内置温度报警功能、可寄生供电

img

# 1、引脚及其电路

引脚 功能
VDD 电源(3.0V ~ 5.5V)
GND 电源地
DQ 单总线接口

img

  • 下图为普中A2开发板的原理图

DS18B20

# 2、内部结构框架图

img

  • 64-BIT ROM:作为器件地址,用于总线通信的寻址
  • SCRATCHPAD(暂存器):用于总线的数据交互
  • EEPROM:用于保存温度触发阈值和配置参数
  • 左边是上拉电阻 (opens new window),下方是有电源时走的线路,上方是DQ单总线走的线路。先通过一个ROM寻址,相当于大门的功能,然后是内存控制,相当于管家,再到RAM关联的设备,这大概就是内部的结构,在图中都有说明。

# 3、储存器结构

img

# 二、单总线

# 1、单总线介绍

  • 单总线(1-Wire BUS)是由Dallas公司开发的一种通用数据总线
  • 一根通信线:DQ
  • 异步、半双工
  • 单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,还可以省去设备的VDD线路,此时,供电加通信只需要DQ和GND两根线

# 2、电路规范

  • 设备的DQ均要配置成开漏输出模式
  • DQ添加一个上拉电阻,阻值一般为4.7KΩ左右
  • 若此总线的从机采取寄生供电,则主机还应配一个强上拉输出电路

电源供电: img

寄生供电: img

# 三、时序结构

# 1、初始化

  • 初始化:主机将总线拉低至少480us,然后释放总线,等待15-60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线

img

/**
  * @brief  单总线初始化
  * @param  无
  * @retval 从机响应位,0为响应,1为未响应
  */

unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;  //初始化为1,保证能让主机将总线拉低
	OneWire_DQ=0;  //主机拉低总线
	i = 227;while (--i);  //延时500us
	OneWire_DQ=1;   //主机释放总线
	i = 29;while (--i);   //延时70us(释放总线需要时间,延时给予释放时间,同时释放完从机会拉低总线60~240us来响应从机)
	AckBit = OneWire_DQ;  //如果从机成功响应,那就会拉低,即AckBit=0
	i = 227;while (--i);  //延时500us

	return AckBit;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2、发送一位(Bit)

  • 发送一位:主机将总线拉低60—120us,然后释放总线,表示发送0;主机将总线拉低1~15us,然后释放总线,表示发送1。从机将在总线拉低30us后(典型值)读取电平,整个时间片应大于60us

img

/**
  * @brief  单总线发送一位
  * @param  Bit 要发送的位
  * @retval 无
  */
//发送相当于写入
void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	//注意:11.0592,执行一个空函数需要5us
	i = 4; while (--i); //延时10us(因为文档里说延时1~15us,所以我们取了个中间值10us)
	OneWire_DQ=Bit;  //我们把数据发送到总线,如果为0,则持续拉低,如果为1,表示释放
	i = 22;while (--i);  //延时50us(因为发送一位整个的时间片必须大于60us)
	//从机将在总线拉低30us后(典型值)读取电平,
	OneWire_DQ=1;  //无论之前发送过来的是1还是0,我们都将总线释放
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3、接收一位(Bit)

  • 接收一位:主机将总线拉低1~15us,然后释放总线,并在拉低后15us内读取总线电平(尽量贴近15us的末尾),读取为低电平则为接收0,读取为高电平则为接收1 ,整个时间片应大于60us

img

/**
  * @brief  单总线接收一位
  * @param  无
  * @retval 读取的位
  */
//接收相当于读取
unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2; while (--i); //延时5us
	OneWire_DQ=1;  //主机释放总线,此时从机控制
	i = 2; while (--i); //延时5us
	Bit=OneWire_DQ;//如果从机之前读取的数据为0,则总线不会被释放,而是保持0(被从机拉低),为1,则总线释放
	i = 22;while (--i); //延时50us
	
	return Bit;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 注:有些同学可能觉得读和写如此相似,单片机怎么去区分是读还是写呢?其实单片机默认为写入,相当于课堂上默认老师先说话一样,然后给出相应的指令,才能读取,相当于老师让我们回答问题之后,学生才能说话一样。

# 4、接收和发送一个字节

  • 发送一个字节:连续调用8次发送一位的时序,依次发送一个字节的8位(低位在前)

img

  • 接收一个字节:连续调用8次接收一位的时序,依次接收一个字节的8位(低位在前)

img

/**
  * @brief  单总线发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void OneWire_SendByte(unsigned char Byte)	
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}


/**
  * @brief  单总线接收一个字节
  * @param  无
  * @retval 接收的一个字节
  */
unsigned char OneWire_ReceiveByte(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}

	return Byte;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 四、操作流程

  • 初始化:从机复位,主机判断从机是否响应
  • ROM操作:ROM指令+本指令需要的读写操作
  • 功能操作:功能指令+本指令需要的读写操作

img

# 五、数据帧及温度存储格式

img

  • DS18B20.c
#include <REGX52.H>
#include "OneWire.h"

#define DS18B20_SKIP_ROM  0xCC
#define	DS18B20_CONVERT_T  0x44
#define DS18B20_READ_SCRATCHPAD  0xBE


/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

/**
  * @brief  DS18B20读取温度
  * @param  无
  * @retval 温度数值
  */
float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;
	int Temp;
	float T;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB; 
	T=Temp/16.0;  //因为TLSB最低位是从2^-4开始,所以需要除以16

	return T;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  • 温度存储格式

img

img

以补码的形式存储,便于计算机进行计算。计算转换的过程如下所示:

img

# 六、DS18B20温度读取代码

// OneWire.c
#include <REGX52.H>
 
//DQ引脚定义
sbit OneWire_DQ=P3^7;
 
/**
  * @brief  单总线初始化
  * @param  无
  * @retval 从机响应位,0为响应,1为未响应
  */
unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 227;while (--i);		//@11.0592MHz Delay 500us
	OneWire_DQ=1; //释放
	i = 34;while (--i);			//Delay 80us
	AckBit=OneWire_DQ;		// 应答
	i = 227;while (--i);		//Delay 500us
	return AckBit;
}
 
/**
  * @brief  单总线发送一位
  * @param  Bit 要发送的位
  * @retval 无
  */
void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	i = 3;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 22;while (--i);			//Delay 50us
	OneWire_DQ=1;
}
 
/**
  * @brief  单总线接收一位
  * @param  无
  * @retval 读取的位
  */
unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2;while (--i);			//Delay 6us
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 6us
	Bit=OneWire_DQ;
	i = 22;while (--i);			//Delay 50us
	return Bit;
}
 
/**
  * @brief  单总线发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}
 
/**
  * @brief  单总线接收一个字节
  * @param  无
  * @retval 接收的一个字节
  */
unsigned char OneWire_ReceiveByte(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}
	return Byte;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// DS18B20.c
#include <REGX52.H>
#include "OneWire.h"
 
//DS18B20指令
#define DS18B20_SKIP_ROM			0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD 	0xBE
 
/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}
 
/**
  * @brief  DS18B20读取温度
  * @param  无
  * @retval 温度数值
  */
float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;
	int Temp;
	float T;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0; 	// 右移4位,取小数
	return T;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
 
float T;
 
void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	LCD_Init();
	LCD_ShowString(1,1,"Temperature:");
	while(1)
	{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				
		{
			LCD_ShowChar(2,1,'-');	//显示负号
			T=-T;			//将温度变为正数
		}
		else				
		{
			LCD_ShowChar(2,1,'+');	//显示正号
		}
		LCD_ShowNum(2,2,T,3);		//显示温度整数部分
		LCD_ShowChar(2,5,'.');		
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示温度小数部分
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
编辑 (opens new window)
上次更新: 2023/09/13, 12:29:52
AD与DA
DS1302时钟

← AD与DA DS1302时钟→

最近更新
01
51单片机及补充知识
09-13
02
独立按键
09-13
03
LCD1602液晶显示器
09-13
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式