嵌入式开发学习(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(); // 初始化DS18B20

	while (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; // 显示负号
		}
		else
			temp_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; // 拉低DQ
	delay_10us(75);	  // 拉低750us
	DS18B20_PORT = 1; // DQ=1
	delay_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; // 如果超时则强制返回1
	else
		time_temp = 0;
	while ((!DS18B20_PORT) && time_temp < 20) // 等待DQ为高电平
	{
		time_temp++;
		delay_10us(1);
	}
	if (time_temp >= 20)
		return 1; // 如果超时则强制返回1
	return 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,否则为0
	else
		dat = 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();		  // 检查DS18B20
	ds18b20_write_byte(0xcc); // SKIP ROM
	ds18b20_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 ROM
	ds18b20_write_byte(0xbe); // 读存储器

	datl = ds18b20_read_byte(); // 低字节
	dath = ds18b20_read_byte(); // 高字节
	value = (dath << 8) + datl; // 合并为16位数据

	if ((value & 0xf800) == 0xf800) // 判断符号位,负温度
	{
		value = (~value) + 1;	  // 数据取反再加1
		temp = 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文件下载到单片机

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】map和set

目录 一、容器补充1.序列式容器与关联式容器2.键值对3.树形结构的关联式容器 二、set1.set的介绍2.set的使用3.multset的介绍4.multset的使用 三、map1.map的介绍2.map的使用3.multimap的介绍4.multimap的使用 一、容器补充 1.序列式容器与关联式容器 我们已经接触过STL中的部…

Mysql自动同步的详细设置步骤

以下步骤是真实的测试过程&#xff0c;将其记录下来&#xff0c;与大家共同学习。 一、环境说明&#xff1a; 1、主数据库&#xff1a; &#xff08;1&#xff09;操作系统&#xff1a;安装在虚拟机中的CentOS Linux release 7.4.1708 (Core) [rootlocalhost ~]# cat /etc/redh…

Docker学习(二十四)报错速查手册

目录 一、This error may indicate that the docker daemon is not running 报错docker login 报错截图&#xff1a;原因分析&#xff1a;解决方案&#xff1a; 二、Get "https://harbor.xxx.cn/v2/": EOF 报错docker login 报错截图&#xff1a;原因分析&#xff1a…

使用ubuntu-base制作根文件系统

1&#xff1a;ubuntu官网下载最小根文件系统&#xff1a; 放置到电脑的ubuntu中&#xff0c; Mkdir Ubuntu_rootfs Cd Ubuntu_rootfs Sudo tar –zxvf Ubuntu-bash-xxxxxx.tar.gz 2&#xff1a;电脑的ubuntu安装qemu搭建arm模拟系统 将/usr/bin/qemu-arm-static/(64位拷贝…

(黑客)自学笔记

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 行为&#xff1a;从编程开始掌握&#xff0c;前端后端、通信协议、什么都学。 缺点&#xff1a;花费时间太长、实际向安全过渡后可用到的关键知识并不多。…

Java基础面试题2

Java基础面试题 一、IO和多线程专题 1.介绍下进程和线程的关系 进程&#xff1a;一个独立的正在执行的程序 线程&#xff1a;一个进程的最基本的执行单位&#xff0c;执行路径 多进程&#xff1a;在操作系统中&#xff0c;同时运行多个程序 多进程的好处&#xff1a;可以充…

[webpack] 基本配置 (一)

文章目录 1.基本介绍2.功能介绍3.简单使用3.1 文件目录和内容3.2 下载依赖3.3 启动webpack 4.基本配置4.1 五大核心概念4.2 基本使用 1.基本介绍 Webpack 是一个静态资源打包工具。它会以一个或多个文件作为打包的入口, 将我们整个项目所有文件编译组合成一个或多个文件输出出去…

macbook怎么卸载软件?2023年最新全新解析macbook电脑怎样删除软件

macbook怎么卸载软件&#xff1f;2023年最新全新解析macbook电脑怎样删除软件。关于Mac笔记本如何卸载软件_Mac笔记本卸载软件的四种方法的知识大家了解吗&#xff1f;以下就是小编整理的关于Mac笔记本如何卸载软件_Mac笔记本卸载软件的四种方法的介绍&#xff0c;希望可以给到…

LeetCode 热题 100 JavaScript--206. 反转链表

/*** Definition for singly-linked list.* function ListNode(val, next) {* this.val (valundefined ? 0 : val)* this.next (nextundefined ? null : next)* }*/ /*** param {ListNode} head* return {ListNode}*/1、逐个断键&#xff0c;将后一个节点放到前面 …

网络可靠性之链路聚合

网络的可靠性 网络的可靠性指当设备或者链路出现单点或者多点故障时保证网络服务不间断的能力网络的可靠性是可以从单板、设备、链路多个层面实现。 链路聚合 以太网链路聚合&#xff1a; 通过将多个物理接口捆绑成为一个逻辑接口&#xff0c;可以再不进行硬件升级的条件下&a…

neo4j入门实例介绍

使用Cypher查询语言创建了一个图数据库&#xff0c;其中包含了电影《The Matrix》和演员Keanu Reeves、Carrie-Anne Moss、Laurence Fishburne、Hugo Weaving以及导演Lilly Wachowski和Lana Wachowski之间的关系。 CREATE (TheMatrix:Movie {title:The Matrix, released:1999,…

LeetCode-Java(06)

24. 两两交换链表中的节点 非递归解法 class Solution {public ListNode swapPairs(ListNode head) {ListNode pre new ListNode(0);pre.next head;ListNode temp pre;while(temp.next ! null && temp.next.next ! null) {ListNode start temp.next;ListNode end …

Android平台GB28181设备接入端如何降低资源占用和性能消耗

背景 我们在做GB28181设备接入模块的时候&#xff0c;考虑到好多设备性能一般&#xff0c;我们一般的设计思路是&#xff0c;先注册设备到平台侧&#xff0c;平台侧发calalog过来&#xff0c;获取设备信息&#xff0c;然后&#xff0c;设备侧和国标平台侧维持心跳&#xff0c;…

如何在Spring MVC中使用@ControllerAdvice创建全局异常处理器

文章目录 前言一、认识注解&#xff1a;RestControllerAdvice和ExceptionHandler二、使用步骤1、封装统一返回结果类2、自定义异常类封装3、定义全局异常处理类4、测试 总结 前言 全局异常处理器是一种 &#x1f31f;✨机制&#xff0c;用于处理应用程序中发生的异常&#xff…

HCIA---OSI/RM--开放式系统互联参考模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 一.OSI--开放式系统互联参考模型简介 OSI开放式系统互联参考模型是一种用于计算机网络通信…

C# Blazor 学习笔记(11):路由跳转和信息传值

文章目录 前言路由跳转测试用例路由传参/路由约束想法更新&#xff1a;2023年8月4日 前言 Blazor对路由跳转进行了封装。 ASP.NET Core Blazor 路由和导航 NavigationManager 类 本文的主要内容就是全局的跳转 路由跳转 路由跳转就要用到NavigationManager 类。 其实最常用…

解密HTTP代理爬虫中的IP代理选择与管理策略

在当今数据驱动的世界中&#xff0c;HTTP代理爬虫作为一项重要的数据采集工具&#xff0c;其成功与否往往取决于IP代理的选择与管理策略。作为一家专业的HTTP代理产品供应商&#xff0c;我们深知IP代理在数据采集中的重要性。在本文中&#xff0c;我们将分享一些关于HTTP代理爬…

RabbitMQ-API

这里写目录标题 Hello word 模式添加依赖生产者消费者获取信道工具类 Work Queues模式消费者代码 C1开启多线程运行启动 消费者代码 C2生产者代码 消息应答自动应答消息应答的方法Multiple 的解释消息自动重新入队消息手动应答代码消费者API 队列持久化消息持久化不公平分发消息…

一文带你深入了解JMM(Java内存模型)

JMM&#xff08;Java内存模型&#xff09;详解 为什么要有内存模型&#xff1f; 要想回答这个问题&#xff0c;我们需要先弄懂传统计算机硬件内存架构。 硬件内存架构 &#xff08;1&#xff09;CPU 去过机房的同学都知道&#xff0c;一般在大型服务器上会配置多个CPU&…

edge://settings/defaultbrowser default ie

Microsoft Edge 中的 Internet Explorer 模式 有些网站专为与 Internet Explorer 一起使用&#xff0c;它们具有 Microsoft Edge 等新式浏览器不支持的功能。 如果你需要查看其中的某个网站&#xff0c;可使用 Microsoft Edge 中的 Internet Explorer 模式。 大多数网站在新…