嵌入式开发学习(STC51-13-温度传感器)

内容

通过DS18B20温度传感器,在数码管显示检测到的温度值;

DS18B20介绍

简介

DS18B20是由DALLAS半导体公司推出的一种的“一线总线(单总线)”接口的温度传感器;

与传统的热敏电阻等测温元件相比,它是一种新型的体积小、适用电压宽、与微处理器接口简单的数字化温度传感器;

特点

DS18B20温度传感器具有如下特点:

  • 适应电压范围更宽,电压范围:3.0~5.5V,在寄生电源方式下可由数据线供电;
  • 温范围-55℃~+125℃,在-10~+85℃时精度为±0.5℃;
  • 可编程的分辨率为9~12位,对应的可分辨温度分别为0.5℃、0.25℃、0.125℃和 0.0625℃,可实现高精度测温;
  • 在9位分辨率时最多在93.75ms内把温度转换为数字,12位分辨率时最多在750ms内把温度值转换为数字,速度更慢;
  • 测量结果直接输出数字温度信号,以"一根总线"串行传送给CPU,同时可传送CRC校验码,具有极强的抗干扰纠错能力;
  • 负压特性:电源极性接反时,芯片不会因发热而烧毁,但不能正常工作;

结构

DS18B20一共有三个管脚,当我们正对传感器切面(传感器型号字符那一面)时,传感器的管脚顺序是从左到右排列;

管脚1为GND,管脚2为数据DQ,管脚3为VDD;

如果把传感器插反,那么电源将短路,传感器就会发烫,很容易损坏,所以一定要注意传感器方向;

通常在开发板上都会标出传感器的凸起出,所以只需要把传感器凸起的方向对着开发板凸起方向插入即可;

DS18B20温度传感器的内部存储器包括一个高速的暂存器RAM和一个非易失性的可电擦除的EEPROM,后者存放高温度和低温度触发器TH、TL和配置寄存器;

配置寄存器是配置不同的位数来确定温度和数字的转化,配置寄存器结构如下:

TMR1R011111

低五位一直都是"1",TM是测试模式位,用于设置DS18B20在工作模式还是在测试模式,在DS18B20出厂时该位被设置为0,用户不需要去改动;

R1和R0用来设置DS18B20的精度(分辨率),可设置为9,10,11或12位,对应的分辨率温度是0.5℃,0.25℃,0.125℃和0.0625℃;

R0和R1配置如下图:
在这里插入图片描述
在初始状态下默认的精度是12位,即R0=1、R1=1;

高速暂存存储器由9个字节组成,其分配如下:
在这里插入图片描述
当温度转换命令(44H)发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节;

存储由两个字节组成,高字节的前5位是符号位S,单片机可通过单线接口读到该数据,读取时低位在前,高位在后,数据格式如下:
在这里插入图片描述
如果测得的温度大于0,这5位为‘0’,只要将测到的数值乘以0.0625(默认精度是12位)即可得到实际温度;
如果温度小于0,这5位为‘1’,测到的数值需要取反加1再乘以0.0625即可得到实际温度;

温度计算

温度与数据对应关系如下:
在这里插入图片描述
比如我们要计算+85度,数据输出十六进制是0X0550,因为高字节的高5位为0,表明检测的温度是正温度,0X0550对应的十进制为1360,将这个值乘以12位精度0.0625,所以可以得到+85度;

DS18B20使用

知道了怎么计算温度,接下来我们就来看看如何读取温度数据;

由于DS18B20是单总线器件,所有的单总线器件都要求采用严格的信号时序,以保证数据的完整性;

DS18B20时序包括如下几种:初始化时序、写(0和1)时序、 读(0和1)时序;

DS18B20发送所有的命令和数据都是字节的低位在前;

这里我们简单介绍这几个信号的时序:

初始化时序

初始化时序图如下:
在这里插入图片描述

单总线上的所有通信都是以初始化序列开始;

主机输出低电平,保持低电平时间至少480us(该时间的时间范围可以从480到960us),以产生复位脉冲;

接着主机释放总线,外部的上拉电阻将单总线拉高,延时15~60us,并进入接收模式;

接着DS18B20拉低总线60~240us,以产生低电平应答脉冲,若为低电平,还要做延时,其延时的时间从外部上拉电阻将单总线拉高算起最少要480us;

写时序

写时序图如下:
在这里插入图片描述
写时序包括写0时序和写1时序;

所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线;

写1时序:主机输出低电平,延时2us,然后释放总线,延时60us;

写0时序:主机输出低电平,延时60us,然后释放总线,延时2us;

读时序

读时序图如下:
在这里插入图片描述
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据;

所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间;

每个读时序都由主机发起,至少拉低总线1us;

主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态;

一般的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us;

完整过程

了解了单总线时序之后,我们来看看DS18B20的温度读取过程:
DS18B20的温度读取过程为:复位→发SKIP ROM命令(0XCC)→发开始转换命令(0X44)→延时→复位→发送SKIP ROM命令(0XCC)→发读存储器命令(0XBE)→连续读出两个字节数据(即温度)→结束;

原理图

在这里插入图片描述
由图可知,总线连接p37口,所以我们通过控制该io口的电位变化即可实现初始化以及读写时序;

思路

根据时序图编写初始化、读、写程序;(初始化包括复位和检测DS18B20是否存在)

编写检测DS18B20是否存在的程序(如果信号口一直为低电位,即判定为不存在);

按使用步骤,读取温度值,转换为十进制后,使其在数码管上显示;

编码

User

main.c

/** @Description: 通过DS18B20温度传感器,在数码管显示检测到的温度值*/
#include "public.h"
#include "smg.h"
#include "ds18b20.h"void main()
{u8 i = 0;int temp_value;u8 temp_buf[5];ds18b20_init(); // 初始化DS18B20while (1){i++;if (i % 50 == 0)								 // 间隔一段时间读取温度值,间隔时间要大于温度传感器转换温度时间(12位分辨率时转换时间为750ms)temp_value = ds18b20_read_temperture() * 10; // 保留温度值小数后一位if (temp_value < 0)								 // 负温度{temp_value = -temp_value;temp_buf[0] = 0x40; // 显示负号}elsetemp_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];		  // 小数点后一位smg_display(temp_buf, 4);}
}

Public

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

public.c

#include "public.h"/*** @description: 延时函数,ten_us=1时,大约延时10us* @param {u16} ten_us 延时倍数* @return {*}*/
void delay_10us(u16 ten_us)
{while (ten_us--);
}/**ms延时函数,ms=1时,大约延时1ms**** @param {u16} ms 延时倍数* @return {*}*/
void delay_ms(u16 ms)
{u16 i, j;for (i = ms; i > 0; i--)for (j = 110; j > 0; j--);
}

App/ds18b20

ds18b20.h

#ifndef _ds18b20_H
#define _ds18b20_H#include "public.h"// 管脚定义
sbit DS18B20_PORT = P3 ^ 7; // DS18B20数据口定义// 函数声明
u8 ds18b20_init(void);
float ds18b20_read_temperture(void);#endif

ds18b20.c

#include "ds18b20.h"
#include "intrins.h"/*** @description: 复位DS18B20* @return {*}*/
void ds18b20_reset(void)
{DS18B20_PORT = 0; // 拉低DQdelay_10us(75);	  // 拉低750usDS18B20_PORT = 1; // DQ=1delay_10us(2);	  // 20US
}/*** @description: 检测DS18B20是否存在* @return {u8} 1:未检测到DS18B20的存在,0:存在*/
u8 ds18b20_check(void)
{u8 time_temp = 0;while (DS18B20_PORT && time_temp < 20) // 等待DQ为低电平{time_temp++;delay_10us(1);}if (time_temp >= 20)return 1; // 如果超时则强制返回1elsetime_temp = 0;while ((!DS18B20_PORT) && time_temp < 20) // 等待DQ为高电平{time_temp++;delay_10us(1);}if (time_temp >= 20)return 1; // 如果超时则强制返回1return 0;
}/*** @description: 从DS18B20读取一个位* @return {u8} 1/0*/
u8 ds18b20_read_bit(void)
{u8 dat = 0;DS18B20_PORT = 0;_nop_();_nop_();DS18B20_PORT = 1;_nop_();_nop_(); // 该段时间不能过长,必须在15us内读取数据if (DS18B20_PORT)dat = 1; // 如果总线上为1则数据dat为1,否则为0elsedat = 0;delay_10us(5);return dat;
}/*** @description: 从DS18B20读取一个字节* @return {u8} 一个字节数据*/
u8 ds18b20_read_byte(void)
{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;
}/*** @description: 写一个字节到DS18B20* @param {u8} dat 要写入的字节* @return {*}*/
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_();}}
}/*** @description: 开始温度转换* @return {*}*/
void ds18b20_start(void)
{ds18b20_reset();		  // 复位ds18b20_check();		  // 检查DS18B20ds18b20_write_byte(0xcc); // SKIP ROMds18b20_write_byte(0x44); // 转换命令
}/*** @description: 初始化DS18B20的IO口DQ,同时检测DS的存在* @return {u8} 1:不存在,0:存在*/
u8 ds18b20_init(void)
{ds18b20_reset();return ds18b20_check();
}/*** @description: 从ds18b20得到温度值* @return {float} 温度数据*/
float ds18b20_read_temperture(void)
{float temp;u8 dath = 0;u8 datl = 0;u16 value = 0;ds18b20_start(); // 开始转换ds18b20_reset(); // 复位ds18b20_check();ds18b20_write_byte(0xcc); // SKIP ROMds18b20_write_byte(0xbe); // 读存储器datl = ds18b20_read_byte(); // 低字节dath = ds18b20_read_byte(); // 高字节value = (dath << 8) + datl; // 合并为16位数据if ((value & 0xf800) == 0xf800) // 判断符号位,负温度{value = (~value) + 1;	  // 数据取反再加1temp = value * (-0.0625); // 乘以精度}else // 正温度{temp = value * 0.0625;}return temp;
}

App/smg

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]; // 使“共阴极数码管显示0~F的段码数据”这个变量定义为外部可用void smg_display(u8 dat[], u8 pos);#endif

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};/*** @description: 动态数码管显示函数* @param {u8} dat 要显示的数据* @param {u8} pos 从左开始第几个位置开始显示,范围1-8* @return {*}*/
void smg_display(u8 dat[], u8 pos)
{u8 i = 0;u8 pos_temp = pos - 1;for (i = pos_temp; i < 8; i++){switch (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;						  // 消影}
}

编译和结果

按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机

结果:显示检测到的温度
在这里插入图片描述

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

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

相关文章

关于Express 5

目录 1、概述 2、Express 5的变化 2.1 弃用或删除内容的列表&#xff1a; app.param&#xff08;name&#xff0c;fn&#xff09;名称中的前导冒号&#xff08;&#xff1a;&#xff09; app.del() app.param&#xff08;fn&#xff09; 复数方法名 res.json&#xff0…

Codeforces Round 890 (Div. 2) D. More Wrong(交互题 贪心/启发式 补写法)

题目 t(t<100)组样例&#xff0c;长为n(n<2000)的序列 交互题&#xff0c;每次你可以询问一个区间[l,r]的逆序对数&#xff0c;代价是 要在的代价内问出最大元素的位置&#xff0c;输出其位置 思路来源 neal Codeforces Round 890 (Div. 2) supported by Constructo…

Godot 4 源码分析 - Path2D与PathFollow2D

学习演示项目dodge_the_creeps&#xff0c;发现里面多了一个Path2D与PathFollow2D 研究GDScript代码发现&#xff0c;它主要用于随机生成Mob var mob_spawn_location get_node(^"MobPath/MobSpawnLocation")mob_spawn_location.progress randi()# Set the mobs dir…

【C语言】初阶完结练习题

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;C语言初阶 ✨其他专栏&#xff1a;代码小游戏 &#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论…

Misc取证学习

文章目录 Misc取证学习磁盘取证工具veracryto挂载fat文件DiskGenius 磁盘取证例题[RCTF2019]disk 磁盘[](https://ciphersaw.me/ctf-wiki/misc/disk-memory/introduction/#_2)内存取证工具volatility 内存取证例题数字取证赛题0x01.从内存中获取到用户admin的密码并且破解密码 …

如何搭建一个成功的家具小程序

家具行业近年来发展迅猛&#xff0c;越来越多的消费者开始选择在小程序商城上购买家具。因此&#xff0c;制作一款家具小程序商城成为了许多家具商家的必然选择。那么&#xff0c;如何制作一款个性化、功能齐全的家具小程序商城呢&#xff1f;下面将为大家介绍一种简单且高效的…

观察者模式(C++)

定义 定义对象间的一种一对多(变化)的依赖关系&#xff0c;以便当一个对象(Subject)的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并自动更新。 ——《设计模式》GoF 使用场景 一个对象&#xff08;目标对象&#xff09;的状态发生改变&#xff0c;所有的依赖对…

Pytorch Tutorial【Chapter 3. Simple Neural Network】

Pytorch Tutorial【Chapter 3. Simple Neural Network】 文章目录 Pytorch Tutorial【Chapter 3. Simple Neural Network】Chapter 3. Simple Neural Network3.1 Train Neural Network Procedure训练神经网络流程3.2 Build Neural Network Procedure 搭建神经网络3.3 Use Loss …

【LeetCode】24.两两交换链表中的节点

题目 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a…

SQL-每日一题【1193. 每月交易 I】

题目 Table: Transactions 编写一个 sql 查询来查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数及其总金额。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 1.题目要求我们查找每个月和每个国家/地区的事务数及其总金额、已批准的事务数…

实验笔记之——Windows下的Android环境开发搭建

好久一段时间没有进行Android开发了&#xff0c;最新在用的电脑也没有了Android studio了。为此&#xff0c;本博文记录一下最近重新搭建Android开发的过程。本博文仅为本人学习记录用&#xff08;**别看&#xff09; 目录 安装Android Studio以及JDK JDK Android Studiio …

Java并发系列之七:ConcurrentHashMap

回顾HashMap 既然说到HashMap了&#xff0c;那么我们就先来简单总结一下HashMap的重点。 1.基本结构 HashMap存储的是存在映射关系的键值对&#xff0c;存储在被称为哈希表(数组链表/红黑树)的数据结构中。通过计算key的hashCode值来确定键值对在数组中的位置&#xff0c;假…

【机器学习】西瓜书学习心得及课后习题参考答案—第5章神经网络

笔记心得 5.1神经元模型——这是神经网络中最基本的成分。 5.2感知机与多层网络——由简单的感知机循序渐进引出多层前馈神经网络。 5.3误差逆传播算法——BP算法&#xff0c;迄今最成功的神经网络学习算法。算法如下&#xff08;公式参考西瓜书&#xff09; 停止条件与缓解…

Laravel 框架路由参数.重定向.视图回退.当前路由.单行为 ②

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; THINK PHP &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

Redis压缩列表

区分一下 3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表 3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的…

【C++】深入浅出STL之vector类

文章篇幅较长&#xff0c;越3万余字&#xff0c;建议电脑端访问 文章目录 一、前言二、vector的介绍及使用1、vector的介绍2、常用接口细述1&#xff09;vector类对象的默认成员函数① 构造函数② 拷贝构造③ 赋值重载 2&#xff09;vector类对象的访问及遍历操作① operator[]…

学习左耳听风栏目90天——第一天 1-90(学习左耳朵耗子的工匠精神,对技术的热爱)【洞悉技术的本质,享受科技的乐趣】

洞悉技术的本质&#xff0c;享受科技的乐趣 第一篇&#xff0c;我的感受就是 耗叔是一个热爱技术&#xff0c;可以通过代码找到快乐的技术人。 作为it从业者&#xff0c;我们如何可以通过代码找到快乐呢&#xff1f;这是一个问题&#xff1f; 至少目前&#xff0c;我还没有这种…

Qt之C++

Qt之C 类的定义 C语言的灵魂是指针 C的灵魂是类&#xff0c;类可以看出C语言结构体的升级版&#xff0c;类的成员可以是变量&#xff0c;也可是函数。 class Box { public://确定类成员的访问属性double length;//长double breadth;//宽度double heigth;//高度 };定义对象 …

TestNG中实现多线程并行,提速用例的执行时间

TestNG是一个开源自动化测试工具&#xff0c;TestNG源于Junit&#xff0c;最初用来做单元测试&#xff0c;可支持异常测试&#xff0c;忽略测试&#xff0c;超时测试&#xff0c;参数化测试和依赖测试。 除了单元测试&#xff0c;TestNG的强大功能让他在接口和UI自动化中也占有…

UE4 Cesium 学习笔记

Cesium中CesiumGeoreference的原点Orgin&#xff0c;设置到新的位置上过后&#xff0c;将FloatingPawn的Translation全改为0&#xff0c;才能到对应的目标点上去 在该位置可以修改整体建筑的材质 防止刚运行的时候&#xff0c;人物就掉下场景之下&#xff0c;controller控制的…