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

单总线介绍与总结

  • 单总线介绍
  • 单总线时序图
  • 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;//以下时序图均看自己总结的csdnoneWire_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然后再置0i = 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 满足时间切片为60usoneWire_DQ=Bit;//为bit1时代表释放 bit为0时oneWire_DQ继续为0i = 24;while (--i);//延时50usoneWire_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 0010if(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.mzph.cn/news/683272.shtml

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

相关文章

docker (三)-开箱即用常用命令

一 docker架构 拉取镜像仓库中的镜像到本地&#xff0c;镜像运行产生一个容器 registry 镜像仓库 registry可以理解为镜像仓库&#xff0c;用于保存docker image。 Docker Hub 是docker官方的镜像仓库&#xff0c;docker命令默认从docker hub中拉取镜像。我们也可以搭建自己…

【数据结构】二叉树的三种遍历

目录 一、数据结构 二、二叉树 三、如何遍历二叉树 一、数据结构 数据结构是计算机科学中用于组织和存储数据的方式。它定义了数据元素之间的关系以及对数据元素的操作。常见的数据结构包括数组、链表、栈、队列、树、图等。 数组是一种线性数据结构&#xff0c;它使用连续…

18 19 SPI接口的74HC595驱动数码管实验

1. 串行移位寄存器原理&#xff08;以四个移位寄存器为例&#xff09; 1. 通过移位寄存器实现串转并&#xff1a;一个数据输入端口可得到四位并行数据。 通过给data输送0101数据&#xff0c;那么在经过四个时钟周期后&#xff0c;与data相连的四个寄存器的输出端口得到了0101…

【Linux】环境变量及相关指令

一、环境变量的基本概念 其实&#xff0c;我们早就听说过环境变量&#xff0c;比如在学习 JAVA / Python 的时候&#xff0c;会在 Windows 上配置环境变量&#xff1a; 环境变量到底是什么呢&#xff1f; 环境变量&#xff08;environment variables&#xff09;一般是指在操作…

数码管扫描显示-单片机通用模板

数码管扫描显示-单片机通用模板 一、数码管扫描的原理二、display.c的实现1、void Display(void) 各模式界面定义数据2、void BackupRamToDisRam(void)从缓存区刷新显示映射Ram3、void FreshDisplay(void) 映射显示Ram到主控的IO口4、void LcdDisplay_8bit(void) 映射显示Ram到…

C++类和对象-继承->基本语法、继承方式、继承中的对象模型、继承中构造和析构顺序、继承同名成员处理方式、继承同名静态成员处理方式、多继承语法、菱形继承

#include<iostream> using namespace std; //普通实现页面 //Java页面 //class Java //{ //public: // void header() // { // cout << "首页、公开课、登录、注册...&#xff08;公共头部&#xff09;" << endl; // } // voi…

前端秘法基础式(HTML)(第二卷)

目录 一.表单标签 1.表单域 2.表单控件 2.1input标签 2.2label/select/textarea标签 2.3无语义标签 三.特殊字符 一.表单标签 用来完成与用户的交互,例如登录系统 1.表单域 <form>通过action属性,将用户填写的数据转交给服务器 2.表单控件 2.1input标签 type…

六、Mybatis注解开发

1.MyBatis的常用注解 注解开发越来越流行&#xff0c; Mybatis也可以使用注解开发方式&#xff0c;这样就可以减少编写Mapper映射文件。Insert&#xff1a;实现新增Update&#xff1a;实现更新Delete&#xff1a;实现删除Select&#xff1a;实现查询Result&#xff1a;实现结果…

DS:二叉树的顺序结构及堆的实现

创作不易&#xff0c;兄弟们给个三连&#xff01;&#xff01; 一、二叉树的顺序存储 顺序结构指的是利用数组来存储&#xff0c;一般只适用于表示完全二叉树&#xff0c;原因如上图&#xff0c;存储不完全二叉树会造成空间上的浪费&#xff0c;有的人又会问&#xff0c;为什么…

linux 09 软件安装,YUM

下载软件时候&#xff0c;windows会从网上下载exe文件。 windows中的exe文件linux中的rpm文件 简介部分&#xff1a; 其中的认识RPM包&#xff1a; YUM&#xff08;软件包管理工具&#xff09; 01.YUM工具简介 02.使用YUM 第一 安装YUM 全新安装&#xff1a; 01.先pin…

linux系统zabbix监控配置钉钉告警

zabbix配置钉钉告警 配置钉钉告警环境准备配置钉钉脚本文件钉钉日志目录编写脚本浏览器配置钉钉告警中文消息告警模版为用户添加报警媒介添加监控项》添加触发器》 添加玩监控项和触发器后添加动作 配置钉钉告警 环境准备 创建钉钉内部群创建自定义机器人记录加签地址和webho…

Web安全研究(六)

文章目录 HideNoSeek: Camouflaging(隐藏) Malicious JavaScript in Benign ASTs文章结构Introjs obfuscationmethodologyExample HideNoSeek: Camouflaging(隐藏) Malicious JavaScript in Benign ASTs CCS 2019 CISPA 恶意软件领域&#xff0c;基于学习的系统已经非常流行&am…

DS:二叉树的链式结构及实现

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、前言 前期我们解释过二叉树的顺序结构&#xff08;堆&#xff09;为什么比较适用于完全二叉树&#xff0c;因为如果用数组来实现非完全二叉树&#xff0c;那么数组的中间部分就可能会存在大量的空间浪费。 …

Linux操作系统基础(十四):集群服务器搭建

文章目录 集群服务器搭建 一、新增Linux服务器 1、克隆虚拟机 2、修改虚拟机的硬件配置 3、修改虚拟机的网络配置 二、关闭防火墙 1、关闭firewalld 2、关闭SElinux 三、修改主机名 四、修改hosts映射 五、SSH免密登录 六、时钟同步 七、远程文件拷贝 1、从本机拷…

剑指offer——二进制中1的个数

目录 1. 题目描述2. 可能引起死循环的想法3. 改进后的代码4. 给面试官惊喜的代码 1. 题目描述 请实现一个函数&#xff0c;输入一个整数&#xff0c;输出该数二进制表示中1的个数。例如把9表示成二进制位1001&#xff0c;有2位是1&#xff0c;因此如果输入9&#xff0c;该函数输…

Selenium图表自动化开篇

目录 前言&#xff1a; 使用 Canvas 或者 SVG 渲染 选择哪种渲染器 代码触发 ECharts 中组件的行为 前言&#xff1a; 图表自动化一直以来是自动化测试中的痛点&#xff0c;也是难点&#xff0c;痛点在于目前越来越多公司开始构建自己的BI报表平台但是没有合适的自动化测试…

Shell 学习笔记(三)-shell变量

Shell 语言是一种动态类型和弱类型语言, 因此,在Shell中无需显示地声明变量, 且变量的类型会根据不同的操作符而发生变化. 静态类型语言: 在程序编译期间就确定变量类型的语言, 如java, C等 动态类型语言: 在程序运行期间才确定变量类型的语言, 如PHP, Python等. 一 shell变量…

高中信息技术—数据采集与编码(一)

计算机技术的应用&#xff0c;使得数据的处理方式发生了巨大的转变&#xff0c;要用计算机处理这些数据&#xff0c;需要对采集到的数据进行一定的转换。 采集方式 1.人工采集—观察、实验 2.机器采集 互联网—网络爬虫 传感器—自然信源 数字化 信息可用模拟信号或数字信号表…

MySQL学习记录——구 复合查询

文章目录 1、基本查询2、多表查询3、自连接4、子查询1、多行子查询2、多列子查询3、from句中的子查询 5、合并查询 1、基本查询 看一些例子&#xff0c;不关心具体内容&#xff0c;只看写法 //查询工资高于500或岗位为MANAGER的雇员, 同时还要满足他们的姓名首字母为大写的J …

Docker的常见命令以及命令别名

常见命令 命令说明docker pull拉取镜像docker push推送镜像到DockerRegistrydocker images查看本地镜像docker rmi删除本地镜像docker run创建并允许容器docker stop停止指定容器docker start启动指定容器docker restart重新启动容器docker rm删除指定容器docker ps查看容器do…