文章目录
- 引言
- 电路图
- 引脚讲解
- 初始化时序
- 写时序
- 读时序
- 温度变换
- 温度读取
- 完整代码
引言
DS18B20是一款单总线接口的数字温度传感器,仅需一个IO口即可实现数据通信。这里只对如何简单操作开发板的DS1802进行讲解,关于DS18B20温度传感器的详细操作原理,可参考此博客:DS18B20数字温度传感器操作解析。
电路图
下图显示了DS18B20的电路连接。数据总线通过J14排针引出,并连接到所选的IO口。数据总线上需要一个上拉电阻以确保稳定的通信。
引脚讲解
DS18B20传感器通常采用TO-92封装或PDIP封装,具有以下三个主要引脚:
- VDD - 电源正极,为传感器提供工作电压。
- GND - 电源负极,接地。
- DQ - 数据引脚,用于与微控制器或计算机进行数据通信。
引脚详解
- VDD: 连接到传感器的工作电压,通常为3.3V或5V。确保不要超过传感器的最大工作电压,以避免损坏。
- GND: 连接到电路的地线,确保传感器的稳定工作。
- DQ: 是一个开漏输出引脚,需要通过上拉电阻连接到VDD。这个引脚负责与主控制器进行通信,支持1-Wire通信协议。
初始化时序
初始化过程从主机发送复位脉冲开始。主机将总线拉低至少480微秒(us),通常是500us,以确保所有从设备都能检测到复位信号。复位脉冲后,总线需保持高电平15-60微秒,等待从设备响应。
从设备通过发送存在脉冲来响应,表示它们已经检测到复位信号,并将总线拉低60-240微秒。表明它已检测到复位信号。之后将电平拉高。
sbit DS18B20_DQ = P3^7;
unsigned char DS18B20_Init()
{
unsigned char i;
unsigned char ackBit;
DS18B20_DQ = 1;
DS18B20_DQ = 0;
i = 247;
while (--i); //延时500us
DS18B20_DQ = 1;
i = 32;
while (--i);
ackBit = DS18B20_DQ;
i = 247;
while (--i); //延时500us
return ackBit;
}
写时序
写时序包括主机发送数据位“0”或“1”到从设备。每个位的写入时序稍有不同。每次写入一个数据位都需要初始化一个写周期。主机将总线拉低至少1微秒(通常是1-15微秒),然后释放总线,这是初始化写周期。
写0时序:
- 主机将总线拉低至少60微秒(通常是60-120微秒),然后释放总线。
写1时序:
- 主机将总线拉低至少1微秒(通常是1-15微秒),然后在剩余时间内保持高电平(释放总线)。
写入一个字节(8位)需要重复上述写0和写1时序八次。写入顺序为低位在前(LSB first)。
- 开始写入字节:初始化第一个写周期。
- 写入每个位:根据数据位的值,执行写0或写1时序。
- 结束写入字节:完成8个位的写入后,字节写入结束。
假设我们要写入字节0x5A(01011010)。
- 写入0位:主机将总线拉低至少60微秒,释放总线。
- 写入1位:主机将总线拉低至少1微秒,释放总线。
- 写入0位:重复写0时序。
- 写入1位:重复写1时序。
- 写入1位:重复写1时序。
- 写入0位:重复写0时序。
- 写入1位:重复写1时序。
- 写入0位:重复写0时序。
//发送一位
void ds18b20_write_bit(unsigned char bits)
{
unsigned char i;
DS18B20_DQ = 0;
i = 4;
while (--i); //延时10us
DS18B20_DQ = bits;
i = 24;
while (--i); //延时50us
DS18B20_DQ = 1;
}
//发送字节
void ds18b20_write_byte(unsigned char byte)
{
unsigned char i;
for(i = 0;i<8;i++)
{
ds18b20_write_bit(byte & 0x01<<i);//先发送低位
}
}
读时序
每次读取一个数据位都需要初始化一个读周期。初始化读周期期间需要主机将总线拉低至少1微秒(通常是1-15微秒),然后释放总线。之后读取数据位,主机在读周期内读取从设备发送的数据位。需要主机将总线拉低至少1微秒(通常是1-15微秒)。然后释放总线,主机释放总线,并在15微秒内读取总线状态。读取数据位期间如果总线保持低电平,读取到的数据位为0;如果总线拉高,读取到的数据位为1。要读取一个字节(8位),需要重复上述读取数据位的过程八次,按低位在前(LSB first)的顺序读取。
假设我们要读取一个字节的数据,具体步骤如下:
- 初始化读周期:主机将总线拉低至少1微秒,然后释放总线。
- 读取每个位:在读周期内,主机读取从设备发送的每个位数据。
- 完成字节读取:重复上述步骤八次,读取一个完整的字节。
//接收一位
unsigned char ds18b20_read_bit()
{
unsigned char i;
unsigned char bits;
DS18B20_DQ = 0;
i = 2;
while (--i); //延时5us
DS18B20_DQ = 1;
i = 2;
while (--i); //延时5us
bits = DS18B20_DQ;
i = 24;
while (--i); //延时50us
return bits;
}
unsigned char ds18b20_read_byte()
{
unsigned char i;
unsigned char byte = 0x00;
for(i = 0;i<8;i++)
{
if(ds18b20_read_bit())
{
byte |= 0x01<<i;
}
}
return byte;
}
温度变换
DS18B20温度传感器的温度转换功能允许用户读取精确的温度数据。为了实现温度转换,必须遵循特定的时序和命令流程。
温度转换流程包括以下几个主要步骤:
- 发送初始化命令:主机需要发送初始化命令来复位总线并检测从设备的存在。
- 跳过ROM命令:向总线上的所有设备广播命令。所有设备都会响应接下来的命令。
- 发送启动温度转换命令:0x44用于启动温度转换(Convert T)
//转换温度
void ds18b20_ConvertT()
{
DS18B20_Init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0x44);
}
温度读取
读取DS18B20温度传感器的数据是一个包括命令发送和数据处理的过程。
温度读取过程包括以下几个主要步骤:
- 发送初始化命令:主机需要发送初始化命令来复位总线并检测从设备的存在。
- 跳过ROM命令:向总线上的所有设备广播命令。所有设备都会响应接下来的命令。
- 发送读暂存器命令:用于从DS18B20传感器的暂存器中读取温度数据、报警阈值和配置寄存器信息。
先读取低位,后读取高位,温度数据是16位带符号的二进制数,最低位代表
2
−
4
2^{-4}
2−4摄氏度(即0.0625摄氏度)
//读取温度
float ds18b20_ReadT()
{
unsigned char byteL;
unsigned char byteH;
int temp;
float T;
DS18B20_Init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE);
byteL = ds18b20_read_byte();//低字节
byteH = ds18b20_read_byte();//高字节
temp = (byteH << 8) | byteL;
T = temp / 16.0;
return T;
}
完整代码
LCD1602液晶显示屏实时获取温度变化
#include <REGX52.H>
#include <LCD1602.H>
#include "stdio.h"
sbit DS18B20_DQ = P3^7;
unsigned char DS18B20_Init()
{
unsigned char i;
unsigned char ackBit;
DS18B20_DQ = 1;
DS18B20_DQ = 0;
i = 247;
while (--i); //延时500us
DS18B20_DQ = 1;
i = 32;
while (--i);
ackBit = DS18B20_DQ;
i = 247;
while (--i); //延时500us
return ackBit;
}
//发送一位
void ds18b20_write_bit(unsigned char bits)
{
unsigned char i;
DS18B20_DQ = 0;
i = 4;
while (--i); //延时10us
DS18B20_DQ = bits;
i = 24;
while (--i); //延时50us
DS18B20_DQ = 1;
}
//接收一位
unsigned char ds18b20_read_bit()
{
unsigned char i;
unsigned char bits;
DS18B20_DQ = 0;
i = 2;
while (--i); //延时5us
DS18B20_DQ = 1;
i = 2;
while (--i); //延时5us
bits = DS18B20_DQ;
i = 24;
while (--i); //延时50us
return bits;
}
//发送字节
void ds18b20_write_byte(unsigned char byte)
{
unsigned char i;
for(i = 0;i<8;i++)
{
ds18b20_write_bit(byte & 0x01<<i);//先发送低位
}
}
unsigned char ds18b20_read_byte()
{
unsigned char i;
unsigned char byte = 0x00;
for(i = 0;i<8;i++)
{
if(ds18b20_read_bit())
{
byte |= 0x01<<i;
}
}
return byte;
}
//转换温度
void ds18b20_ConvertT()
{
DS18B20_Init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0x44);
}
//读取温度
float ds18b20_ReadT()
{
unsigned char byteL;
unsigned char byteH;
int temp;
float T;
DS18B20_Init();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE);
byteL = ds18b20_read_byte();//低字节
byteH = ds18b20_read_byte();//高字节
temp = (byteH << 8) | byteL;
T = temp / 16.0;
return T;
}
unsigned char ack = 1;
float g_T;
void main()
{
char temp_buff[50];
LCD_Init();
LCD_ShowString(1,1,"helloworld");
ack = DS18B20_Init();
LCD_ShowNum(2,1,ack,3);
while(1)
{
ds18b20_ConvertT();
g_T = ds18b20_ReadT();
if(g_T<0)
{
//负数
LCD_ShowChar(2,1,'-');
g_T = -g_T;
}
else
{
LCD_ShowChar(2,1,'+');
}
// 使用 sprintf 将浮点数转换为字符串
sprintf(temp_buff, "%.3f", g_T);
LCD_ShowString(2,2,temp_buff);
}
}