51单片机与DS18B20温度传感器的通信:原理与实践
51单片机与DS18B20温度传感器的通信:原理与实践
在现代电子技术中,温度监测和控制是一项非常基础且常见的需求。本文将详细介绍如何使用51单片机与DS18B20温度传感器进行通信,实现温度数据的读取和处理。通过这个案例,我们可以深入理解单片机的工作原理以及数字温度传感器的通信协议。
一、引言
在现代电子技术中,温度监测和控制是一项非常基础且常见的需求。本文将详细介绍如何使用51单片机与DS18B20温度传感器进行通信,实现温度数据的读取和处理。通过这个案例,我们可以深入理解单片机的工作原理以及数字温度传感器的通信协议。
二、51单片机简介
51单片机是一种经典的8位微控制器,具有丰富的I/O口资源、定时器/计数器、串行通信接口等功能,广泛应用于嵌入式系统开发中。51单片机以其简单、易用、成本低廉而著称,非常适合用于初学者入门学习。
三、DS18B20温度传感器简介
DS18B20是一款广泛使用的数字温度传感器,它能够提供9位至12位的摄氏温度测量值。该传感器通过单总线协议与单片机进行通信,仅需一根数据线即可实现双向通信,极大地简化了硬件连接。
四、硬件连接
4.1 DS18B20引脚配置
- GND: 电源地
- DQ: 数据输入/输出引脚
- VDD: 可选的电源引脚,可用于寄生电源模式
4.2 与51单片机的连接
由于DS18B20采用单总线协议,因此我们只需要将其DQ引脚连接到51单片机的一个I/O口(例如P3.7),并通过一个上拉电阻接到电源。这样,就可以实现51单片机与DS18B20的通信。
五、软件编程
5.1 初始化DS18B20
在与DS18B20通信之前,首先需要对其进行初始化。初始化过程包括发送复位脉冲并等待传感器响应。
void DS18B20_Init() {
// 定义DS18B20的数据引脚
sbit DQ = P3^7;
// 拉低总线,复位脉冲开始
DQ = 0;
_nop_(); // 稍作延时
DQ = 1; // 释放总线
// 等待DS18B20响应
while(DQ); // 如果接收到响应,退出循环
}
5.2 读写数据位
DS18B20的数据传输基于位操作,每次传输1位数据。写入数据时,先将总线拉低,然后根据要写入的数据(0或1)决定总线的高低状态。读取数据时,先将总线拉低,然后释放总线,通过检测总线的状态读取数据位。
5.2.1 写数据位
void DS18B20_Write_Bit(unsigned char bit) {
// 定义DS18B20的数据引脚
sbit DQ = P3^7;
// 拉低总线
DQ = 0;
_nop_(); // 稍作延时
DQ = bit; // 根据要写入的数据设置总线状态
_nop_(); // 稍作延时
DQ = 1; // 释放总线
_nop_(); // 稍作延时
}
5.2.2 读数据位
unsigned char DS18B20_Read_Bit() {
// 定义DS18B20的数据引脚
sbit DQ = P3^7;
unsigned char bit;
DQ = 0; // 拉低总线
_nop_(); // 稍作延时
DQ = 1; // 释放总线
_nop_(); // 稍作延时
bit = DQ; // 读取总线状态
_nop_(); // 稍作延时
return bit;
}
5.3 读写数据字节
在读写数据位的基础上,我们可以封装出读写数据字节的函数。每次读写操作持续8个时钟周期,完成一个字节的传输。
5.3.1 写数据字节
void DS18B20_Write_Byte(unsigned char byte) {
unsigned char i;
for (i = 0; i < 8; i++) {
DS18B20_Write_Bit(byte & 0x01); // 取最低位
byte >>= 1; // 右移一位,准备下一位
}
}
5.3.2 读数据字节
unsigned char DS18B20_Read_Byte() {
unsigned char i;
unsigned char byte = 0;
for (i = 0; i < 8; i++) {
byte >>= 1; // 左移一位,为新数据位让出位置
if (DS18B20_Read_Bit()) {
byte |= 0x80; // 如果读到1,则将最高位置1
}
}
return byte;
}
5.4 读取温度值
读取温度值的过程包括发送温度转换命令、等待转换完成、发送读暂存器命令并读取数据。
float DS18B20_Read_Temp() {
unsigned char temp_lsb, temp_msb;
int temp;
float temperature;
// 初始化DS18B20
DS18B20_Init();
// 发送温度转换命令
DS18B20_Write_Byte(0xCC); // 跳过ROM指令
DS18B20_Write_Byte(0x44); // 转换命令
// 等待转换完成,通常需要750毫秒左右
delay_ms(750);
// 发送读暂存器命令
DS18B20_Write_Byte(0xCC); // 跳过ROM指令
DS18B20_Write_Byte(0xBE); // 读暂存器命令
// 读取温度值的两个字节
temp_lsb = DS18B20_Read_Byte();
temp_msb = DS18B20_Read_Byte();
// 合并两个字节,并转换为实际温度值
temp = (temp_msb << 8) | temp_lsb;
temperature = temp / 16.0; // 根据DS18B20的数据手册,温度值需要除以16
return temperature;
}
六、全代码
以下是将上述代码整合在一起的完整示例:
#include <reg51.h>
// 定义DS18B20的数据引脚
sbit DQ = P3^7;
// 延时函数
void delay_ms(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 123; j++);
}
// 初始化DS18B20
void DS18B20_Init() {
DQ = 0; // 拉低总线,复位脉冲开始
_nop_(); // 稍作延时
DQ = 1; // 释放总线
// 等待DS18B20响应
while(DQ); // 如果接收到响应,退出循环
}
// 写数据位
void DS18B20_Write_Bit(unsigned char bit) {
DQ = 0; // 拉低总线
_nop_(); // 稍作延时
DQ = bit; // 根据要写入的数据设置总线状态
_nop_(); // 稍作延时
DQ = 1; // 释放总线
_nop_(); // 稍作延时
}
// 读数据位
unsigned char DS18B20_Read_Bit() {
unsigned char bit;
DQ = 0; // 拉低总线
_nop_(); // 稍作延时
DQ = 1; // 释放总线
_nop_(); // 稍作延时
bit = DQ; // 读取总线状态
_nop_(); // 稍作延时
return bit;
}
// 写数据字节
void DS18B20_Write_Byte(unsigned char byte) {
unsigned char i;
for (i = 0; i < 8; i++) {
DS18B20_Write_Bit(byte & 0x01); // 取最低位
byte >>= 1; // 右移一位,准备下一位
}
}
// 读数据字节
unsigned char DS18B20_Read_Byte() {
unsigned char i;
unsigned char byte = 0;
for (i = 0; i < 8; i++) {
byte >>= 1; // 左移一位,为新数据位让出位置
if (DS18B20_Read_Bit()) {
byte |= 0x80; // 如果读到1,则将最高位置1
}
}
return byte;
}
// 读取温度值
float DS18B20_Read_Temp() {
unsigned char temp_lsb, temp_msb;
int temp;
float temperature;
// 初始化DS18B20
DS18B20_Init();
// 发送温度转换命令
DS18B20_Write_Byte(0xCC); // 跳过ROM指令
DS18B20_Write_Byte(0x44); // 转换命令
// 等待转换完成,通常需要750毫秒左右
delay_ms(750);
// 发送读暂存器命令
DS18B20_Write_Byte(0xCC); // 跳过ROM指令
DS18B20_Write_Byte(0xBE); // 读暂存器命令
// 读取温度值的两个字节
temp_lsb = DS18B20_Read_Byte();
temp_msb = DS18B20_Read_Byte();
// 合并两个字节,并转换为实际温度值
temp = (temp_msb << 8) | temp_lsb;
temperature = temp / 16.0; // 根据DS18B20的数据手册,温度值需要除以16
return temperature;
}
void main() {
float temperature;
while (1) {
temperature = DS18B20_Read_Temp(); // 读取温度值
// 这里可以添加代码将温度值显示在LCD上或通过串口发送出去
delay_ms(1000); // 每秒读取一次温度值
}
}
代码说明:
- 硬件连接:DS18B20的GND、VCC和DQ分别连接到51单片机的电源地、电源正极和一个I/O口(P3.7)。为了确保通信稳定,DQ引脚需要接一个上拉电阻。
- 初始化:DS18B20_Init函数用于初始化DS18B20传感器,通过拉低总线并释放来启动复位脉冲。
- 读写操作:DS18B20_Write_Bit和DS18B20_Read_Bit函数分别用于写和读单个位。DS18B20_Write_Byte和DS18B20_Read_Byte函数则用于写和读一个字节。
- 温度读取:DS18B20_Read_Temp函数首先发送温度转换命令,然后等待转换完成,最后读取温度值并返回。
- 主程序:在主程序中,通过调用DS18B20_Read_Temp函数获取温度值,并可以根据需求将温度值显示在LCD上或通过串口发送出去。
七、总结
本文详细介绍了51单片机与DS18B20温度传感器的通信原理及实践方法。通过初始化DS18B20、读写数据位和数据字节,最终实现了温度数据的读取和处理。这一过程不仅展示了51单片机的基本编程技巧,还深入介绍了数字温度传感器的通信协议。希望本文对大家在嵌入式系统开发中的温度监测应用有所帮助。