其他分享
首页 > 其他分享> > 单片机学习(十二)1-Wire通信协议和DS18B20温度传感器

单片机学习(十二)1-Wire通信协议和DS18B20温度传感器

作者:互联网

目录

一、DS18B20

1. DS18B20简介

DS18B20是一种常见的数字温度传感器,其控制命令和数据都是以数字信号的方式输入输出,相比较于模拟温度传感器,具有功能强大、硬件简单、易扩展、抗干扰性强等特点

2. 电路原理图

image-20210909130231679

其中1和3号引脚分别连接GNDVCC,而二号引脚则用于使用1-Wire(单总线)接口进行通信。

即:

image-20210909131028390

3. 内部结构

内部完整结构框图

image-20210909155650282

其中配置寄存器可以配置温度变化的精度值。

存储器结构

image-20210909160511275

当我们希望修改EEPROM中存储的内容时,我们需要先将数据写入到暂存器中,然后再发送一条指令使从机将暂存器中的数据写入到EEPROM中。

二、单总线(1-Wire BUS)

由于DS18B20使用的通信接口是1-Wire,因此我们需要学习1-Wire相关的通信协议,这样才能使单片机和它进行通信。

1. 单总线简介

单总线(1-Wire BUS)是由Dallas公司开发的一种通用数据总线

2. 电路规范

image-20210909161424463

3. 单总线的时序结构

① 初始化

对应的信号时序图:

image-20210909161912440

② 发送一位

对应的信号时序图:

image-20210909162154023

③ 接收一位

对应的信号时序图:

image-20210909162353560

④ 发送一个byte和接收一个byte

这个过程和使用I2C发送和接收一个字节的数据的过程类似,都是重复发送一位或接受一位8次即可发送或接受一个byte的数据了:

image-20210909162748561 image-20210909162805563

注意发送和接收到的数据都是低位在前的。

4. DS18B20操作流程

对应的ROM操作和功能操作的指令如下:

ROM指令 功能指令
SEARCH ROM [0xF0] CONVERT T [0x44]
READ ROM [0x33] WRITE SCRATCHPAD [0x4E]
MATCH ROM [0x55] READ SCRATCHPAD [0xBE]
SKIP ROM [0xCC] COPY SCRATCHPAD [0x48]
ALARM SEARCH [0xEC] RECALL E2 [0xB8]
READ POWER SUPPLY [0xB4]

各个功能指令的作用:

  1. CONVERT T:使用温度传感器更新温度值
  2. WRITE SCRATCHPAD:将各个EEPROM中的值写入到暂存器中
  3. READ SCRATCHPAD:读取暂存器中的值
  4. COPY SCRATCHPAD:将暂存器中的内容复制到EEPROM中
  5. RECALL E2:将EEPROM中的内容复制到暂存器中
  6. READ POWER SUPPLY:读取设备的供电模式【独立供电|寄生供电】

5. DS18B20数据帧

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

image-20210909163413495

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

image-20210909163445714

6. 温度的存储格式

里面的温度是使用补码形式存储的,具体的例子如下:

image-20210909164515148 image-20210909164722612

温度表示的范围是-55到+125度

三、编码实现

1. 单总线部分

我们将这部分编写到OneWire模块中

首先是DQ引脚,根据电路原理图我们可以知道他对应的是芯片的P37引脚,因此先把它定义出来:

sbit OneWire_DQ = P3 ^ 7;

① 初始化

image-20210909161912440
unsigned char OneWire_Init() {
    unsigned char i;
    unsigned char Ack;
    EA=0;
    {
        OneWire_DQ = 1;
        OneWire_DQ = 0;         // 拉低
        i = 227; while (--i);   // delay 500μs
        OneWire_DQ = 1;         // 释放
        
        i = 29; while (--i);    // delay 70μs,等待从机将电平拉低
        // 获取从机应答
        Ack = OneWire_DQ;
        i = 227; while (--i);   // delay 500μs 等待时序走完
    }
    EA=1;
    // 将从机应答返回,0表示有应答,1表示无应答
    return Ack;
}

可以发现,我们的代码中出现了EA=0;EA=1;,这两句代码分别是操作终端系统的总开关进行关闭和开启中断系统的,因为在单总线发送信号的过程中,如果突然来了中断,CPU转而运行中断程序,那么延时就会受到巨大的影响

例如当前运行到delay 70μs的位置,此时来了一个中断信号,当运行完中断程序回来的时候,可能就已经延时了10ms了,这对单总线通信的影响是致命的,故我们在使用单总线发送或接受信号时都需要先关闭中断

tips:其中的延时代码都是使用stc-isp软件进行生成的,在生成代码时需要注意晶振和8051指令集的选择:

image-20210910120545180

② 发送一位

image-20210909162154023
void OneWire_SendBit(unsigned char Bit) {
    unsigned char i;
    EA=0;
    {
        OneWire_DQ = 0;         // 拉低
        i = 3; while (--i);     // delay 10μs  
        // 若为1则释放总线,代表发送1;若为0一直为低电平,代表发送0
        OneWire_DQ = Bit;
        i = 22; while (--i);    // delay 50μs
        OneWire_DQ = 1;         // 最后释放总线
    }
    EA=1;
}

③ 接收一位

image-20210909162353560
unsigned char OneWire_ReceiveBit() {
    unsigned char i;
    unsigned char Bit;
    EA=0;
    {
        OneWire_DQ = 0;         // 拉低
        i = 1; while (--i);     // delay 5μs
        OneWire_DQ = 1;         // 释放
        i = 1; while (--i);     // delay 5μs
        Bit = OneWire_DQ;       // 采样
        i = 22; while (--i);    // delay 50μs
    }
    EA=1;
    return Bit;
}

④ 发送一个byte和接收一个byte

image-20210909162748561
void OneWire_SendByte(unsigned char byte) {
    unsigned char i;
    for(i = 0; i < 8; i++) {
        OneWire_SendBit(byte & (0x01 << i));
    }
}
image-20210909162805563
unsigned char OneWire_ReceiveByte() {
    unsigned char i;
    unsigned char byte = 0x00;
    for(i = 0; i < 8; i++) {
        if(OneWire_ReceiveBit()) {
            byte |= (0x01 << i);
        }
    }
    return byte;
}

2. DS18B20模块

首先我们把需要的命令和依赖的模块(OneWire模块)添加进来:

#include "OneWire.h"

#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE

① 温度转换

image-20210909163413495
void DS18B20_ConvertT() {
    OneWire_Init();
    OneWire_SendByte(DS18B20_SKIP_ROM);
    OneWire_SendByte(DS18B20_CONVERT_T);
}

② 温度读取

image-20210909163445714
float DS18B20_ReadT() {
    unsigned char TLSB, THSB;
    int Temp;
    float T;
    OneWire_Init();
    OneWire_SendByte(DS18B20_SKIP_ROM);
    OneWire_SendByte(DS18B20_READ_SCRATCHPAD);

    TLSB = OneWire_ReceiveByte();  // 接收低八位
    THSB = OneWire_ReceiveByte();  // 接收高八位
    Temp = (THSB << 8) | TLSB;
    T = Temp / 16.0;  // 转换成float类型
    return T;
}

3. main.c部分

void main() {
    float T, TShow;
    LCD_Init();
    DS18B20_ConvertT();
    Delay(1000);

    while (1) {
        DS18B20_ConvertT();    // 温度转换
        T = DS18B20_ReadT();   // 读取温度
        // 显示符号位
        if (T < 0) {
            LCD_ShowString(2, 0, "-");
            TShow = -T;
        } else {
            LCD_ShowString(2, 0, "+");
            TShow = T;
        }
        LCD_ShowNum(2, 2, TShow, 3);  // 整数部分
        LCD_ShowString(2, 5, ".");    // 小数点
        LCD_ShowNum(2, 6, (unsigned long) (TShow * 10) % 10, 1); // 小数部分,一位小数
    }
}

这样我们就可以实时地展示温度了。

tips:在开头进行一次温度转换并Delay(1000);的原因是:温度转换是需要一定的时间的,如果我们不进行延时而直接取出温度值就会得到初始值25.0。

标签:Wire,OneWire,DS18B20,总线,通信协议,unsigned,单总线,温度传感器,DQ
来源: https://www.cnblogs.com/CodeReaper/p/15250831.html