蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析

目录

一、引言

DS18B20的原理图

单总线简介:

​编辑暂存器简介:

 DS18B20的温度转换与读取流程

二、代码配置

maic文件

疑问

关于不同格式化输出符号的使用  

为什么要rd_temperature()/16.0?

onewire.h文件

这个配置为什么要先读low,如果反过来读会怎么样?


一、引言

 DS18B20是单线接口数字温度传感器,测量范围是-55°C~+125°C,-10°C~+85°C的范围精度是±0.5°C,还是精度很高的呢。

DS18B20的原理图

外部结构长这样

符号说明
GND接地
DQ数据输入/输出引脚。当工作在寄生电源模式时用来提供电源。
VDD可选的VDD引脚。工作与寄生电源模式是VDD必须接地。

这是内部结构

 DS18B20包括很多东西,有寄生电源电路,64位ROM和单线接口电路、暂存器、EEPROM、8位CRC生成器和温度传感器。寄生电源电路可以实现外部电源供电和单线寄生供电,64位ROM中存放的48位序列号用于识别同一单线上连接的多个DS18B20,以实现多点测温。

单总线简介:


单总线是一种通用数据总线他只有一根通信线:DQ,单总线只需要一根通信线即可实现数据的双向传输。

单总线的具体时序:
初始化:

主机将总线拉低至少480us,然后释放总线,当DS18B20探测到I/O引脚上的上升沿侯,等待15~60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线

发送一位数据:

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

接收一位:

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

具体的单总线完整的操作时序如下:

温度变换:初始化→跳过ROM →开始温度变换:

温度读取:初始化→跳过ROM →读暂存器→连续的读操作

其中ROM命令如下:

暂存器简介:

其中的暂存器很重要,有九个字节,最上面的两个字节是温度低位和高位。如下图

在LSB,MSB中BIT15~BIT11是符号位,控制符号;BIT10~BIT4是整数位;BIT3~BIT0是小数位。

这是一些例子说明,前五位是符号位,5个都为0是正数,5个都为1是负数,其他的就按二进制,十六进制常规操作算。

 DS18B20的温度转换与读取流程

[1] 初始化总线
[2] 写入字节0xcc,跳过rom。
[3] 写入字节0x44,进行温度转换。
[4] 初始化总线
[5] 写入字节0xcc,跳过rom。
[6] 写入字节0xbe,读取高速暂存器。(将后面的high和low的值存放到这里面)
[7] 读取暂存器的第0字节,即温度数据的LSB(low)。
[8] 读取暂存器的第1字节,即温度数据的MSB(high)。
[9] 返回high+low的值
————————————————

二、代码配置

maic文件

#include "bsp_seg.h"
#include "Timer0.h"
#include "bsp_key.h"
#include "STDIO.H"
#include <STC15F2K60S2.H>
#include "bsp_init.h"
#include "bsp_led.h"
#include "bsp_1302.h"
#include "bsp_onewire.h"/* 函数声明 */
//三个主体循环,基本上不变
void	Key_Proc(void);//按键处理
void	Seg_Proc(void);//显示处理
void	Led_Proc(void);//LED处理/* 全局变量声明 */
//显示专用,基本上永远不变
unsigned char seg_buf[8];//放置字符串转换后的段码到数组
unsigned char seg_string[10];//放置字符串
unsigned char pos = 0;//中断显示专用
//LED显示专用,基本上永远不变
unsigned char ucLed;
//按键专用,基本上永远不变
unsigned char Key_Value;//读取按键的数值存储变量
unsigned char Key_Down,Key_Old;//按键和显示函数减速专用,基本上永远不变
unsigned int Key_Slow_Down;//按键减速
unsigned int Seg_Slow_Down;	//DS1302专用,当使用DS1302时,基本不变
unsigned char ucRtc[3] = {23,59,55};//设置RTC时间unsigned int ms_count;
unsigned char s_count;unsigned char Running_State;//记录运行状态void main()
{Cls_Peripheral();Timer0Init();		//1毫秒@12.000MHzEA = 1;Set_Rtc(ucRtc);//设置RTC时间,23-59-55while(1){Key_Proc();//按键处理Seg_Proc();//显示处理Led_Proc();}}/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 
{if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 10) Seg_Slow_Down = 0;	if(++ms_count == 1000) //记录·运行时间 {s_count++;ms_count = 0;}Seg_Disp(seg_buf,  pos);if(++pos ==8) pos = 0;Led_Disp(ucLed);//LED显示
}
/* Key_Proc */
void	Key_Proc(void)//按键处理,底层数据变更
{if(Key_Slow_Down) return;Key_Slow_Down = 1;Key_Value = Key_Read();//读取按键按下的编号Key_Down = Key_Value & (Key_Old ^ Key_Value);//^异或(0000^0101)= 0101   0101 & 0101 = 0101//如果按键发生了下降沿的变化,输出结果和本次按键数值相同//^异或(0101^0101)= 0000   0101 & 0000 = 0000//如果按键发生了下降沿的变化,输出结果和本次按键数值相同Key_Old = Key_Value;if(Key_Down)//如果捕捉到下降沿跳变{if(++Running_State == 3) Running_State = 0;//保证Running_State在0-2之间翻滚}}/* Seg_Proc */
//Seg_Proc,准备数码管要显示的内容,Seg_Tran把字符串转成数码管段码,存进seg_buf[]
void	Seg_Proc(void)//显示处理,显示信息生成
{if(Seg_Slow_Down) return;Seg_Slow_Down = 1;switch(Running_State){case 0://读取18B20的数值	//seg_string是一个字符数组,理解为“数码管要显示的文字内容”sprintf(seg_string, "----%04.2f",rd_temperature()/16.0);//这个代码的效果是当ucRtc是[23,59,55],seg_string =“23-59-55”break;%d%2d%02d%2.2f%02.2fcase 1:Read_RTC(ucRtc);//读取1302内部	//seg_string是一个字符数组,理解为“数码管要显示的文字内容”sprintf(seg_string, "%02d-%02d-%02d",(unsigned int)ucRtc[0],(unsigned int)ucRtc[1],(unsigned int)ucRtc[2]);//这个代码的效果是当ucRtc是[23,59,55],seg_string =“23-59-55”break;case 2:sprintf(seg_string, "-----%03d",(unsigned int)s_count);break;}//seg_buf是一个存储段码的数组。因为数码管不能直接显示“字符”,它要的是“段码”-告诉它点亮哪几段Seg_Tran(seg_string,  seg_buf);//Seg_Tran作用——把字符串seg_string转换成段码,放入数组seg_buf中}void	Led_Proc(void)
{switch(Running_State){case 0:ucLed = 0x03;//让L1,L2两个亮		0000 0011break;case 1:ucLed =0x0c;//让L3,L4两个亮		0000 1100break;case 2:ucLed =0x30;//让L5,L6两个亮		0011 0000break;}}
//温度,时钟,系统运行时

疑问

sprintf(seg_string, "----%04.2f",rd_temperature()/16.0);
 break;  在这个代码里有"----%04.2f",为什么这里要这样写呢,引起我的思考

关于不同格式化输出符号的使用  

%d:输出一个十进制整数,无特别格式限制。
%2d:输出一个整数,占用至少2个字符宽度,右对齐。若数字不足2位,用空格补在左侧
%02d:输出一个整数,占用2 位宽度,不足的用 0 补左边。
%2.2f:整体宽度至少 2 位。小数点后保留2 位小数。整数部分和小数点也算在宽度里,但如果不够宽度会自动扩展。示例:printf("%2.2f", 3.1); → 输出:3.10。实际宽度超过 2 位(共 4 位),所以宽度不限制实际输出。
%02.2f::整体至少 2 位宽(但不包含小数位数限制时会自动扩展)。小数点后保留 2 位。前面不足时补 0(但一般无效) 。
示例:printf("%02.2f", 3.1); → 输出:3.10
实际上宽度会扩展以容纳整个数字,0补位不会生效,因为 3.10 就已经超出了 2 的宽度

为什么要rd_temperature()/16.0?

假设温度传感器(比如DS18B20)的测量范围是 -55°C 到 +125°C,但它内部存储温度数据时,把温度值放大了16倍,相当于把温度的小数部分用整数来记录。

onewire.h文件

#include "bsp_onewire.h"
#include <STC15F2K60S2.H>void Delay_OneWire(unsigned int t)  //STC89C52RC
{t *=12;while(t--);
}void Write_DS18B20(unsigned char dat)
{unsigned char i;for(i=0;i<8;i++){DQ = 0;DQ = dat&0x01;Delay_OneWire(5);DQ = 1;dat >>= 1;}Delay_OneWire(5);
}unsigned char Read_DS18B20(void)
{unsigned char i;unsigned char dat;for(i=0;i<8;i++){DQ = 0;dat >>= 1;DQ = 1;if(DQ){dat |= 0x80;}	    Delay_OneWire(5);}return dat;
}bit init_ds18b20(void)
{bit initflag = 0;DQ = 1;Delay_OneWire(12);DQ = 0;Delay_OneWire(80);DQ = 1;Delay_OneWire(10); initflag = DQ;     Delay_OneWire(5);return initflag;
}//unsigned char check_1[7] = {0};
unsigned int rd_temperature(void)
{unsigned char low,high;init_ds18b20();Write_DS18B20(0xcc);//Ìø¹ýROMWrite_DS18B20(0x44);//ת»»Î¶Èinit_ds18b20();Write_DS18B20(0xcc);//Ìø¹ýROMWrite_DS18B20(0xbe);//¶ÁȡζÈlow = Read_DS18B20();high = Read_DS18B20();//¶ÁÈ¡¸ßλreturn (high<<8)|low;
}

unsigned int rd_temperature(void)
{
    unsigned char low,high;
    
    init_ds18b20();
    Write_DS18B20(0xcc);//跳过ROM
    Write_DS18B20(0x44);//转换温度

    init_ds18b20();
    Write_DS18B20(0xcc);//跳过ROM
    Write_DS18B20(0xbe);//读取温度

    low = Read_DS18B20();
    high = Read_DS18B20();//读取高位
    
    return (high<<8)|low;
}
 low = Read_DS18B20();
   high = Read_DS18B20();//读取高位

这个配置为什么要先读low,如果反过来读会怎么样?

因为ds18b20中,是先读低位再读高位,并且这里将high左移8位是为了正确对齐两个字节的二进制位,确保高字节占据16位整数的高8位,低字节占据低8位。这都是DS18B20数据格式的强制要求。如果反过来读,那得到的数据就是错误的。

这是我配置的效果,显示了环境的温度,如果想让温度变高,可以拿手指捏住温度传感器[黑色帽子一样的,在右上角]大家可以试试。


        

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

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

相关文章

MySQL的并发事务问题及事务隔离级别

一、并发事务问题 1). 赃读&#xff1a;一个事务读到另外一个事务还没有提交的数据。 比如 B 读取到了 A 未提交的数据。 2). 不可重复读&#xff1a;一个事务先后读取同一条记录&#xff0c;但两次读取的数据不同&#xff0c;称之为不可重复读。 事务 A 两次读取同一条记录&…

密码学基础——SM4算法

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​专栏主页&#xff1a;密码学 &#x1f4cc; 【今日更新】&#x1f4cc; 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 ​编辑…

练习:对象数组 4

定义数组存储 4 个女朋友的对象。女朋友的属性&#xff1a;姓名、年龄、性别、爱好&#xff1b;要求1&#xff1a;计算出四个女朋友的平均年龄&#xff1b;要求2&#xff1a;统计年龄比平均值低的女朋友有几个&#xff1f;并把他们的所有信息打印出来。 代码&#xff1a; //对…

React Hooks 基础指南

React Hooks 是 React 16.8 引入的重要特性&#xff0c;它允许开发者在函数组件中使用状态和其他 React 特性。本文将详细介绍 6 个最常用的 React Hooks。 1. useState useState 是最常用的 Hook&#xff0c;用于在函数组件中添加 state。 import React, { useState } from…

【Python 算法零基础 4.排序 ⑥ 快速排序】

既有锦绣前程可奔赴&#xff0c;亦有往日岁月可回首 —— 25.5.25 选择排序回顾 ① 遍历数组&#xff1a;从索引 0 到 n-1&#xff08;n 为数组长度&#xff09;。 ② 每轮确定最小值&#xff1a;假设当前索引 i 为最小值索引 min_index。从 i1 到 n-1 遍历&#xff0c;若找到…

处理git没做修改,但是文件显示变更的情况

使用 TortoiseGit&#xff08;小乌龟 Git&#xff09; 时遇到 “文件内容没改&#xff0c;但显示为变更&#xff0c;提示有 n 行删除、n 行添加”&#xff0c;你可以按照以下步骤操作来排查并解决问题&#xff1a; ✅ 一、定位问题根源&#xff08;是否为行尾差异&#xff09;…

智慧货运飞船多维度可视化管控系统

图扑搭建智慧货运飞船可视化系统&#xff0c;借数字孪生技术&#xff0c;高精度复刻货运飞船外观、结构与运行场景。整合多维度数据&#xff0c;实时呈现飞行状态、设备参数等信息&#xff0c;助力直观洞察货运飞船运行逻辑&#xff0c;为航天运维、任务推演及决策提供数字化支…

maven微服务${revision}依赖打包无法识别

1、场景描述 我现在又一个微服务项目&#xff0c;父pom的版本&#xff0c;使用<properties>定义好&#xff0c;如下所示&#xff1a; <name>ypsx-finance-center</name> <artifactId>ypsx-finance</artifactId> <packaging>pom</pack…

详解代理型RAG与MCP服务器集成

检索增强型生成(RAG)将语言模型与外部知识检索相结合,让模型的回答基于最新的事实,而不仅仅是其训练数据呢。 RAG(高级别) 在 RAG 流程中,用户查询用于搜索知识库(通常通过向量数据库中的嵌入来实现),并将检索到的最相关文档“增强”到模型的提示中,以帮助生成事实…

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…

如何防止服务器被用于僵尸网络(Botnet)攻击 ?

防止服务器被用于僵尸网络&#xff08;Botnet&#xff09;攻击是关键的网络安全措施之一。僵尸网络是黑客利用大量被感染的计算机、服务器或物联网设备来发起攻击的网络。以下是关于如何防止服务器被用于僵尸网络攻击的技术文章&#xff1a; 防止服务器被用于僵尸网络&#xff…

贪心算法应用:硬币找零问题详解

贪心算法与硬币找零问题详解 贪心算法&#xff08;Greedy Algorithm&#xff09;在解决优化问题时表现出简洁高效的特点&#xff0c;尤其适用于特定结构的组合优化问题。本文将用2万字篇幅&#xff0c;深入探讨贪心算法在硬币找零问题中的应用&#xff0c;覆盖算法原理、正确性…

Java高级 | 【实验一】Springboot安装及测试 |最新

隶属文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 目录 一、SpringBoot的特点 二、Spring Boot安装及测试 &#xff08;一&#xff09;安装Intellij IDEA &#xff08;二&#xff09;安装MySQL &#xff08;三&#xff09;安装postma…

C# WPF 左右布局实现学习笔记(1)

开发流程视频&#xff1a; https://www.youtube.com/watch?vCkHyDYeImjY&ab_channelC%23DesignPro Git源码&#xff1a; GitHub - CSharpDesignPro/Page-Navigation-using-MVVM: WPF - Page Navigation using MVVM 1. 新建工程 新建WPF应用&#xff08;.NET Framework) 2.…

从零开始,学会上传,更新,维护github仓库

以下是一份从头到尾、覆盖安装、配置、创建仓库、上传项目到 GitHub 的完整教程。全程使用通用示例&#xff0c;不包含任何具体的仓库链接&#xff0c;仅供参考。 一、准备工作 1. 注册 GitHub 账号 打开浏览器&#xff0c;访问 GitHub 官网&#xff08;输入 “GitHub” 即可找…

使用 Docker Compose 从零部署 TeamCity + PostgreSQL(详细新手教程)

JetBrains TeamCity 是一款专业的持续集成&#xff08;CI&#xff09;服务器工具&#xff0c;支持各种编程语言和构建流程。本文将一步一步带你用 Docker 和 Docker Compose 快速部署 TeamCity&#xff0c;搭配 PostgreSQL 数据库&#xff0c;并确保 所有操作新手可跟着做。 一…

微软推出SQL Server 2025技术预览版,深化人工智能应用集成

在Build 2025 大会上&#xff0c;微软向开发者社区开放了SQL Server 2025的测试版本。该版本的技术改进主要涵盖人工智能功能集成、系统性能优化与开发工具链升级三个维度&#xff0c;展示了数据库管理系统在智能化演进方向上的重要进展。 智能数据处理功能更新 新版本的技术亮…

企业管理中,商业智能BI主要做哪些事情?

开门见山的告诉大家&#xff0c;在企业管理中商业智能BI 主要就做三件事&#xff1a;拉通数据、整合数据、数据可视化展现。 技术角度的商业智能BI 从技术的角度来讲&#xff0c;商业智能BI是一套完整的由数据仓库、查询报表、数据分析等组成的数据类技术解决方案。它有一个非…

openharmony5.0.0中kernel子系统编译构建流程概览(rk3568)

概述 在梳理openharmony对linux内核做了哪些更改时&#xff0c;简单梳理了下kernel部分的编译构建流程&#xff0c;并根据源码做了简单论证。分享出来&#xff0c;希望对大家有所帮助。 系统版本:openharmony5.0.0 开发板:dayu200 编译环境:ubuntu22 执行流程 在kernel\l…

考研系列—操作系统:冲刺笔记(4-5章)

目录 第四章 文件管理 1.真题总结文件管理方式 (1)目录文件的FCB就是“目录名-目录地址” (2)普通文件的FCB (3)区分索引文件、顺序文件、索引分配 (4)文件的物理结构 ①连续分配方式 ②链接分配 ③索引分配-使用索引表(一个文件对应一张索引表!!!) 计算考点:超级…