51单片机完全学习——DS18B20温度传感器

news2024/10/28 12:34:01

一、DS18B20数据手册解读

首先我们知道DS18B20使用的是单总线传输,默认情况下读出来的温度是12位的,我们这里只讨论外部电源供电这种情况。

有这张图片我们知道,12位温度的最小分辨率是10^-4次方,因此就是0.0625.我们只需要将最后读到的温度,乘以0.0625即可得到我们测量到的温度。

通过单总线端口访问DS18B20的协议是:首先进行初始化、ROM操作命令、存储器操作命令、执行/数据,这4步来完成的。接下来我们一步一步的来看

(1)初始化

首先我们需要知道,所有的执行都是从一个初始化序列开始的,我们需要控制总线先产生一个复位脉冲,一个最少保持480微秒的低电平信号,然后释放总线,进入到接收状态,当DS18B20检测到I/O引脚上的上升沿之后,DS18B20等待15~60微秒,然后发送一个存在脉冲,也就是一个60~240微秒的低电平信号。具体编程实现如下:我这里加了一些返回参数,用来保证初始化的成功

uchar ds18b20_init(void)
{
	uchar i = 0;
	DS18B20_BUS = 1;    //将数据线拉高方便产生下降沿
	_nop_();
	DS18B20_BUS = 0;    //产生复位脉冲
	delay500us();       //最短为480微秒的低电平信号
	DS18B20_BUS = 1;    //释放掉总线并进入接收状态
	_nop_();
	while (DS18B20_BUS) //循环检测ds18b20发送过来的存在信号
	{
		i++;
		delay20us();      //每20微秒检测一次
		if (i > 7)
		{
			return 1;       //如果等了140微秒还没有就返回1,表示失败
		}
	}
	delay500us();       //如果没有失败,就延时至少480微秒,等待ds18b20将总线释放
	return 0;
}

(2)ROM操作命令

我们想要进行ROM指令的操作,就必须得有一定的方法,给DS18B20发送数据,和接收数据。接下来我们先实现DS18B20对于一个字节数据的发送和接收。我们首先来看发送函数,也就是给DS18B20写数据:

我们主要是根据上面的时序图来进行程序的编写,首先先对时序图做一些解释:当主机把数据线从逻辑高电平拉高到逻辑低电平的时候,写时序开始,有两种写时序,一种是写0,一种是写1.所有的些时间时序必须最少持续60微秒,两个写周期之间至少间隔1微秒。数据线上的电平变低以后,DS18B20在15~60微秒的窗口内对数据线进行采样,如果线上是高电平就写1,如果线上是低电平就写0,我这里的编程思路是:首先将数据线拉低持续1个微秒,然后赶紧释放总线,然后将我们想要发送的0或者1放在数据线上,然后持续至少60微秒的延时。最后在释放总线,具体的编程实现如下:

//给ds18b20写入数据
void ds18b20_write(uchar cmd)
{
	uchar i = 0, temp = 0;
	for (i=0; i<8; i++)
	{
		DS18B20_BUS = 0;       //首先将总线拉低,产生写时序
		_nop_();               //延时一个微秒
		DS18B20_BUS = 1;       //释放总线
		temp = (cmd & 0x01);   
		DS18B20_BUS = temp;    //发送0或者1
		delay60us();           //凑够至少60微秒的时间
		DS18B20_BUS = 1;       //释放总线
		cmd >>= 1;             //连续两个写周期间隙应该大于1us
	}
}

接下来我们就需要进行读字节时序了,还是一样先来看时序图:

读时序和写时序差不都,只不过我们需要注意主机的采样时间,当主机把数据线从高电平拉到低电平时,读时序开始,数据线必须至少保持1微秒,然后我们就要将数据线释放掉,方便DS18B20传输数据,从DS18B20输出的数据在读时序开始后的15微秒内有效,也就是说我们必须在这个时间间隔内完成采样。所有的读时序都必须最少60微秒,两个读周期至少1微秒的恢复时间。具体编程实现如下:

//从ds18b20里面读取数据
uchar ds18b20_read(void)
{
	uchar date = 0, i = 0, temp = 0;
	for (i=0; i<8; i++)
	{
		DS18B20_BUS = 0;            //拉低总线产生读时序的起始信号
		_nop_();                    //产生1us的延时
		DS18B20_BUS = 1;            //释放掉总线
		delay6us();                 //延时6us 这里也可以是其他的延时只要保证15us以内
		temp = DS18B20_BUS;         //采集ds18b20上面的数据
		date = (date | (temp << i));//采集到的数据从低位到高位一次放好
		delay60us();                //等待ds18b20释放总线后,准备下一次的就收
	}
	return date;
}

当我们有了这两个函数之后我们就可以进行ROM指令的操作了。接下来我们来看一下,我们常用的ROM指令:一般来讲我们的设备上就只有一个DS18B20,也就是说,我们只需要一条指令,跳过ROM这一条指令就可以了,也就是发送cch就可以了。具体下图:

(3)存储器操作指令

我们一般也就用到 温度转换命令、读取暂存器命令。其他的不太需要:在我们发送出去读存储器的指令之后,我们只要连续的不停的读,他就会一直读到最后一个字节,也就是说当我们发送读存储器命令之后,我们读第一次就是再读,下面存储器映射表的字节0, 读第二次就是读字节1。如果我们只是想获取读到的温度值,我们只需要,发送完读,存储器命令之后读两次就可以了。

二、DS18B20读取温度

首先我们得知道,所有的操作都包含4步,1、初始化, 2、ROM操作指令,3、暂存器操作指令 4、读数据(这一步可以都很多次都可以)

首先我们需要给DS18B20发送一个温度转换的指令,具体编程如下:我这里发送完命令之后直接给他足够的时间,让他完成温度的转换。

//发送检测温度的命令
void ds18b20_change_temperature(void)
{
	ds18b20_init();        //首先进行初始化
	ds18b20_write(0xcc);   //发送ROM指令
  ds18b20_write(0x44);   //发送温度转换指令
	delay1s();             //等待温度转换完毕
}

 温度转换完成之后就是,读温度了,DS18B20将温度转换完毕后,他不会向我们主动发送,而是将转换完后的温度,放到暂存器里面,因此我们只需要都暂存器就可以了。具体代码实现如下:在使用的时候,我们只需要连续调用这两个函数就可以啦。

//读取转换完成的温度
//注意这里温度转换过程中将温度结果放大了1000倍
uint ds18b20_read_temperatur(void)
{
	uint temp = 0;
	uchar temp1 = 0, temp2 = 0;
	ds18b20_init();          //首先进行初始化
	ds18b20_write(0xcc);     //发送ROM指令
	ds18b20_write(0xbe);     //读取暂存器
	temp1 = ds18b20_read();	 //读取暂存器第0个字节    温度的低8位   
	temp2 = ds18b20_read();  //读取暂存器第1个字节    温度的高8位
    temp = ((temp2 << 8) | temp1);	
	temp = temp * 62.5;      //将温度进行转换
	return temp;
}

我这里还专门为这个读取温度的函数,写了一个串口发送函数,实现如下:需要注意串口发送一个字节的函数需要自己实现。

//串口发送温度专用函数
void uart_send_num1(uint num)
{
	uchar a[10] = 0, i = 0;
	do
	{
		a[i] = num % 10 + '0';
		num /= 10;
		a[i+1] = '\0';
		i++;
	}while (num);
	while (i--)
	{	
		uart_send_byte(a[i]);
		if (i == 3)
		{
			uart_send_byte('.');
		}
	}
	
}

三、总线上有两个DS18B20

我们前面讨论的是,总线上只有一个DS18B20的情况,接下来我们讨论总线上有2个DS18B20的情况,具体目标是让两个DS18B20能独立地采集温度。并将温度打印在串口:

首先我们需要知道我们手中的DS18B20内置ROM的唯一64位编码,具体实现如下:需要注意的是我们先一个一个的将DS18B20放到总线上然后运行下面的程序,这样我们就可以在串口上面看到这个DS18B20的唯一64位编码了。

	ds18b20_init();
	ds18b20_write(0x33);
	temp = ds18b20_read();
    uart_send_byte(temp);	
    temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);	
	temp = ds18b20_read();
    uart_send_byte(temp);

接下来我们就可以将2个DS18B20的总线连接到一起,然后通过ROM指令里面的匹配ROM,来查找我们需要查找的DS18B20,然后再和他进行通讯,发送温度转换命令,然后读取温度即可,具体实现如下:

        ds18b20_init();
	    ds18b20_write(0x55);
		ds18b20_write(0x28);
		ds18b20_write(0xaf);
		ds18b20_write(0x0d);
		ds18b20_write(0x85);
		ds18b20_write(0x00);
		ds18b20_write(0x00);
		ds18b20_write(0x00);
		ds18b20_write(0xd2);
		
		ds18b20_write(0x44);
	    delay1s();
	    temp = ds18b20_read_temperatur1();
		uart_send_byte('a');
	    uart_send_num1(temp);

	    ds18b20_init();
		ds18b20_write(0x55);
		ds18b20_write(0x28);
		ds18b20_write(0xb4);
		ds18b20_write(0xfc);
		ds18b20_write(0x43);
		ds18b20_write(0xd4);
		ds18b20_write(0xe1);
		ds18b20_write(0x3c);
		ds18b20_write(0x01);
		
		ds18b20_write(0x44);
	    delay1s();
	    temp = ds18b20_read_temperatur2();
		uart_send_byte('b');
	    uart_send_num1(temp);

 需要注意的是,在温度读取函数里面我们也必须针对不同的DS18B20有着不同的温度读取函数,我这里写的是原始的处理方式,以上的代码也可以简化,将每个DS18B20的64位编码放到一个数据里面,我们使用循环的方式发送就可以了。这里就不做进一步修改了,感兴趣的可以自己修改。


uint ds18b20_read_temperatur1(void)
{
	uint temp = 0;
	uchar temp1 = 0, temp2 = 0;
	ds18b20_init();          //首先进行初始化
	ds18b20_write(0x55);     //发送ROM指令
	ds18b20_write(0x28);
	ds18b20_write(0xaf);
	ds18b20_write(0x0d);
	ds18b20_write(0x85);
	ds18b20_write(0x00);
	ds18b20_write(0x00);
	ds18b20_write(0x00);
	ds18b20_write(0xd2);
	ds18b20_write(0xbe);     //读取暂存器
	temp1 = ds18b20_read();	 //读取暂存器第0个字节    温度的低8位   
	temp2 = ds18b20_read();  //读取暂存器第1个字节    温度的高8位
  temp = ((temp2 << 8) | temp1);	
	temp = temp * 62.5;      //将温度进行转换
	return temp;
}

uint ds18b20_read_temperatur2(void)
{
	uint temp = 0;
	uchar temp1 = 0, temp2 = 0;
	ds18b20_init();          //首先进行初始化
	ds18b20_write(0x55);     //发送ROM指令
	ds18b20_write(0x28);
	ds18b20_write(0xb4);
	ds18b20_write(0xfc);
	ds18b20_write(0x43);
	ds18b20_write(0xd4);
	ds18b20_write(0xe1);
	ds18b20_write(0x3c);
	ds18b20_write(0x01);
	ds18b20_write(0xbe);     //读取暂存器
	temp1 = ds18b20_read();	 //读取暂存器第0个字节    温度的低8位   
	temp2 = ds18b20_read();  //读取暂存器第1个字节    温度的高8位
  temp = ((temp2 << 8) | temp1);	
	temp = temp * 62.5;      //将温度进行转换
	return temp;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2225425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文阅读(二十三):Squeeze-and-Excitation Networks

文章目录 1.介绍2.原理3.代码4.SE模块的应用 论文&#xff1a;Squeeze-and-Excitation Networks   论文链接&#xff1a;Squeeze-and-Excitation Networks   代码链接&#xff1a;Github 1.介绍 卷积算子使网络能够在每一层的局部感受野中融合空间&#xff08;spatial&…

内容安全与系统构建加速,助力解决生成式AI时代的双重挑战

内容安全与系统构建加速&#xff0c;助力解决生成式AI时代的双重挑战 0. 前言1. PRCV 20241.1 大会简介1.2 生成式 Al 时代的内容安全与系统构建加速 2. 生成式 AI2.1 生成模型2.2 生成模型与判别模型的区别2.3 生成模型的发展 3. GAI 内容安全3.1 GAI 时代内容安全挑战3.2 图像…

Linux 进程间通信_匿名管道

1.程间通信目的 : 数据传输&#xff1a;一个进程需要将它的数据发送给另一个进程 资源共享&#xff1a;多个进程之间共享同样的资源。 通知事件&#xff1a;一个进程需要向另一个或一组进程发送消息&#xff0c;通知它&#xff08;它们&#xff09;发生了某种事件&#xff08;如…

Linux CentOS7下创建SFTP服务器

本文详细介绍了在Linux CentOS上部署安全文件传输协议&#xff08;SFTP&#xff09;服务器的全过程。SFTP基于SSH&#xff08;安全壳层协议&#xff09;提供文件传输服务&#xff0c;继承了SSH的安全特性&#xff0c;如数据加密、完整性验证和服务器认证等&#xff0c;确保数据…

信号与系统学习:周期信号的频谱

一、概念 1. 什么是频谱&#xff1f; 频谱描述了信号在不同频率上的能量分布对于一个周期信号&#xff0c;其频谱通常是离散的&#xff0c;由一系列离散的频率成分组成 2. 周期信号与傅里叶级数 周期信号可以用傅里叶级数展开&#xff0c;表示为无数个正弦和余弦&#xff0…

巡飞单机多旋翼无人机技术详解

巡飞单机多旋翼无人机技术是一种集成了多种先进技术的无人机系统&#xff0c;它具备自主飞行、长续航、高精度控制以及多任务负载能力等特点。以下是对巡飞单机多旋翼无人机技术的详细解析&#xff1a; 一、机架与结构设计 1.材料选择&#xff1a;为了确保无人机能够承载足够…

基于深度学习的图像修复系统设计与实现(PyQt5、CodeFormer ffhq-dataset数据集)

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

logback日志导入使用

1导入配置 <!-- 日志 &#xff0c; 会自动传递slf4j门面--> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version> </dependency>2 引入配置 Logback要求…

Synergy遇见的问题

1.两台设备无法ping通 首先两个设备是在同一个局域网中&#xff0c;但任然是无法ping通 问题所在&#xff1a;防火墙进行了隔离&#xff1b; 解决方法&#xff1a; &#xff08;1&#xff09;关闭防火墙 没有用过&#xff0c;个人感觉不怎么安全就没有使用&#xff1b; &am…

react18中的受控与非受控组件及ref的使用

受控与非受控组件 受控组件,基于修改 state 的值,修改组件内部的状态&#xff0c;来实现页面的更新&#xff0c;推荐使用 非受控组件&#xff0c;基于 ref 获取 dom 的值&#xff0c;来实现页面的更新,不推荐使用,偶尔特殊的场景会使用 给需要获取的元素设置 ref“xxx”,后期基…

一步一步从微信小程序获取asp.net Core API的数据

前面我们说过&#xff0c;如何使用微信小程序获取asp.net的数据&#xff0c;这里我们继续介绍如何获取asp.net core api的数据。两者之间还是有一些差别的。本篇博文旨在详细介绍如何一步一步从微信小程序获取asp.net Core API的数据。 文章目录 一、建立并了解asp.net core we…

Git 创建SSH秘钥

1、命令行输入 ssh-keygen -t rsa -b 4096 2、系统提示你“Enter a file in which to save the key”&#xff0c;直接按回车键 3、再提示你输入密码的时候直接按回车键&#xff0c;创建没有密码的SSH密钥 4、密钥对创建后&#xff0c;可以在自己电脑对应的 ~/.ssh 目录下找到…

vue 果蔬识别系统百度AI识别vue+springboot java开发、elementui+ echarts+ vant开发

编号&#xff1a;R03-果蔬识别系统 简介&#xff1a;vuespringboot百度AI实现的果蔬识别系统 版本&#xff1a;2025版 视频介绍&#xff1a; vuespringboot百度AI实现的果蔬识别系统前后端java开发&#xff0c;百度识别&#xff0c;带H5移动端&#xff0c;mysql数据库可视化 1 …

Unity编辑器制作多级下拉菜单

Unity编辑器下拉菜单 大家好&#xff0c;我是阿赵。   在Unity引擎里面编写工具插件&#xff0c;有时候会用到一些特殊的菜单形式&#xff0c;比如下拉选项。 通过下拉菜单&#xff0c;给用户选择不同的选项。   如果只是一层的下拉列表&#xff0c;可以用EditorGUILayout.…

西南大学软件专硕考研难度分析!

C哥专业提供——计软考研院校选择分析专业课备考指南规划 西南大学软件工程学硕近三年呈现出招生规模稳定、复试线稳中有升的特点。2024届实际录取8人&#xff0c;复试分数线305分&#xff0c;复试录取率67%&#xff0c;相比去年复试线略有下降但仍高于2022届&#xff0c;显示出…

Maven 项目构建打包,如何引入本地 Jar 包?

上一篇讲到 Maven 离线仓库的使用&#xff0c;反响不错很多人收藏&#xff0c;这一篇还是继续聊 Maven 。假如你发现某开源项目有个 bug 影响到自己的系统&#xff0c;但官方还没修复&#xff0c;自己定位到了本地修改打了包先应急用&#xff0c;那么如何在其他项目上使用该包&…

【动态规划】力扣198.打家劫舍

目录 一、题目二、思路1.递归2.递推 三、代码 一、题目 二、思路 1.递归 题目中指出不可以选相邻的房间&#xff0c;说明如果选了第 1 间&#xff0c;那么第 2 间一定不可以选&#xff0c;第 3 间房间可以选&#xff0c;也可以不选……假设是按照从第 1 间房间开始依次往后选…

【测试】——Fiddler入门

&#x1f4d6; 前言&#xff1a;本文介绍Fiddler&#xff0c;一个强大的HTTP协议调试代理工具。文章详细讲解了Fiddler的安装步骤、基础操作、抓包技巧以及模拟测试等内容。 目录 &#x1f552; 1. Fiddler基础介绍&#x1f558; 1.1 安装&#x1f558; 1.2 基础操作&#x1f5…

[oeasy]python038_ range函数_大小写字母的起止范围_start_stop

range函数_大小写字母的起止范围_start_stop 回忆上次内容 所有字符 都有序号 就连 空格 也不例外 空格 序号32是 print函数中 sep参数的 默认值 字符 在计算机中 用数字序号 来 存储表示 字符序号 有规律 a 对应 97b 对应 98c 对应 99 连续字母 对应 连续序号 似乎应该是 天经…

SOLID - 接口隔离原则(Interface Segregation Principle)

SOLID - 接口隔离原则&#xff08;Interface Segregation Principle) 定义 接口隔离原则&#xff08;Interface Segregation Principle&#xff0c;ISP&#xff09;是面向对象设计中的五个基本原则之一&#xff0c;通常缩写为SOLID中的I。这一原则由Robert C. Martin提出&…