DS18B20数字温度计这个模块和以往单片机学习的模块可能不同,这里还要知道其头文件(.h)和.c文件代码的理解。
具体这个温度计是怎么实现检测温度的,呃呃呃呃呃这可能就要去查阅专业资料,涉及的知识体系应该很庞大,以下就温度计怎么使用的流程来讲讲。
【进阶强化-01】单总线温度传感器DS18B20的基本原理与应用开发-小蜜蜂笔记 (xmf393.com)
1 DS18B20数字温度计 .c文件代码的理解
芯片手册的阅读起来可能太多,可以看看小蜜蜂老师对.c文件里代码的理解。
单总线数字温度传感器DS18B20的基本原理及开发要点-小蜜蜂笔记 (xmf393.com)
以下结合小蜜蜂老师的文章写一些东东。
1.1 延时函数
延时函数就和我们平时训练的差不多,这里定义的是整数类型t
//单总线延时函数
void Delay_OneWire(unsigned int t)
{
while(t--);
}
1.2 初始化函数(主要是用于复位操作)
总线用DQ表示,0表示拉低,1表示释放总线;定义一个initflag作为复位的标志。
拉低总线(DQ=0)-> 释放总线(DQ=1) -> 复位标志置一(initflag=1) -> 返回复位标志
//DS18B20芯片初始化
bit Init_DS18B20(void)
{
bit initflag = 0;
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(20);
return initflag;
}
1.3 写入函数
注意这里是把dat写入,而且是一位一位写。DQ = dat&0x01; 就保证了每次只写一个数据。
//DS18B20的写操作底层驱动代码参考--51版
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0; //先拉低总线电平10~15us
DQ = dat&0x01; //向总线写入一个位数据
Delay_OneWire(5); //维持状态20~45us
DQ = 1; //释放总线
dat >>= 1; //准备发送下一个数据位
}
}
1.3 读取函数
读取函数最终返回的是是dat的值,这里也是dat按位来读取,
//DS18B20的读操作底层驱动代码参考--51版
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0; //先将总线电平拉低10~15us
dat >>= 1;
DQ = 1; //然后释放总线
if(DQ) //读取总线上的电平状态
{
dat |= 0x80;
}
Delay_OneWire(5); //延时45us左右,再度下一个数据位
}
return dat;
}
2 DS18B20 的 .h文件
.h 头文件头文件主要是做一些函数声明,定义等。
现在把这个划分成几个部分来讲解以下:首先DS18B20的两个文件名如下:
#ifndef _XMF_DS18B20_H
#define _XMF_DS18B20_H
#include "reg52.h"
#define OW_SKIP_ROM 0xcc
#define DS18B20_CONVERT 0x44
#define DS18B20_READ 0xbe
//IC引脚定义
sbit DQ = P2^2;
//函数声明
void Delay_OneWire(unsigned int t);
void Write_DS18B20(unsigned char dat);
bit Init_DS18B20(void);
unsigned char Read_DS18B20(void);
#endif
2.1 ifndef define endif
- #ifndef:如果未定义)用于判断指定的标识符是否已经被定义。如果该标识符未定义,则执行下面的代码块,否则跳过。
- #define: 用于定义指定的标识符,通常用于定义宏。在条件编译中,一般用来定义一个标识符,以便在后面的代码中进行条件判断。
- #endif :用于结束条件编译的代码块
(参考【#ifndef, #define, 和 #endif】_#ifndef #define #endif-CSDN博客)
可以看到,文件开头用了#ifndef 和 #define+(_ 文件名_H)的形式进行了宏定义,文件末尾还用了#endif(注意定义的时候文件名要大写,即使保存文件名的时候用的是小写。)
2.2 使用了reg52.h的头文件 和引脚定义
使用了red52.h 的头文件,并定义了DQ引脚。
2.3 定义了三个重要指令
用define定义了三个指令。
CCH:跳过ROM指令。忽略64位ROM地址,直接向DS18B20发起各种执行指令。
44H:温度转换指令。启动DS18B20进行温度转换。
BEH:读取暂存器指令。DS18B20收到该指令后,会逐个输出高速暂存器中字节0到字节9的内容。如果要停止读取,必须进行复位操作。如果只需要读取温度数据,那么,在读完第0个字节和第1个字节数据后,不再理会DS18B20后面发出的数据即可。
2.4 对.c文件用到的函数进行声明。
.c 使用了四个函数, 直接复制过来即可。
3 温度换算原理及使用方法
3.1 使用方法
这里的使用方法较为套公式化,只要记住相关步骤写入代码即可。
这里同样参考小蜜蜂老师的那篇文章以及代码。
微处理器读取单个DS18B20的温度数据,可参考以下步骤:
【1】DS18B20复位。
【2】写入字节0xCC,跳过ROM指令。
【3】写入字节0x44,开始温度转换。
【4】延时700~900ms。
【5】DS18B20复位。
【6】写入字节0xCC,跳过ROM指令。
【7】写入字节0xBE,读取高速暂存器。
【8】读取暂存器的第0字节,即温度数据的LSB。
【9】读取暂存器的第1字节,即温度数据的MSB。
【10】 DS18B20复位。,表示读取数据结束。
【11】将LSB和MSB整合成为一个16位数据。
【12】判断读取结果的符号,进行正负温度的数据处理。
float Read_Temperature()
{
float temp;
unsigned char LSB,MSB;
unsigned int dat = 0;
init_ds18b20(); //初始化DS18B20
Display_Num();
Write_DS18B20(0xcc); //忽略ROM操作
Write_DS18B20(0x44); //启动温度转换
Delay(1000); //等待温度转换完成
init_ds18b20(); //初始化DS18B20
Write_DS18B20(0xcc); //忽略ROM操作
Write_DS18B20(0xbe); //读出内部存储器
LSB = Read_DS18B20(); //第0字节:温度低8位
MSB = Read_DS18B20(); //第1字节:温度高8位
init_ds18b20(); //初始化DS18B20,停止数据读取
//上述程序中插入多处数码管刷新,可使显示亮度充足
dat = MSB;
dat = (dat << 8) | LSB; //合并为16位温度原始数据
//判断符号,处理正温度
if((dat & 0xf800) == 0x0000)
{
temp = dat * 0.0625; //计算实际温度值
}
return temp;
}
上述代码的前面部分主要是按步骤来走并且定义一些你可能用到的变量。主要是以下这部分温度转换需要知道是怎么来的。
3.2 温度换算的原理
由图,其数据由两个寄存器LSB和MSB组成16位,(MSB为高8位,LSB为低8位)且为二进制补码形式读出。
低4位为小数部分,中间7位为整数部分。
高5位为扩展符号位,即BIT15~BIT11为00000,读出的数据为正温度,若为11111,则为负温度。
比如常见的温度对应的值小蜜蜂老师也总结了起来!!(大爱)
注意:在上电复位的时候,温度寄存器中的值为0x0550,即+85摄氏度。所以在应用开发中,有些朋友一直读到的数据都是85.5摄氏度,就说明DS18B20根本没有进行温度转换,你读到的是上电复位的初始值。
换算之前首先要把两个寄存器的16位进行合并。
可以使用以下代码,先把高8位的MSB值赋给变量dat,然后再把变量像左移动8位,其实就是为LSB的低8位腾出位置,然后再或上LSB。
dat = MSB;
dat = (dat << 8) | LSB; //合并为16位温度原始数据
合并完16位后,就可以进行温度的换算率,换算原理小蜜蜂老师是这样写的:
从输出数据与温度值的关系表中可知,DS18B20的分辨率为0.0625。(最小分辨率即最小单位,这里最小为2的-4次方,等于0.0625(4位小数))
读出数据为正温度时,将LSB和MSB整合成的16位整数,直接乘以0.0625即可。(n个0.0625嘛)
读出数据为负温度时,则需要将LSB和MSB整合成的16位整数,取反加1后,再乘以0.0625,因为温度数据是以补码形式表示的。
例如:
读出结果为00A2H,温度值 = 162×0.0625 = 10.125 摄氏度。
读出结果为FF5EH,取反加1就是00A2H,温度值则为 -10.125 摄氏度。
欢迎指正。