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

一、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或者1delay60us();           //凑够至少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.mzph.cn/pingmian/58185.shtml

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

相关文章

STM32应用详解(12)使用I2C的main函数例程

文章目录 前言一、支持I2C总线的常见器件二、程序详解1.main函数2.读取传感器温度值的函数3.相关宏定义 前言 学习I2C总线。本文件主要分析main函数和LM75A驱动程序。了解器件驱动基本原理。 一、支持I2C总线的常见器件 (1)支持I2C总线的器件有很多&#xff0c;在开发板上支持…

redis详细教程(3.ZSet,Bitmap,HyperLogLog)

ZSet Redis 的 ZSet&#xff08;有序集合&#xff09;是一种特殊的数据类型&#xff0c;它允许存储一系列不重复的字符串元素&#xff0c;并为每个元素关联一个分数&#xff08;score&#xff09;。这个分数用于对集合中的元素进行排序。ZSet 的特点是&#xff1a; 唯一性&am…

Openlayers高级交互(11/20):显示带箭头的线段轨迹,箭头居中

本示例介绍如何在vue+openlayers项目中设置带有箭头的线段,箭头位于线段的中间位置。这里用到 forEachSegment 函数, 这个函数接受一个特征和一个回调函数作为参数。它遍历特征中的每个子线段,并调用回调函数传入子线段的中点坐标。 效果图 专栏名称内容介绍Openlayers基础…

Springboot整合spring-boot-starter-data-elasticsearch

前言 <font style"color:rgb(36, 41, 47);">spring-boot-starter-data-elasticsearch</font> 是 Spring Boot 提供的一个起始依赖&#xff0c;旨在简化与 Elasticsearch 交互的开发过程。它集成了 Spring Data Elasticsearch&#xff0c;提供了一套完整…

51c自动驾驶~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/11491137 #BEVWorld BEV潜在空间构建多模态世界模型&#xff0c;全面理解自动驾驶~一、引言 世界模型建模了有关环境的知识&#xff0c;其可以通过给定的条件对未来进行合理的想象。未来想象要求世界模型具有物理规律的理解…

秦时明月2搭建笔记

1.具体配置 数据库不修改&#xff0c;如果修改了&#xff0c;gm那边也要 2.数据库 3.上传配置文件出现问题 参考&#xff1a;对于测试时&#xff0c;错误信息 Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large-CSDN博客 4.启动tomcat&#x…

“冷”在日语里有这些表达-柯桥商务日语培训成人零基础学习

“冷”在日语里有这些表达: 寒い 这是最常用的表达,与中文的“冷”意思相同。 例句: 部屋が寒いから、エアコンをつけます。(房间冷,我去开空调。) 冷たい 形容物体表面温度较低,有“冷的”的意思。 例句: この水は冷たいですね。(这水挺冷的。) にぶい 指饮料不够冰镇…

安全芯片 OPTIGA TRUST M 使用介绍与示例(基于STM32裸机)

文章目录 目的资料索引硬件电路软件框架介绍数据存储框架移植框架使用 使用示例示例地址与硬件连接通讯测试功能测试 总结 目的 OPTIGA TRUST M 是英飞凌推出的安全芯片&#xff0c;芯片通提供了很多 slot &#xff0c;用于存放各类安全证书、密钥、用户数据等&#xff0c;内置…

Python: Print Table on console

# encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看&#xff1a; # 描述&#xff1a; # Author : geovindu,Geovin Du 涂聚文. # IDE : PyCharm 2023.1 python 3.11 # OS : windows 10 # Datetime : 2024/10/28 22:08 # User : geo…

Midjourney中文版:激发无限创意的艺术之旅

在数字化时代&#xff0c;艺术创作已不再受限于传统工具与技巧的束缚。Midjourney中文版&#xff0c;作为一款专为国内用户打造的智能艺术平台&#xff0c;正以超凡的智能算法和丰富的功能&#xff0c;引领每一位创作者踏上一场前所未有的艺术之旅。 Midjourney AI超强绘画 (原…

OpenHarmony鸿蒙应用开发 | 如何使用vsCode配置cangjie(仓颉)插件编程

前沿 余承东余总&#xff08;余大嘴&#xff09;在2024年10月21日鸿蒙【原生鸿蒙之夜暨华为全场景新品发布会】现场说&#xff0c;cangjie会成为鸿蒙下一代的编程语言&#xff0c;为开发者提供更强大的编程能力&#xff0c;让开发者在鸿蒙设备上实现更多创意。目前cangjie正处…

海亮科技亮相第84届中国教装展 尽显生于校园 长于校园教育基因

10月25日&#xff0c;第84届中国教育装备展示会&#xff08;以下简称“教装展”&#xff09;在昆明滇池国际会展中心开幕。作为国内教育装备领域规模最大、影响最广的专业展会&#xff0c;本届教装展以“数字赋能教育&#xff0c;创新引领未来”为主题&#xff0c;为教育领域新…

相识redis

一、Redis简介 什么是redis&#xff1f; Redis&#xff08;全称为Remote Dictionary Server&#xff09;是一个开源的非关系性数据库用于存储键值对&#xff0c;主要用于数据存储、缓存和消息队列方面&#xff0c;相传redis的初心是做消息队列起家但有心栽花花不开&#xff0…

WPF+MVVM案例实战(一)- 设备状态LED灯变化实现

文章目录 1、项目创建2、UI界面布局1. MainWindow.xaml2、颜色转换器实现2.MainViewModel.cs 代码实现 3、运行效果4.源代码下载 1、项目创建 打开 VS2022 &#xff0c;新建项目 Wpf_Examples&#xff0c;创建各层级文件夹&#xff0c;安装 CommunityToolkit.Mvvm 和 Microsof…

react18中react-thunk实现公共数据仓库的异步操作

redux及react-redux都只能实现数据的同步修改更新&#xff0c;有点类似于vue中的mutation&#xff0c;只能做同步操作&#xff0c;异步的话不用actions来实现。由于在项目始终不可避免要实现的异步数据的更新&#xff0c;这明显不够用了。是时候引入我们的异步中间件redux-thun…

长思维PRM

思维链 除了常见的连接词如 “and” 和 “so” 之外。还出现了"wait", Alternatively" 等特殊的关键词&#xff0c;"像 “wait” (表示反思)和 “Alternatively”(表示探索不同路径) 这样的关键词是模型能够进行反思和自我纠正的重要指标 迭代式问题解决&…

【PLC编程】GX Works报未能正常执行RUN中写入解决办法

在PLC编程中按F4转换时报未正常执行RUN中写入&#xff0c;可能是程序不一致。 选择工具->选项 选择RUN中写入。去除转换&#xff08;编译&#xff09;中执行RUN中写入 点击确定后&#xff0c;就不会再报此问题。F4转换也能正常转换了。

Java Lock CountDownLatch 总结

前言 相关系列 《Java & Lock & 目录》&#xff08;持续更新&#xff09;《Java & Lock & CountDownLatch & 源码》&#xff08;学习过程/多有漏误/仅作参考/不再更新&#xff09;《Java & Lock & CountDownLatch & 总结》&#xff08;学习总…

Selenium4自动化测试常用函数总结,各种场景操作实战

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 seleninum作为自动化测试的工具&#xff0c;自然是提供了很多自动化操作的函数&#xff0c;下面列举下比较常用的函数&#xff0c;更多可见官方文档&#xff1a;…

网络安全的重要性及实践指南

网络安全的重要性及实践指南 前言 随着信息技术的快速发展&#xff0c;网络安全问题日益突出。无论是个人用户还是企业组织&#xff0c;网络安全都成为了必须重视的问题。本文将深入探讨网络安全的重要性、常见威胁、以及如何有效地保护网络安全。 一、网络安全的重要性 1.…