单片机学习笔记---DS18B20温度读取

news2024/11/30 10:44:58

目录

OneWire.c

模拟初始化的时序

模拟发送一位的时序

 模拟接收一位的时序

模拟发送一个字节的时序

模拟接收一个字节的时序

OneWire.h

DS18B20.c

DS18B20数据帧

模拟温度变换的数据帧

模拟温度读取的数据帧

DS18B20.h

main.c


上一篇讲了DS18B20温度传感器的工作原理,这节开始代码演示!

新创建一个工程:DS18B20温度读取

将前面我们学过的几个模块化代码添加进来

然后创建main.c,DS18B20.c,DS18B20.h,OneWire.c和OneWire.h文件

开始代码讲解:

OneWire.c

首先我们根据原理图定义引脚

#include <REGX52.H>

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

我们再根据上一篇讲的时序逐个定义函数写在OneWire.c里面 

模拟初始化的时序

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

unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;//返回值,应答位
	OneWire_DQ=1;//拉低之前确保是释放状态
    //因为我们在执行任何操作的时候都可以用初始化来打断它,
    //所以总线再初始化的时候还是有可能处于0的状态,所以先把它拉高再拉低
	OneWire_DQ=0;

	i = 247;while (--i);		//Delay 500us
	OneWire_DQ=1;//释放

    //等待15~60us后,存在的从机会拉低总线60~240us以响应主机
	i = 32;while (--i);			//Delay 70us
    //我们直接延时70us后肯定已经到了从机拉低总线的状态了

    //然后直接可以读了
	AckBit=OneWire_DQ;//把IO口电平读出来赋值给应答位
    
    //初始化时有两个部分(复位和响应),
    //每一部分时序至少480us,这部分我们已经Delay了70微秒,
    //为了将这段时序走完,再Delay 500us,那么这个时序肯定就走完了
	i = 247;while (--i);		//Delay 500us
	
    //最后是从机将释放总线,我们主要写主机的代码,
    //不体现从机的代码,所以不用管最后释放的这一步

    return AckBit;//返回应答位
}

 怎么产生Delay 500us的那一行代码呢?

 

但因为我们初始化的条件说的是主机将总线拉低至少480us,为了保险起见,我们最好Delay500us

将500微秒的主体部分复制过来就是我们代码里的这部分:

模拟发送一位的时序

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

void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
    //在这一步之前先给它置1也行,但是考虑到初始化后它一定是1了
	OneWire_DQ=0;//所以直接拉低就行

    //主机将总线拉低60~120us,然后释放总线,表示发送0;
    //主机将总线拉低1~15us,然后释放总线,表示发送1
    //因此我们直接在10微秒的时候把bit放在线上
    //如果是0的话它肯定一直都是0,不会变化
    //如果是1的话它就会变成高位
	i = 4;while (--i);			//Delay 10us
    //由于调用一个函数就已经用了4us,所以我们直接生成一个14us的函数
	OneWire_DQ=Bit;//把bit放在线上
    
    //从机将在总线拉低30us后(典型值)读取电平,整个时间片应大于60us
    //我们已经Delay了10us,(4us是调用一个函数的时间)
    //再生成一个Delay 54us的代码就走完了时序(4us是调用一个函数的时间)
	i = 24;while (--i);			//Delay 50us
	
    OneWire_DQ=1;//释放
}

 模拟接收一位的时序

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

unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	OneWire_DQ=0;//拉低
    //Delay 5us就生成9us的代码(因为调用函数就是4us了)
    //在这段时间里从机接着也拉低总线(我们写是主机的代码,不体现从机)
	i = 2;while (--i);			//Delay 5us
	OneWire_DQ=1;//释放
    
    //因为释放需要一定的时间,所以需要Delay
    //如果释放后立马读的话可能来不及恢复变成1
	i = 2;while (--i);			//Delay 5us

	Bit=OneWire_DQ;//读取并赋给Bit
    
	i = 24;while (--i);			//Delay 50us
	return Bit;//返回Bit
}

模拟发送一个字节的时序

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

void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));//从低位到高位
	}
}

模拟接收一个字节的时序

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

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;
}

OneWire.h

在OneWire.c声明一下这些函数

#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__

unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);

#endif

DS18B20.c

我们要在这文件中分别调用前面我们写好的函数,完成上一篇博客讲的这个数据帧

先定义一下我们要用到的三个指令:跳过ROM,温度变换,读暂存器。

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

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

DS18B20数据帧

模拟温度变换的数据帧

温度变换:初始化→跳过ROM →开始温度变换

void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

模拟温度读取的数据帧

温度读取:初始化→跳过ROM →读暂存器→连续的读操作

除了写温度读取的数据帧之外,我们还要把读出来的两个温度字节合成16位并转换成十进制的温度值

float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;//暂存器的第一个字节和第二个字节
	int Temp;//中间变量
	float T;//T表示实际温度,float型既可以表示正负也可以表示小数
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
    //一旦发完这个指令,总线的控制权就交给从机了

	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
    //这样就把暂存器里前两个字节(温度字节的数据)给读出来了

    //转换温度
	Temp=(TMSB<<8)|TLSB;//两个字节合成16位
    //TMSB<<8将第二个字节放到高位上

    //无符号的TLSB,TMSB合成16位数后本身包含了符号位
    //无符号的转换成有符号的int内容没有改变
    //我们可以通过上面的示例图看到合成16位后bit4才是温度整数值的最低位
    //二进制数向左挪一位和乘以2是一样的,往左挪4位就是乘以16
    //因为实际值的最后一位代表2的-4次方,变为2的0次方相差16倍
    //为了不损失精度,就将Temp往右挪4位,转换成实际温度就除以16


    //如果还是看不懂的话,可以用十进制来做个类比:比如本来是1.0001结果把小数点擦掉饿了,
    //是不是成了10001,这就扩大了一万倍,想要准确的话就要除以1000

    //这就可以理解了,我们将两个字节拼成了16位的二进制数据之后赋给int型的Temp,
    //那么我们16就都成了整数了,
    //为了保证最后四位还是我们的小数位,就要将小数点往左移4位,那么除以几呢?
    //2的-4次方到2的0次方相差16倍,相当于Temp比实际的温度值T扩大了16倍,想要得到T那就是除以16

	T=Temp/16.0;
	return T;
}

DS18B20.h

声明一下这两个函数

#ifndef __DS18B20_H__
#define __DS18B20_H__

void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);

#endif

main.c

先定义一个实际温度值T

#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);//显示温度小数部分
        //T*10000将小数挪成整数部分
        //(unsigned long)(T*10000)强制类型转换成(unsigned long),因为它超过了unsigned int
        //小数部分丢弃并且能够取余了
        //(T*10000)%10000得到10000的后四位
	}
}

效果请看视频:

DS18B20温度读取

以上就是本节的内容,源码会放在评论区,有问题可以评论区留言!

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

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

相关文章

[GYCTF2020]Blacklist

感觉是[强网杯 2019]随便注 的加强版&#xff0c;之前做的是最后可以通过prepare和execute实现对select的绕过&#xff0c;但是这题把这两个关键字也过滤了。 前面堆叠注入没啥问题&#xff0c;卡在了最后读取flag 查看其他师傅的wp&#xff0c;发现这个handler的可以当作丐版s…

CSGO搬砖项目怎么样?分享一下个人的看法!

对于steam搬砖平台&#xff0c;无人不知&#xff0c;无人不晓啊&#xff0c;全球最大的一个游戏平台&#xff0c;像我们知道的PUBG&#xff0c;CS:GO&#xff0c;都是里面的&#xff0c;比较火的一个平台。 对于想了解Steam搬砖的&#xff0c;今天分享一下个人的看法。 首先&a…

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

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

[缓存] - 2.分布式缓存重磅中间件 Redis

1. 高性能 尽量使用短key 不要存过大的数据 避免使用keys *&#xff1a;使用SCAN,来代替 在存到Redis之前压缩数据 设置 key 有效期 选择回收策略(maxmemory-policy) 减少不必要的连接 限制redis的内存大小&#xff08;防止swap&#xff0c;OOM&#xff09; slowLog …

单片机学习笔记---LCD1602功能函数代码

目录 LCD1602.c 模拟写指令的时序 模拟写数据的时序 初始化 显示字符 显示字符串 显示数字 显示有符号的数字 显示16进制数字 显示二进制数 LCD1602.h main.c 上一篇讲了LCD1602的工作原理&#xff0c;这一节开始代码演示&#xff01; 新创建工程&#xff1a;LCD1…

HGAME 2024 WEEK2 WP

文章目录 WEBWhat the cow say?Select More Coursesmyflask CryptomidRSAmidRSA revengebackpackbackpack revengebabyRSA奇怪的图片plus MISC我要成为华容道高手ek1ng_want_girlfriendezWord龙之舞 回老家了&#xff0c;初七晚上才回去&#xff0c;估计week3前几天不怎么能做…

Android14之Android Rust模块编译语法(一百八十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

SPFA最短路复习

文章目录 从Bellman-Ford开始核心思想模拟算法执行过程时间复杂度模板 spfaspfa优化的思想模板 从Bellman-Ford开始 对于所有边权都大于等于0的图&#xff0c;任意两个顶点之间的最短路&#xff0c;显然不会经过重复的顶点或者边。也就是说任意一条最短路经过的定点数不会超过…

《汇编语言》- 读书笔记 - 第9章 - 转移指令的原理

《汇编语言》- 读书笔记 - 第9章 - 转移指令的原理 总结9.1 操作符 offset问题 9.1 9.2 jmp 指令9.3 依据位移进行转移的 jmp 指令jmp short 标号程序 9.1程序 9.2图 9.2 程序 9.2 的机器码 jmp near ptr 标号 9.4 转移的目的地址在指令中的 jmp 指令如何选择 jmp short、jmp n…

Github用人工智能(AI)帮你的代码修正安全漏洞

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Java:继承——继承概念+父子类成员、构造访问顺序+super、this关键字(代码+画图超详解!)

一、什么是继承 1、继承的概念 举例理解&#xff1a; 根据打印机的原理&#xff0c;我们可以知道不管是彩色打印机还是黑白打印机&#xff0c;实现的都是一个功能&#xff1a;打印&#xff0c;这是二者的共性。彩色打印机和黑白打印机都继承了打印机的打印功能&#xff0c;且二…

基于T1w/T2w 比值揭示髓磷脂相关变化

前言&#xff1a; 最近在阅读文献的时候发现2篇文章&#xff0c;是采用T1w/T2w 比值表征髓磷脂&#xff0c;有点感兴趣&#xff0c;因此尝试了一下文献所提出的方法。&#xff08;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC9247578/ https://www.ncbi.nlm.nih.gov/pmc/ar…

vue的网络请求以及封装

①先备好springboot的接口 ②安装依赖 在vue中安装网络请求工具的依赖&#xff1a; npm i axios③简单的demo 直接通过axios请求尝试一下&#xff1a; <script> import axios from "axios";export default {name: HomeView,data() {return {users:[]}}, …

言语残疾和言语残疾分级

言语残疾和言语残疾分级 言语残疾&#xff0c;指各种原因导致的不同程度的言语障碍&#xff0c;经治疗一年以上不愈或病程超过两年&#xff0c;而不能或难以进行正常的言语交流活动&#xff0c;以致影响其日常生活和社会参与。包括&#xff1a;失语、运动性构音障碍、器质性构音…

app移动应用开发

1.案例7.安安的通讯助手 目标 组件设计 素材准备 所有组件的说明及属性设置&#xff08;1&#xff09; 所有组件的说明及属性设置&#xff08;2&#xff09; 所有组件的说明及属性设置&#xff08;3&#xff09;布局小技巧 行为逻辑设计 自动回复短信 短信收发器 组件 记录已收…

MongoDB部署策略

内 容 简 介 本文介绍了MongoDB数据库的优点的数据存储模式的安装部署过程。 利用MongoDB在存储海量数据上的优势&#xff0c;部署存储空间大数据。 欢迎批评指正补充 由于编者水平有限&#xff0c;所搜集资料也很有限&#xff0c;制定的规范肯定有考虑不周全、甚至完全错误…

利用路由懒加载和CDN分发策略对极客园项目进行性能优化

文章目录 前言1.配置路由懒加载2.项目资源打包3.包体积可视化分析4.cdn配置 总结 前言 极客园项目的完成之后&#xff0c;我们需要对项目进行打包以及性能优化&#xff0c;优化用户体验以及加快响应时间&#xff0c;本文只列举了路由懒加载和cdn分发的策略 1.配置路由懒加载 …

Spring Security学习(四)——登陆认证(包括自定义登录页)

前言 和前面的文章隔了很长时间才更新Spring Security系列&#xff0c;主要原因一个是之前太忙了&#xff0c;把项目都忙完了&#xff0c;赶上春节假期&#xff0c;就慢慢研究。Spring Security的体系非常复杂&#xff0c;一口吃不了热豆腐&#xff0c;没办法速成&#xff0c;…

​StableSwarmUI#超越文本的prompt

今天看到一个新的webui方案&#xff0c;是Stability-AI开源的&#xff1a; StableSwarmUI 是一个模块化的稳定扩散web用户界面&#xff0c;着重于使强大的工具易于访问、高性能和可扩展性。 由于项目还在开发中&#xff0c;我们可以先了解下&#xff0c;翻看了它的特点&#xf…

年假作业11

一、选择题 ADDAADADC&#xff0c;BD,D,B,BD,D,C,CD 二、填空题 6 2&#xff0c;3,5,7,9 rgb *s, - a 2,5 *s 三、编程题 1、 #include <iostream> using namespace std; int main() {int arr[10]{10,20,30,40,50,60,70,80,90,100};int m;//从标准输入读取一个…