单总线及DS18B20

news2025/1/18 10:47:30

目录

单总线

单总线介绍

单总线的电路规范

单总线时序结构

初始化

代码理解

发送一位

代码理解

接收一位

代码理解

发送一个字节

代码理解

接收一个字节

代码理解

DS18B20

DS18B20介绍

引脚及应用电路

内部结构

存储器结构

DS18B20操作流程

ROM指令

功能指令

DS18B20数据帧

温度变换

代码理解

温度读取

代码理解

温度的存储格式

举例

仿真案例

电路图

keil文件

单总线

单总线介绍

  • 单总线(1-wire BUS)是由Dallas公司开发的一种通用数据总线
  • 使用一根异步、半双工的通信线:DQ
  • 单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,可以省去设备的VDD线路,此时供电+通信只需要DQ和GND两根线

单总线的电路规范

  • 设备的DQ均要配置成开漏输出模式
  • DQ添加一个上拉电阻,阻值一般为4.7k欧左右
  • 若此总线的从机采用寄生供电,则主机还应配一个强上拉电阻

注意:第一个为电源供电电路,第二个为寄生供电电路(相对于第一个多了个强上拉)

单总线时序结构

初始化

前言:主机将总线拉低至少480us,然后释放总线,等待15——16us后,存在的从机会拉低总线60——240us以响应主机,之后从机释放总线(总过程至少960us)。

注意:上面弯的时序图部分是电阻的弱上拉作用,电阻拉的高电平是一种弱上拉,不会立即把总线拉高。

代码理解
//单总线初始化
unsigned char OneWire_Init(){
	unsigned char i=0,AckBit=0;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i=247;while(--i);	//延时500us
	OneWire_DQ=1; //释放总线
	i=32;while(--i);	//延时70us
	AckBit=OneWire_DQ; //读出IO口电平
	i=247;while(--i);	//延时500us
	return AckBit;
}

发送一位

前言:主机将总线拉低60-120us,然后释放总线,表示发送0;主机将总线拉低1-15us,然后释放总线表示发送1.从机将在总线拉低30us后(典型值)读取电平,发送的整个时间片应大于60us但不超过120us

代码理解
//单总线发送1位
void OneWire_SendBit(unsigned char Bit){
	unsigned char i=0;
	OneWire_DQ=0;
	i=4;while(--i); //延时10us
	OneWire_DQ=Bit;	//是1的话此时拉高,是0的话不拉高直接走完时序
	i=24;while(i--); //延时50us
	OneWire_DQ=1;
}

接收一位

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

注意:在15us内若电平变为1,则读取到的为1(主机将线拉下来后释放,释放之后总线立即弹上去说明从机发的是1),若电平依旧是0,则读取到的为0(阴影表示从机随时可能释放总线)

代码理解
//单总线接收一位
unsigned char OneWire_ReceiveBit(){
	unsigned char Bit=0,i=0;
	OneWire_DQ=0;
	i=2;while(i--);	//延时5us
	OneWire_DQ=1;
	i=2;while(i--);	//延时5us
	Bit=OneWire_DQ;
	i=24;while(i--); //延时50us
	return Bit;
}

发送一个字节

前言:连续调用8次发送1位的时序,依次发送一个字节的8位(低位在前)

代码理解
//单总线发送1字节
void OneWire_SendByte(unsigned char Byte){
	unsigned char i=0;
	for(i=0;i<8;i++){
		OneWire_SendBit(Byte&(0x01<<i)); //低位在前(任何数当作bit看不为0就为1)
	}
}

接收一个字节

前言:连续调用8次接收1位的时序,依次接收一个字节的8位(低位在前)

代码理解
//单总线接收1字节
unsigned char OneWire_ReceiveByte(){
	unsigned char i=0,Byte=0;
	for(i=0;i<8;i++){
		if(OneWire_ReceiveBit()==1){
			Byte=Byte|(0x01<<i);
		}
	}
	return Byte;
}

DS18B20

DS18B20介绍

  • DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点
  • 测温范围:-55摄氏度到+125摄氏度
  • 通信接口:1-Wire(单总线)
  • 其他特征:可形成总线结构(可以在一条通信线上挂载多个设备),内置温度报警功能、可寄生供电(电源不用接,直接接数据线和GND就可以)

理解:模拟温度传感器如热敏电阻,可以直接测温度,它输出的电压随着温度变化而变化;我们通过AD采集芯片(模拟到数字转化的芯片)将模拟的电压值转化为数字电压值,这样单片机读取后才会知道温度;由此观之模拟温度传感器比较复杂,需要外部电路和模数转换及系数配比才可得到具体温度;而数字传感器就集成了模拟温度传感器以及AD模数转换器以及微控制器,它内部读取模拟温度传感器,然后自动通过内部转化,将温度存在RAM中;因此我们只需通过引脚及单总线协议将温度转化读取出来就可以。

引脚及应用电路

内部结构

理解:

  • 最左边的电路为寄生电源电路,正常情况下电源用的是VDD进而让电流走向internal Vdd,若不用VDD,那么电流从DQ进流入internal Vdd(寄生供电使用时需要强上拉)。
  • power-supply-sense:电源供给感应模块,它可以感应我们外部VDD是否存在,若不存在(采用寄生供电)他会调节内部的结构来省电
  • 64bit ROM:一种光刻ROM,这种ROM标识着我们的ID号(每个DS18B20都有全球唯一的一个ID号)在通信时就作为器件的地址,用于总线的通信寻址;同时其也是单总线的一个接口
  • Memory control logic:64bit ROM便会进入,内存控制逻辑,其掌管着内部RAM
  • scartchpad:其是内部RAM,内部储存着温度等等一些配置参数,用于总线的数据交互(右边的连线为内部的一些设备)
  • 当我们想要通信的时候,经过64bit ROM,确定是对该设备通信,来和Memory control logic交流,若我们想读,那么他就会从scartchpad中取出数据放在总线上,若我们想写,那么他就会把我们的数据写到scartchpad里面
  • temperature sensor:内部的模拟温度传感器,其自动的将温度转换都做好了,当我们发出指令让他开始温度转换时,温度传感器就会工作,然后将他的数据放到RAM里面,我们之后通过数据交互就可以把温度值拿出来了
  • alarm high trigger:报警高触发计算器,用来存储我们的温度上限阈值,用于温度报警,其存储介质为E2PROM
  • alarm low trigger:报警低触发计算器,用来存储我们的温度下限阈值,用于温度报警,其存储介质为E2PROM
  • configuration register:配置寄存器,其用来设置我们的分辨率以及精度(出场默认最高分辨率0.0625)我们通过配置两位可以把分辨率降低,最低0.5摄氏度(降低后温度转换速度提升,该字节有8位,其中第六第七位为R0和R1位,通过配置这两位就可以配置不同分辨率)
  • 8位crcgenerator:将RAM之前的数据进行校验,得到校验码放到ROM后面(用于通信判断数据是否正确的)

存储器结构

理解:

  • 左边暂存器scartchpad总共9个字节,前两个字节共同组成了温度的数据,若上电直接读的话默认85摄氏度(80+5)
  • byte2、byte3、byte4分别对应右边的E2PROM;我们不能从外面发送一个数据存到E2PROM里面,我们只能先将数据写入暂存器,然后我们通过发送一条指令进而把暂存器中的数据复制到E2PROM中(读取就从E2PROM中将数据回调到暂存器)上电时会自动地将E2PROM的三个字节搬到暂存器中
  • byte5、byte6、byte7为保留位,都没有被使用
  • CRC校验:将前面的8个字节做一个运算,然后算出一个校验位跟在后面;我们把暂存器整个读出来后进行相同的运算,看看是不是得到对应的校验位,若是证明数据传输正确

DS18B20操作流程

  • 初始化:1.从机复位;2.从机是否响应
  • ROM操作:ROM指令,本指令需要的读写操作
  • 功能操作:功能指令,本指令需要的读写操作

ROM指令

  • 搜寻ROM:SEARCH ROM[F0h](用于确定挂载在同一总线上的DS18B20的个数和识别64位ROM地址)
  • 读取ROM:READ ROM[33h](读取DS18B20中ROM中的编码)
  • 匹配ROM:MATCH ROM[55h](发出指令后,接着发出64位ROM的编码,访问总线上与该编码相应的DS18B20)
  • 跳过ROM:SKIP ROM[CCh](忽略64位ROM地址,直接向DS18B20发送温度变换命令,适用于单片工作)
  • 报警搜索:ALARM SEARCH[ECh](执行后,只有温度超过设定值上限或下限的片子才做出响应)

功能指令

  • 温度变换:CONVERT T[44h](暂存器温度值从温度传感器中更新)
  • 写暂存器:WRITE SCRATCHPAD[4Eh](将字节数据写入到中间的RAM[byte2、3、4])
  • 读暂存器:READ SCRATCHPAD[BEh](将暂存器的值全部的读出来)
  • 复制暂存器:COPY SCRATCHPAD[48H](将RAM[byte2,3,4]字节写入到E2PROM)
  • 回调E2PROM:RECALL E2[B8h](将E2PROM的值覆盖到RAM[byte2,3,4]字节处)
  • 读取设备供电模式:READ POWER SUPPLY[B4h](读取DS18B20供电方式,寄生供电时DS1820发送0,外接电源时DS18B20发送1)

DS18B20数据帧

温度变换

前言:初始化——》跳过ROM——》开始温度变换

代码理解
//温度转换
void DS18B20_ConvertT(){
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

温度读取

前言:初始化——》跳过ROM——》读暂存器——》连续的读操作

注意:LSB和MSB共同组成具体温度.

代码理解
//读取温度
float DS18B20_READT(){
	unsigned char TLSB,TMSB;
	int Temp=0;
	float T=0;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0; //直接÷会损失精度,所以要÷浮点数
	return T;
}

温度的存储格式

注意:

  • MSB前5位均表示符号位,若温度值是负的,那么前五位全为1,若是正的,则前五位全为0.
  • LSB后四位均表示小数,bit3-0.5,bit2-0.25,bit1-0.125,bit0-0.0625(最低位变化一次整个温度值变化0.0625)

举例

注意:上面的负数采用了补码的行式。

仿真案例

需求:从传感器中读出温度数据。

电路图

keil文件

#include "reg51.h"
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
void delay(unsigned int n){
	unsigned int i=0,j=0;
	for(i=0;i<n;i++){
		for(j=0;j<120;j++);
	}
}
//写指令
void writecom(unsigned char com){
	//写指令
	RS=0;
	RW=0;
	E=0;
	P2=com;
	delay(5);
	E=1;
	E=0;
}
//写数据
void writedat(unsigned char dat){
	//写指令
	RS=1;
	RW=0;
	E=0;
	P2=dat;
	delay(5);
	E=1;
	E=0;
}
//初始化液晶屏
void initlcd(){
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}
//显示一个字符
void LCD_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char){
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	writedat(Char);
}
int LCD_Pow(int X,int Y){
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++){
		Result*=X;
	}
	return Result;
}
//展示数字
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length){
	unsigned char i;
	if(Line==1){
		writecom(0x80|(Column-1));
	}else{
		writecom(0x80|(Column-1)+0x40);
	}
	for(i=Length;i>0;i--){
		writedat('0'+Number/LCD_Pow(10,i-1)%10);
	}
}
//单总线相关
sbit OneWire_DQ=P3^3;
//单总线初始化
unsigned char OneWire_Init(){
	unsigned char i=0,AckBit=0;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i=247;while(--i);	//延时500us
	OneWire_DQ=1; //释放总线
	i=32;while(--i);	//延时70us
	AckBit=OneWire_DQ; //读出IO口电平
	i=247;while(--i);	//延时500us
	return AckBit;
}
//单总线发送1位
void OneWire_SendBit(unsigned char Bit){
	unsigned char i=0;
	OneWire_DQ=0;
	i=4;while(--i); //延时10us
	OneWire_DQ=Bit;	//是1的话此时拉高,是0的话不拉高直接走完时序
	i=24;while(i--); //延时50us
	OneWire_DQ=1;
}
//单总线接收一位
unsigned char OneWire_ReceiveBit(){
	unsigned char Bit=0,i=0;
	OneWire_DQ=0;
	i=2;while(i--);	//延时5us
	OneWire_DQ=1;
	i=2;while(i--);	//延时5us
	Bit=OneWire_DQ;
	i=24;while(i--); //延时50us
	return Bit;
}
//单总线发送1字节
void OneWire_SendByte(unsigned char Byte){
	unsigned char i=0;
	for(i=0;i<8;i++){
		OneWire_SendBit(Byte&(0x01<<i)); //低位在前(任何数当作bit看不为0就为1)
	}
}
//单总线接收1字节
unsigned char OneWire_ReceiveByte(){
	unsigned char i=0,Byte=0;
	for(i=0;i<8;i++){
		if(OneWire_ReceiveBit()==1){
			Byte=Byte|(0x01<<i);
		}
	}
	return Byte;
}
//DS18B20模块
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
//温度转换
void DS18B20_ConvertT(){
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}
//读取温度
float DS18B20_READT(){
	unsigned char TLSB,TMSB;
	int Temp=0;
	float T=0;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0; //直接÷会损失精度,所以要÷浮点数
	return T;
}
float T=0;
void main(){
	initlcd();
	while(1){
		DS18B20_ConvertT();
		T=DS18B20_READT();
		if(T<0){
			LCD_ShowChar(2,1,'-');
			T=-T;
		}else{
			LCD_ShowChar(2,1,'+');
		}
		LCD_ShowNum(2,2,T,3);
		LCD_ShowChar(2,5,'.');
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);
	}
}

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

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

相关文章

大厂面试之【Redis持久化机制】 - RDB和AOF概述及应用配置

文章目录 Redis持久化1. RDB(Redis DataBase)1.1 概述1.2 配置应用 2. AOF(Append Only File)2.1 概述2.2 配置应用 Redis持久化 先上结论&#xff1a;Redis持久化操作分为rdb以及aof&#xff0c;但是前者已经够用 1. RDB(Redis DataBase) 1.1 概述 rdb保存的是dump.rdb文件在指…

基于springboot实现校园资料分享平台系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园资料分享平台演示 摘要 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了校园资料分享平台的开发全过程。通过分析企业对于校园资料分享平台的需求&#xff0c;创…

C++ 11是如何封装Thread库的?

引言 C11 标准引入了一个重要的特性&#xff0c;即原生线程支持&#xff0c;这标志着C语言在并发编程领域迈出了坚实的步伐。在此之前&#xff0c;开发人员在进行跨平台的多线程编程时&#xff0c;不得不依赖于操作系统提供的特定API&#xff0c;如Windows API或POSIX Threads…

开发环境->生产环境

1、数据迁移 不涉及docker # 以数据库用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u abragent -pabragebb17 abragent > abragent.sql# 以root用户导出数据 mysqldump -h 192.168.1.168 -P 3307 -u root -p8d3Ba1b abragent > abragent.sql 涉及docker …

Android12 简单的共享内存驱动实现 参考Ashmem

Android12 共享内存驱动实现 SOC&#xff1a;RK3568 system&#xff1a;Android12 概述&#xff1a; 1. 概述 Ashmem&#xff08;Anonymous Shared Memory&#xff0c;Android 匿名共享内存&#xff09;&#xff0c;它基于 mmap 系统调用&#xff0c;可以让不同进程将同一段…

数据恢复工具哪个成功率高?十大数据恢复软件榜单

数据恢复软件可以恢复损坏或删除的数据。使用数据恢复软件恢复存储在安全位置的剩余信息。您可能会因意外删除文件、文件系统逻辑损坏甚至存储故障等各种原因而丢失数据。执行查看、复制、扫描、识别或提取存储设备中已删除扇区的数据等操作。恢复虚拟存储在任何设备&#xff0…

【算法练习】27:冒泡排序学习笔记

一、冒泡排序的算法思想 原理&#xff1a;以升序为例&#xff0c;冒泡排序通过从左往右连续比较相邻元素&#xff0c;当发现左边比右边大就交换元素。从左往右依次比较完称为“一轮”&#xff0c;每轮结束之后就会固定一个元素。 时间复杂度&#xff1a;2层循环&#xff0c;所以…

windows安装Openssl

openssl官网:[ Downloads ] - /source/index.html Windows 安装方法 OpenSSL 官网没有提供 Windows 版本的安装包&#xff0c;可以选择其他开源平台提供的工具 Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions 等待下载完成 捐不起 配置环境变量 ope…

Maven依赖管理项目构建工具

一 Maven简介 1.1、Maven是一个依赖管理工具 1.1.1 jar 包的规模 随着我们使用越来越多的框架&#xff0c;或者框架封装程度越来越高&#xff0c;项目中使用的jar包也越来越多。项目中&#xff0c;一个模块里面用到上百个jar包是非常正常的。 比如下面的例子&#xff0c;我…

内存管理机制SLAB

1. 为什么需要内存分配管理&#xff1f;为什么需要SLAB&#xff1f; 在学习c语言时&#xff0c;我们常常会使用到malloc()去申请一块内存空间&#xff0c;用于存放我们的数据&#xff0c;这是代码层面的语言 如果我们想要关心malloc这个命令向系统发出后&#xff0c;系统会做什…

HTMLCSSJS

HTML基本结构 <html><head><title>标题</title></head><body>页面内容</body> </html> html是一棵DOM树, html是根标签, head和body是兄弟标签, body包括内容相关, head包含对内容的编写相关, title 与标题有关.类似html这种…

cdp集群扩容节点磁盘挂载失败原因和解决办法

问题说明 之前在对cdp集群扩容节点环境配置时 按照文档挂载磁盘 在最后一步挂载时&#xff0c;发现有块磁盘没挂载上去 可以看到本该挂载到/data5目录的磁盘sdf1被挂到了/data1上面 查看挂载点文件 vim /etc/fstab问题分析&#xff1a; 发现之前在设置挂载点的时候挂载目录…

gpt4.0中文版

我愿把这个网站成为全球最强AI网站&#xff01;弄100多个AI伺候你&#xff1f;&#xff1f; 家人们&#xff0c;你们猜我发现了什么牛逼的AI网站&#xff1f;&#xff1f; 直接上图&#xff1a; 编辑 这个网站&#xff0c;聚合了国内外100多个顶尖的AI&#xff0c;包括了Op…

AI技术在金融领域/银行业的应用和风险

前言 随着科技的不断发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经在各行各业得到了广泛的应用&#xff0c;其中包括银行业。银行业作为经济的重要组成部分&#xff0c;一直在不断地探索和应用新技术&#xff0c;以提升服务效率、风险管理和客户体验。然而&…

解决nvm切换node版本失败的终极办法,亲测有效!

问题 当我们有多个前端项目&#xff0c;但是使用的node版本不相同&#xff0c;这就需要我们在启动不同项目时切换node版本&#xff0c;很麻烦&#xff0c;这时有一个叫nvm的好东西可以帮我们快速切换node版本。 但是&#xff0c;nvm安装有一个巨大的坑点&#xff1a;nvm use …

二、GitLab相关操作

GitLab相关操作 一、组、用户、项目管理1.创建组2.创建项目3.创建用户并分配组3.1 创建用户3.2 设置密码3.3 给用户分配组 二、拉取/推送代码1.配置ssh(第一次需要)1.1 创建一个空文件夹1.2 配置本地仓账号和邮箱1.3 生成ssh公钥密钥1.4 gitlab配置公钥 2.拉取代码3.推送代码3.…

Linux gcc day3

find命令&#xff08;importance&#xff09;&#xff1a; 语法&#xff1a;find pathname -options find /root -name test.c which命令&#xff1a; which [指令] 只搜索指令&#xff0c;在什么位置下 为什么文件夹带有颜色呢&#xff1f; 科普补充alias命令&#xff1a; ali…

理论实践-CPU性能监控工具-uptime-mpstat-pidstat-vmstat-top-ps-perf

CPU 性能工具。 首先&#xff0c;平均负载的案例。我们先用 uptime&#xff0c; 查看了系统的平均负载&#xff1b;而在平均负载升高后&#xff0c;又用 mpstat 和 pidstat &#xff0c;分别观察了每个 CPU 和每个进程 CPU 的使用情况&#xff0c;进而找出了导致平均负载升高的…

刷题之Leetcode35题(超级详细)

35.搜索插入位置 力扣题目链接(opens new window)https://leetcode.cn/problems/search-insert-position/ 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 你可…

【Java八股学习】Redis持久化 思维导图

说明 文章内容通过学习小林Coding内的优质文章后整理而来&#xff0c;整理成思维导图的方式是为了帮助自己理解、记忆和复习。如若侵权请联系删除&#xff0c;再次对小林Coding内的优质文章表示感谢。参考文章如下&#xff1a; AOF 持久化是怎么实现的&#xff1f;RDB 快照是…