C51学习归纳10 --- 单总线通信协议、DS18B20

        通信协议是最重要的,我们之前学习了I2C通信协议,这一节我们学习一下新的通信协议,单总线通信。

一、开发板原理图

        可以看出直接由P3_7口控制,但是遵循单总线协议。

        单总线的电路要求

         现在介绍单总线的通信协议细节:

        1、Init初始化

         初始化:主机将总线拉低至少480us,然后释放总线,等待15~60us后,存在的从机会拉低总线60~240us以响应主机,之后从机将释放总线。

        2、发送一个位

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

        3、接收一位

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

        4、发送、接收一位的功能。连续调用8次就好了

        DS18B20的使用:温度变换:初始化→跳过ROM(因为本节只有一个设备) →开始温度变换

        温度读取:初始化→跳过ROM(因为本节只有一个设备) →读暂存器→连续的读操作

         以下是ROM指令,功能指令

        ROM指令,在只有一个设备的时候直接使用SKIP就好,如果有多个,可以使用MATCH,搜索从机。

        功能指令:1、CONBERT T:执行温度变换操作,读取温度值放在寄存器中。2、对寄存器写WRITE:这里写入的是温度上限、下限、分辨率。3、读取寄存器READ:将寄存器中的温度值读出来。4、COPY :从机将寄存器中主机写入的上下限、精度,存储在DS18B20的E2PROM中。5、RECALL E2P:把从机的E2PROM读取到寄存器中。6、READ POWER SUPLY:判读寄生供电、还是独立供电。

二、简单的温度读取显示

        先按照原理,编写单总线的代码:

#include <REGX52.H>

//引脚定义
sbit OneWire_DQ=P3^7;

/**
  * @brief  单总线初始化
  * @param  无
  * @retval 从机响应位,0为响应,1为未响应
  */
unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 247;while (--i);		//Delay 500us
	OneWire_DQ=1;
	i = 32;while (--i);			//Delay 70us
	AckBit=OneWire_DQ;
	i = 247;while (--i);		//Delay 500us
	return AckBit;
}

/**
  * @brief  单总线发送一位
  * @param  Bit 要发送的位
  * @retval 无
  */
void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	OneWire_DQ=0;
	i = 4;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 24;while (--i);			//Delay 50us
	OneWire_DQ=1;
}

/**
  * @brief  单总线接收一位
  * @param  无
  * @retval 读取的位
  */
unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;
	i = 2;while (--i);			//Delay 5us
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 5us
	Bit=OneWire_DQ;
	i = 24;while (--i);			//Delay 50us
	return Bit;
}

/**
  * @brief  单总线发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}

/**
  * @brief  单总线接收一个字节
  * @param  无
  * @retval 接收的一个字节
  */
unsigned char OneWire_ReceiveByte(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}
	return Byte;
}

        这里的代码,需要结合前面的原理图进行理解,其实并不难,主要是学会如何表达流程与逻辑。上面代码,应该多多理解,因为不是简单的使用逻辑判断,而是使用更合适的方法,收发0,1写在了一起。

        注意这里先发出的是低位。所以收的时候也是从低位开始收的。

        其中延时500us不能直接使用以前的DELAY函数,我们现在用STC-ISP自动生成。代码中我们偷懒了,没有全部使用,大致忽略了5us。

        写完了底层的通信协议,我们借助通信协议去书写我们的DS18B02的函数。

#include <REGX52.H>
#include "OneWire.h"

//DS18B20指令
#define DS18B20_SKIP_ROM			0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD 	0xBE

/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

/**
  * @brief  DS18B20读取温度
  * @param  无
  * @retval 温度数值
  */
float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;
	int Temp;
	float T;
	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;
}

         这里的功能就是前面讲的,初始化,跳过ROM,然后发送指令。因为温度信息在前两位,所以连读两次。

        因为表示的是一个小数,存储的最低为不是2^0,而是2^-4,所以相当于我们读进来的数,大了16倍。所以最后除以16.0,必须是点0,才能得到浮点数。

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"

float T;

void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	LCD_Init();
	LCD_ShowString(1,1,"Temperature:");
	while(1)
	{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(2,1,'-');	//显示负号
			T=-T;			//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(2,1,'+');	//显示正号
		}
		LCD_ShowNum(2,2,T,3);		//显示温度整数部分
		LCD_ShowChar(2,5,'.');		//显示小数点
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示温度小数部分
	}
}

        因为,LCD只能显示整数,小数部分会直接省略,所以我们需要自己把小数部分计算出来。这个逻辑很简单,先把小数部分通过×10000变成整数的一部分,然后取余数,把这部分取出来就好了。

三、设置温度上下限,进行温度报警

        这里写一个综合案例,用于设置温度的上下限,这一个上下限存储在AT24C02,

        里面的代码都是之前写过的,就不再讲,只看main函数,书写逻辑

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "Key.h"
#include "Timer0.h"

float T,TShow;
char TLow,THigh;
unsigned char KeyNum;

void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	
	THigh=AT24C02_ReadByte(0);	//读取温度阈值数据
	TLow=AT24C02_ReadByte(1);
	if(THigh>125 || TLow<-55 || THigh<=TLow)
	{
		THigh=20;			//如果阈值非法,则设为默认值
		TLow=15;
	}
	
	LCD_Init();
	LCD_ShowString(1,1,"T:");
	LCD_ShowString(2,1,"TH:");
	LCD_ShowString(2,9,"TL:");
	LCD_ShowSignedNum(2,4,THigh,3);
	LCD_ShowSignedNum(2,12,TLow,3);
	Timer0_Init();
	
	while(1)
	{
		KeyNum=Key();
		
		/*温度读取及显示*/
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(1,3,'-');	//显示负号
			TShow=-T;		//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(1,3,'+');	//显示正号
			TShow=T;
		}
		LCD_ShowNum(1,4,TShow,3);		//显示温度整数部分
		LCD_ShowChar(1,7,'.');		//显示小数点
		LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分
		
		/*阈值判断及显示*/
		if(KeyNum)
		{
			if(KeyNum==1)	//K1按键,THigh自增
			{
				THigh++;
				if(THigh>125){THigh=125;}
			}
			if(KeyNum==2)	//K2按键,THigh自减
			{
				THigh--;
				if(THigh<=TLow){THigh++;}
			}
			if(KeyNum==3)	//K3按键,TLow自增
			{
				TLow++;
				if(TLow>=THigh){TLow--;}
			}
			if(KeyNum==4)	//K4按键,TLow自减
			{
				TLow--;
				if(TLow<-55){TLow=-55;}
			}
			LCD_ShowSignedNum(2,4,THigh,3);	//显示阈值数据
			LCD_ShowSignedNum(2,12,TLow,3);
			AT24C02_WriteByte(0,THigh);		//写入到At24C02中保存
			Delay(5);
			AT24C02_WriteByte(1,TLow);
			Delay(5);
		}
		if(T>THigh)			//越界判断
		{
			LCD_ShowString(1,13,"OV:H");
		}
		else if(T<TLow)
		{
			LCD_ShowString(1,13,"OV:L");
		}
		else
		{
			LCD_ShowString(1,13,"    ");
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=20)
	{
		T0Count=0;
		Key_Loop();	//每20ms调用一次按键驱动函数
	}
}

        使用中断检测按键按下,获取当前按下的Key_KeyNum。

        在主函数的循环下,根据每次键值的不同,进行不同的操作。键值为1的时候上限加,键值为2的时候上限减。键值为3的时候下限加,键值为4的时候下限减。修改的同时显示出来,并存储在AT24C02中。

        每次循环中,进行温度和上下限的对比,显示不同的结果。

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

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

相关文章

免费插件集-illustrator插件-Ai插件-文本属性批处理

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;进行文本属性批处理。首先从下载网址下载这款插件 https://download.csdn.net/download/m0_67316550/87890501&am…

【递归、搜索与回溯】综合练习 {回溯恢复现场;剪枝优化}

一、经验总结 在递归算法中某些变量需要在回溯到上一层递归后恢复现场&#xff08;如递归路径&#xff09;&#xff0c;恢复现场的方法有&#xff1a; 全局变量手动恢复&#xff1a;如果该变量的类型为自定义类型&#xff08;vector, string等&#xff09;则推荐定义为全局变…

全彩LED显示屏可视角度分析

在当今数字化时代&#xff0c;全彩LED显示屏已成为公共场所、商业中心、体育赛事等场合传递信息与视觉震撼的重要媒介。然而&#xff0c;对于这些显示屏而言&#xff0c;一个关键的技术指标——可视角度&#xff0c;直接决定了观众能否从各个方位享受到一致且优质的视觉体验。本…

SQLserver前五讲课堂笔记

第一讲 基本内容 为什么要学习数据库系统?什么是数据库?什么是数据库系统?什么是数据库管理系统&#xff1f;本课程学什么以及学到什么程度? 重点难点 一组概念的区分&#xff1a;数据库、数据库系统和数据库管理系统熟悉表 的相关要素及术语熟悉数据库系统的构成(工作…

win10怎么截图?电脑截图的3个方法分享

win10怎么截图&#xff1f;在Windows 10操作系统中&#xff0c;截图功能不仅强大而且极其便捷。无论用户需要快速捕捉整个屏幕的内容&#xff0c;还是精确截取屏幕上的特定区域&#xff0c;它都能迅速响应并满足需求。通过内置的截图工具和快捷键&#xff0c;我们可以轻松完成各…

SwiftUI中自定义ViewModifier

在SwiftUI中&#xff0c;ViewModifier是一种强大的工具&#xff0c;用于封装和复用视图修改逻辑。通过创建自定义的ViewModifier&#xff0c;我们可以以一种干净且可维护的方式重用视图配置和样式。本文将介绍如何在SwiftUI中创建和使用自定义ViewModifier。 ViewModifier是一…

【Linux】ls命令

这个命令主要是用于显示指定工作目录下之内容&#xff08;列出目前工作目录所含的文件及子目录)。 掌握几个重点的常使用的就可以&#xff1a; ls -l # 以长格式显示当前目录中的文件和目录 ls -a # 显示当前目录中的所有文件和目录&am…

【内存管理】内存布局

ARM32位系统的内存布局图 32位操作系统的内存布局很经典&#xff0c;很多书籍都是以32位系统为例子去讲解的。32位的系统可访问的地址空间为4GB&#xff0c;用户空间为1GB ~ 3GB&#xff0c;内核空间为3GB ~ 4GB。 为什么要划分为用户空间和内核空间呢&#xff1f; 一般处理器…

BarTender 常见的使用要点

BarTender 简述 BarTender是由美国海鸥科技&#xff08;Seagull Scientific&#xff09;推出的一款条码打印软件&#xff0c;被广泛应用于标签、条形码、证卡和RFID标记的设计和打印领域。它在全球范围内拥有众多用户&#xff0c;被公认为标签打印方面的全球领先者。BarTender…

一.iOS核心动画 - 关于图层与视图

引言 Core Animation听起来会让人误以为它只是用来做动画的&#xff0c;但是事实上它是从Layer Kit库演变而来的&#xff0c;其中做动画的功能只是Core Animation特性的一小部分。 Core Animation是一个复核引起&#xff0c;它的作用就是尽可能快地组合屏幕上不同的显示内容&…

【Vue】getters

除了state之外&#xff0c;有时我们还需要从state中筛选出符合条件的一些数据&#xff0c;这些数据是依赖state的&#xff0c;此时会用到getters getters就类似于属性中的计算属性 这个getter只有获取&#xff0c;如果需要设置修改&#xff0c;还是需要经过mutations getters里…

实验四、零比特插入《计算机网络》

但凡这句话有一点用的话也不至于一点用都没有。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 掌握零比特插入原理及方法使用任意编程语言实现零比特插入方法。 二、实验内容 掌握零比特插入原理及方法 点对点协议 PPP&#xff08;Point-to-Point Protoco…

8.11 矢量图层线要素单一符号使用六(光栅线)

文章目录 前言光栅线&#xff08;Raster Line&#xff09;QGis设置线符号为光栅线&#xff08;Raster Line&#xff09;二次开发代码实现光栅线&#xff08;Raster Line&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中光栅线&#xff08;Raster Line&#xff09;的使…

Navicat导入json文件(json文件数据导入到MySQL表中)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Threejs-05、设置响应式画布与全屏控制。

1、自适应屏幕大小 你会发现,我们前面写好的代码,在页面尺寸发生改变的时候,并不能自适应的改变尺寸,而出现空白或者滚动条突出的情况。所以监听屏幕大小的改变,来重新设置相机的宽高比例和渲染器的尺寸大小,代码如下: // 监听画面变化,更新渲染画面 window.addEven…

删除的东西怎么恢复?5个方法,找回误删数据!

“我刚刚一不小心在电脑上误删了一些数据&#xff0c;想问问大家有什么方法可以恢复删除的东西吗&#xff1f;请帮帮我&#xff01;” 在数据时代&#xff0c;我们每天会在电脑上保存很多重要的数据&#xff0c;这些数据不仅包括我们的学习资料、工作信息&#xff0c;还有各种个…

DeepSORT(目标跟踪算法)中自由度决定卡方分布的形状

DeepSORT&#xff08;目标跟踪算法&#xff09;中自由度决定卡方分布的形状 flyfish 重要的两个点 自由度决定卡方分布的形状&#xff08;本文&#xff09; 马氏距离的平方在多维正态分布下服从自由度为 k 的卡方分布 独立的信息 在统计学中&#xff0c;独立的信息是指数据…

震撼!AI语言模型突破瓶颈,26个提示词原则引领GPT-4响应质量飙升57.7%!你的模型还在等什么?

不是模型不够强大&#xff0c;是你的提示不够精准。 当大型语言模型如ChatGPT在各领域大放异彩时&#xff0c;普通用户却对其指令设计一头雾水。这篇论文揭秘了与模型交流的秘诀&#xff0c;仅凭优化提示&#xff0c;就让GPT-4响应质量和准确性分别飙升57.7%和36.4%&#xff0…

重生奇迹mu套装掉的地点一览

1、目前只有三个地方掉套装&#xff1a;赤色要塞&#xff0c;不是100%掉&#xff0c;靠运气。卡利玛7&#xff0c;杀困顿能掉。魔炼之地&#xff0c;只有城主盟成员可以进入。 2、只有攻城城主盟可以进入的地图“魔炼之地”掉套装&#xff0c;暴率几乎为0。如果你是敏法的话&am…

C++ 判断目标文件是否被占用(独占)(附源码)

在IM软件中发起文件发送时,如果要发送的是某word文件,并且该word文件被office打开,则会提示文件正在被占用无法发送,如下所示: 那文件被占用到底是如何判断出来的呢?其实很简单,调用系统API函数CreateFile,打开该文件(OPEN_EXISTING),传入FILE_SHARE_READ共享读标记…