【单总线与DS18B20总结和代码实现】

news2024/11/29 4:35:10

单总线介绍与总结

  • 单总线介绍
  • 单总线时序图
  • DS18B20的操作流程
  • 代码 读温度
    • 代码思路
    • 代码实现

单总线介绍

单总线介绍
单总线应用案例:Ds18B20、温湿度传感器用到的就是这个,这里Ds18B20从当的角色是从机部分,而开发板充当的部分人是主机部分。
Ds18B20内部结构图
在这里插入图片描述
Ds18B30存储器结构
在这里插入图片描述

单总线的电路规范在这里插入图片描述
从上图可知 单总线的电路规范和IIC有很大的相似之处,也可以想象为上篇文章中拉杆子的案例。想输出0 就把杆子拉下来 1的话就释放杆子。
上图第一个是非寄生供电的模式,第二个他图是寄生的供电模式。

单总线时序图

开始初始化
初始化

注意这里从机应答需要有返回值来确定从机的应答的,并且从机拉低也是自动完成的,我们不需要在代码里面释放从机,我们写的代码是针对主机而言的。

发送时序图 (一位)

发送时序图

接收时序图 (一位)
在这里插入图片描述

发送与接收一个字节 8位
发送与接收8位

DS18B20的操作流程

在这里插入图片描述
读=接收 写=发送 DS18B20数据发送执行

在这里插入图片描述
注意: 跳过ROM必须只有一个设备时才可以跳过设备。
温度是两个字节组成的吧。
R:Temperature LSB 温度的低八位 一个字节
R:Temperature MSB 温度的高八位 一个字节

温度存储格式
DS18B20存储格式

代码 读温度

代码思路

在这里插入图片描述

代码实现

oneWire.c

#include <REGX52.H>

sbit oneWire_DQ=P3^7;
//AT89C52开发板

/**
  * @brief  oneWire单总线初始化  
  * @param  无 
  * @retval ackBit 从机的响应,0代表响应,1代表不响应   
  */
unsigned char oneWire_init()
{
    unsigned char i;
    unsigned char ackBit;
	//以下时序图均看自己总结的csdn
	oneWire_DQ=1;
	oneWire_DQ=0;
	i = 247;while (--i); //延时 500us 在STC-ISP软件 软件延时里设置 @12MHZ,Y1 
	oneWire_DQ=1;
	//等待的这15-60里主机不用操作,从机会在释放总线的15-60内响应主机发出应答位,
	//持续60-240,也就是说从机最慢最慢60之后就会发出应答位,所以取70时来读取,这时候到达低电平
	i = 32;while (--i); //延时70us
	//下面看时序图可知 是从机的响应 这里是从机控制, 我们不需要拉低或者释放	,交给从机自己释放
	ackBit=oneWire_DQ;//得到从机响应
	i = 247;while (--i); //延时 500us ,理论延时 60~240us  但是可以多延时一会,从机自动释放
	return ackBit;//返回应答位
}



/**
  * @brief  oneWire发送一位数据  
  * @param  Bit 一位数据
  * @retval 无  
  */
void oneWire_sendBit(unsigned char Bit)
{
	unsigned char i;
	oneWire_DQ=0;//由于执行过 init()函数后 oneWire_DQ=1了 此时直接拉低即可 当然也可以先置1然后再置0
	i = 4;while (--i);//延时10us 这里和时序图不太一样。这样写可以省去if判(Bit为0和1时)
	// 延时10us后让bit直接给DQ,如果bit是0,则在10us后仍然是0,之后再延时 50us 也就达到了60~120us的范围了
	//如果此时参数Bit=1,那么由时序图可知 在1~15us内需要拉低。执行此函数第一句DQ=0,
	//然后延时了10us,也在1~15us内,然后使得DQ=Bit,
	//此时DQ=1,相当于释放了,之后和0时一样再延时50us 满足时间切片为60us
	oneWire_DQ=Bit;//为bit1时代表释放 bit为0时oneWire_DQ继续为0
	i = 24;while (--i);//延时50us
	oneWire_DQ=1;//bit为0的释放,bit为1的保持高点电平不变
	
}


/**
  * @brief  oneWire接收一位数据 
  * @param  无 
  * @retval Bit 接收来自从机的一位数据   
  */
unsigned char oneWire_receiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	
	//主机先拉低
    oneWire_DQ=0;
    //规定在1~15us内拉低电平 这里在5us	
	i = 2;while (--i);//延时5us
	//释放电平 主动权交给从机
	 oneWire_DQ=1;
	i = 2;while (--i);//延时5us
	//读取从机的电平
	Bit= oneWire_DQ;
	i = 24;while (--i);//延时50us走完时间片
	return Bit;
}

/**
  * @brief  发送一个字节 8位数据 
  * @param  byte 要发送的字节数据 
  * @retval 无  
  */
void oneWire_sendByte(unsigned char byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		oneWire_sendBit(byte&(0x01<<i));//这里解释下:发送一个字节 8位 调用上面的8次发送一位的函数
		//因为从低到高,一位一位的取,故而byte&(0x01<<i)
		//假如byte是0x55,则即是 0101 0101 ,&上0x01 也即是 0101 0101 & 0000 0001 =00000001第一位1便取出来了
		//若想取出低四位的第二位,0101 0101 & 0x02=0101 0101 & 0000 0010 =0000 0000第二位便是0
		//如此循环八次便取出来了 八位数据
	}
}

/**
  * @brief  oneWire接收一个字节 8位数据 
  * @param  无 
  * @retval byte 主机接收来自从机的一个字节的数据   
  */
unsigned char oneWire_receiveByte()
{
	unsigned char i,Data;
	unsigned char byte=0x00;//提前将byte=0x00,初始化
	for(i=0;i<8;i++)
	{
		Data=oneWire_receiveBit();//假如完整的八位数据的Data是 0x52,也即是 0101 0010
		if(Data) //如果接收到的是1才进入if判断
		{
			byte=byte | (0x01<<i); 
			//i =0 时 Data位0x52 取最低位为 0,此时Data为0 ,不进入循环,此时byte=0x00
			//i =1 时,取Data低二位为 1,此时 此时因为Data是1,进入if,byte= 0x00 |(0x01<<1)= 0x00 | 0x02=0000 0000 | 0000 0010 =0000 0010
			//i =2 时,Data为0,不进入循环,此时,byte仍为0000 0010
			//i =3 时,Data也是0 同上
			//i =4 时,Data为1,进入if byte=0000 0010 , 0x01<<4= 0001 0000 ,byte|0x10,也即是 0000 0010 | 0001 0000=0001 0010
			//i =5 时,Data为0,byte仍保持上面的值
			//i =6 时,Data=1,再次进入if,byte=0001 0010 ,0x01<<6= 0100 0000=0x40 ,byte|0x40=0101 0010
			//i =7 时,不进入循环,继续保持0
			//结束后 byte的值就是八位的Data,也就和oneWire_receiveBit()的值一样了
		}
	}
	return byte;//把数据返回出去
}

DS18B20.c

#include <REGX52.H>
#include "oneWire.h"//引入oneWire
#define ds18B20_skipRom        0xcc //跳过rom指令
#define ds18B20_convertT       0x44 //温度转化
#define ds18B20_readScratchpad 0xBE //读暂存器

/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void ds18B20_convertTemp()
{
	oneWire_init();//先进性初始化,观察上面的时序图
	oneWire_sendByte(ds18B20_skipRom);//跳过rom,发送一个字节
	oneWire_sendByte(ds18B20_convertT);
}

/**
  * @brief  DS18B20开始读取温度
  * @param  无
  * @retval 返回真实温度 小数点四位
  */
float ds18B20_readTemp()
{	int temp;//临时变量存温度
	float T;//存真正的温度
	unsigned char TLSB,TMSB;//观察上图可知 此处读的是温度 温度是由 TLSB 和TMSB组成
	oneWire_init();//初始化 可由上述时序图可知,需要先初始化
	oneWire_sendByte(ds18B20_skipRom);
	oneWire_sendByte(ds18B20_readScratchpad);
	TLSB=oneWire_receiveByte();//接收低字节数据
	TMSB=oneWire_receiveByte();//接收高字节数据
	temp=(TMSB<<8) | TLSB;	
	//这里先把整体转为int类型,再把TMSB向左移八位,再放或上 TLSB,例如TMSB是11111001,TLSB为 1000 1100,
	//TMSB<<8=11111001<<8=11111001 00000000 再或上TLSB 1000 1100=11111001 1000 1100
	//变为16位数据,但注意,上图TLSB中后四位是小数,转化为int后,小数部分就被转化了,最低位就变成了2^0的那位了,没有小数了
    //这时候需要把数据再转为带小数的
	T=temp/16.0; //2^4  右移4位把小数的数据拿回来
	return T;//返回真实带有1小数点的温度
}

LCD1602.c

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

main.c

#include <REGX52.H>
#include "LCD1602.h"
#include "oneWire.h"
#include "DS18B20.h"
#include "delayXms.h"
float T;
void main()
{
	LCD_Init();
	LCD_ShowString(1,1,"Temperature:");
	//ack=oneWire_init();
	//LCD_ShowNum(2,1,ack,3);//拔掉ds18b20断电重启显示 1 未应答,插上后断电重启显示0 代表应答成功
	ds18B20_convertTemp();
	delayXms(1000);
	while(1)
	{
	     ds18B20_convertTemp();//先转换温度
		 T= ds18B20_readTemp();
		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);//因为不能取小数 故而先降温度*10000再对10000取余数便得到了小数
		//由因为*10000后数据超过范围 故而强制类型转为 unsigned long类型
		
	}
}

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

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

相关文章

红队打靶练习:HACK ME PLEASE: 1

信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:69:c7:bf, IPv4: 192.168.61.128 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.61.2 00:50:56:f0:df:20 …

ubuntu22.04@laptop OpenCV Get Started: 010_blob_detection

ubuntu22.04laptop OpenCV Get Started: 010_blob_detection 1. 源由2. blob应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 重点分析3.1 Threshold3.2 Area3.3 Circularity3.4 Convexity3.5 Inertia Ratio 4. 总结5. 参考资料6. 补充 1. 源由 Blob是图像中的一组连接像素&#…

Git 初学

目录 一、需求的产生 二、版本控制系统理解 1. 认识版本控制系统 2. 版本控制系统分类 &#xff08;1&#xff09;集中式版本控制系统 缺点&#xff1a; &#xff08;2&#xff09;分布式版本控制系统 三、初识 git 四、git 的使用 例&#xff1a;将 “ OLED文件夹 ”…

STM32物联网(ESP-01S模块及STM32和ESP-01S通信方式介绍)

文章目录 前言一、ESP-01S模块介绍二、STM32和ESP-01S通信方式介绍三、什么是AT指令四、创建基础工程总结 前言 本篇文章我们开始正式进入STM32物联网的专栏&#xff0c;在这个专栏中将会带大家学习使用STM32进行联网&#xff0c;联网模块的话主要就是使用到了ESP-01S WIFI模块…

嵌入式STM32 单片机 GPIO 的工作原理详解

STM32的 GPIO 介绍 GPIO 是通用输入/输出端口的简称&#xff0c;是 STM32 可控制的引脚。GPIO 的引脚与外部硬件设备连接&#xff0c;可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。 以 STM32F103ZET6 芯片为例子&#xff0c;该芯片共有 144 脚芯片&#xff0c…

[word] word技巧分享_word自动编号的标题 #知识分享#知识分享#其他

word技巧分享_word自动编号的标题 日常办公&#xff0c;我们时时都在使用 word 软件。 word 软件内容的组织是通过一节一节的标题进行的。 我们常常需要处理的是下图一样的章节目录

计算机设计大赛 深度学习OCR中文识别 - opencv python

文章目录 0 前言1 课题背景2 实现效果3 文本区域检测网络-CTPN4 文本识别网络-CRNN5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习OCR中文识别系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;…

挑战杯 python图像检索系统设计与实现

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python图像检索系统设计与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c…

【C深度解剖】取模与取余

简介&#xff1a;本系列博客为C深度解剖系列内容&#xff0c;以某个点为中心进行相关详细拓展 适宜人群&#xff1a;已大体了解C语法同学 作者留言&#xff1a;本博客相关内容如需转载请注明出处&#xff0c;本人学疏才浅&#xff0c;难免存在些许错误&#xff0c;望留言指正 作…

AJAX——接口文档

1 接口文档 接口文档&#xff1a;描述接口的文章 接口&#xff1a;使用AJAX和服务器通讯时&#xff0c;使用的URL&#xff0c;请求方法&#xff0c;以及参数 传送门&#xff1a;AJAX阶段接口文档 <!DOCTYPE html> <html lang"en"><head><meta c…

【论文精读】GPT2

摘要 在单一领域数据集上训练单一任务的模型是当前系统普遍缺乏泛化能力的主要原因&#xff0c;要想使用当前的架构构建出稳健的系统&#xff0c;可能需要多任务学习。但多任务需要多数据集&#xff0c;而继续扩大数据集和目标设计的规模是个难以处理的问题&#xff0c;所以只能…

【AIGC】Stable Diffusion的ControlNet参数入门

Stable Diffusion 中的 ControlNet 是一种用于控制图像生成过程的技术&#xff0c;它可以指导模型生成特定风格、内容或属性的图像。下面是关于 ControlNet 的界面参数的详细解释&#xff1a; 低显存模式 是一种在深度学习任务中用于处理显存受限设备的技术。在这种模式下&am…

嵌入式I2C 信号线为何加上拉电阻(图文并茂)

IIC 是一个两线串行通信总线&#xff0c;包含一个 SCL 信号和 SDA 信号&#xff0c;SCL 是时钟信号&#xff0c;从主设备发出&#xff0c;SDA 是数据信号&#xff0c;是一个双向的&#xff0c;设备发送数据和接收数据都是通过 SDA 信号。 在设计 IIC 信号电路的时候我们会在 SC…

84 CTF夺旗-PHP弱类型异或取反序列化RCE

目录 案例1&#xff1a;PHP-相关总结知识点-后期复现案例2&#xff1a;PHP-弱类型对比绕过测试-常考点案例3&#xff1a;PHP-正则preg_match绕过-常考点案例4&#xff1a;PHP-命令执行RCE变异绕过-常考点案例5&#xff1a;PHP-反序列化考题分析构造复现-常考点涉及资源&#xf…

机器学习---HMM前向、后向和维特比算法的计算

1. HMM import numpy as np# In[15]:class HiddenMarkov:def forward(self, Q, V, A, B, O, PI): # 使用前向算法N len(Q) # 状态序列的大小M len(O) # 观测序列的大小alphas np.zeros((N, M)) # alpha值T M # 有几个时刻&#xff0c;有几个观测序列&#xff0c;就有…

大学建筑专业的搜题软件?大学搜题工具中的高级搜索功能有哪些? #学习方法#微信#经验分享

学习和考试是大学生生活中不可避免的一部分&#xff0c;而在这个信息爆炸的时代&#xff0c;如何快速有效地获取学习资源和解答问题成为了大学生们共同面临的难题。为了解决这个问题&#xff0c;搜题和学习软件应运而生。今天&#xff0c;我将为大家介绍几款备受大学生青睐的搜…

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.——> Vue报错&#xff0c;key关键字不唯一&#xff1a; 解决办法&#xff1a;修改一下重复的id值&#xff01;&#xff01;&#xff01;

安卓自定义画板

包含功能&#xff1a; 包含 获取当前画板的截图、设置画笔样式、获取画笔样式、设置画笔宽度、获取画笔宽度、设置画笔颜色、获取画笔颜色、加载图片、获取图片位图对象、设置图片位图对象&#xff0c;并在画布上绘制图片、撤销上一步操作、重做上一步撤销的操作、清空所有绘图…

.net和jar包windows服务部署

一.NetCore 1.创建启动脚本run_instal.bat,例如程序文件为ApiDoc.exe set serviceName"Apidoc Web 01" set serviceFilePath%~dp0ApiDoc.exe set serviceDescription"ApiDoc 动态接口服务 web 01"sc create %serviceName% BinPath%serviceFilePath% sc c…

TiDB 在医疗保障信息平台的应用实践

文章介绍了 TiDB 在医疗保障信息平台中的应用。东软医保云应用管理平台通过与 TiDB 联合&#xff0c;成功满足了医疗保障业务中高并发、实时性和复杂查询的要求。在某地市医疗保障信息平台的实践中&#xff0c;TiDB 分布式数据库有效实现了在线交易和实时分析服务&#xff0c;日…