第六周 DS18B20板块


DS18B20 温度传感器笔记(STC15F2K60S1版)


:pushpin: 一、DS18B20 基本特性

  • 多路采集能力:使得分布式温度采集应用更加简单
  • 无需外围元件:内部集成所有必要电路
  • 数据线供电:供电范围为 3.0V 至 5.5V
  • 测量范围:-55℃ 至 +125℃(-67℉ 至 +257℉)
  • 精度:-10℃ 至 85℃ 范围内具有 ±0.5℃ 的精度
  • 可编程分辨率:内部温度采集精度可由用户自定义为 9-Bits 至 12-Bits

图片路径


:pushpin: 二、内部寄存器结构

暂存器(Scratchpad)映射

┌──────────┬────────────┬──────────┬──────────────────────────┐
│ 字节 │ 名称 │ 默认值 │ 说明 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 0 │ 温度LSB │ 0x50 │ 温度低字节 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 1 │ 温度MSB │ 0x05 │ 温度高字节 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 2 │ TH寄存器 │ 用户定义 │ 最大温度——温度报警寄存器 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 3 │ TL寄存器 │ 用户定义 │ 最小温度——温度报警寄存器 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 4 │ 配置寄存器 │ 0x7F │ 配置精度 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 5-7 │ 保留 │ - │ 内部使用 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 8 │ CRC │ - │ 校验码 │
└──────────┴────────────┴──────────┴──────────────────────────┘

:pushpin: 三、温度数据格式

温度LSB 与 温度MSB 的存储方式

图片路径

位分配:

  • LS(低位)/ MS(高位)
  • bit 0 ~ bit 3:小数位(4位)
  • bit 4 ~ bit 10:整数位(7位)
  • bit 11 ~ bit 15:符号位(5位)

符号位规则:

  • 前面5个0代表正温度
  • 前面5个1代表负温度

数据组成:

  • 后面的4位数字是小数部分
  • 中间7个位是整数部分

温度计算公式

实际温度 = (温度MSB × 256 + 温度LSB) × 0.0625


:pushpin: 四、温度报警寄存器

图片路径

TH/TL寄存器说明:

  • bit 7:符号位
  • bit 0-6:温度值

:warning: 重要限制:

  • 只能比较整数部分,不能比较小数
  • 例如:只能比较 +26℃,但不能比较 +26.5℃

(实际应用中不常用)


:pushpin: 五、配置寄存器

图片路径

寄存器格式:

  • bit 7 与 bit 0 ~ bit 4 的数据是固定的
  • 只能操作 R1 与 R0 两位

精度配置表
┌─────┬─────┬────────┬─────────┬──────────┐
│ R1 │ R0 │ 分辨率 │ 精度 │ 转换时间 │
├─────┼─────┼────────┼─────────┼──────────┤
│ 0 │ 1 │ 10位 │ 0.5℃ │ 187.5ms │
├─────┼─────┼────────┼─────────┼──────────┤
│ 1 │ 0 │ 11位 │ 0.25℃ │ 375ms │
├─────┼─────┼────────┼─────────┼──────────┤
│ 1 │ 1 │ 12位 │ 0.125℃ │ 750ms │
├─────┼─────┼────────┼─────────┼──────────┤
│ 0 │ 0 │ 9位 │ 0.0625℃ │ 93.75ms │
└─────┴─────┴────────┴─────────┴──────────┘
配置值:

  • 9位:0x1F
  • 10位:0x3F
  • 11位:0x5F
  • 12位:0x7F(默认)

:pushpin: 六、通信协议流程

图片路径

三步通信流程

  1. 初始化 DS18B20
  2. 执行 ROM 指令
  3. 执行 DS18B20 功能指令

:light_bulb: 单个设备简化方案:

  • 如果仅使用单个DS18B20,可以直接跳过ROM指令
  • 跳过ROM指令的字节是 0xCC
  • (同一条单总线上,只接了一个 DS18B20 温度传感器)

:pushpin: 七、时序详解

  1. 初始化时序

主机操作:

  • 如果我给一个信号,它能给我一个信号说明初始化成功

图片路径

时序要求:

  • 主机拉低总线 ≥ 480μs
  • 释放总线,等待DS18B20应答
  • DS18B20拉低总线 60-240μs 表示应答成功

  1. 写时序

图片路径

写0时序:

  • 拉低总线 60-120μs

写1时序:

  • 拉低总线 1-15μs,然后释放

:warning: STC15F2K60S1 注意事项:

  • STC15系列是 1T单片机(传统51是12T)
  • 延时函数需要重新计算
  • 每个机器周期 = 1/系统时钟频率

  1. 读时序

图片路径

读取流程:

  • 拉低总线 1-15μs
  • 释放总线
  • 在15μs内读取数据位
  • 等待至少45μs

数据读取:

  • 每次读取1位数字
  • 读取速度:根据晶振频率调整(STC15F2K60S1 通常使用 11.0592MHz 或 12MHz)

:pushpin: 八、ROM 指令集

图片路径

常用ROM指令:

  • 0xCC:跳过ROM(单个设备时使用,最常用)
  • 0x33:读ROM
  • 0x55:匹配ROM
  • 0xF0:搜索ROM
  • 0xEC:报警搜索

:light_bulb: 蓝桥杯提示:

  • 我们只需要了解**跳过ROM指令(0xCC)**即可

:pushpin: 九、功能指令集

图片路径

常用功能指令:

  • 0x44:温度转换(启动温度采集)
  • 0xBE:读暂存器(读取温度数据)
  • 0x4E:写暂存器
  • 0x48:复制暂存器到EEPROM
  • 0xB8:重调EEPROM

:light_bulb: 重点掌握:

  • 需要了解温度转换(0x44)与读取暂存器(0xBE)

:pushpin: 十、STC15F2K60S1 代码实现

:gear: 硬件配置

#include <STC15F2K60S2.h> // STC15F2K60S1头文件
#include <intrins.h>

// 引脚定义
sbit DQ = P1^4; // DS18B20数据线

// 系统时钟配置(根据实际晶振修改)
#define FOSC 11059200L // 11.0592MHz
// #define FOSC 12000000L // 12MHz


:wrench: 延时函数(1T单片机专用)

// 微秒级延时(STC15F2K60S1 @ 11.0592MHz)
void Delay_us(unsigned int t) {
// STC15是1T单片机,需要重新计算延时
// 11.0592MHz: 1us ≈ 11个时钟周期
while (t–) {
nop();
nop();
nop();
nop();
nop();
nop();
nop();
nop();
}
}

// 毫秒级延时
void Delay_ms(unsigned int t) {
unsigned int i, j;
for (i = 0; i < t; i++) {
for (j = 0; j < 120; j++) {
nop();
}
}
}

:warning: 延时说明:

  • 以上延时基于 11.0592MHz 晶振
  • 如果使用其他频率,需要重新计算
  • 建议使用示波器验证时序准确性

:memo: 核心函数框架

下面的代码需要我们自己写:

  1. 初始化函数

bit DS18B20_Init(void) {
bit ack;

  DQ = 1;  // 先拉高
  Delay_us(1);

  DQ = 0;  // 拉低480μs以上
  Delay_us(500);

  DQ = 1;  // 释放总线
  Delay_us(60);

  ack = DQ;  // 读取应答(0=成功,1=失败)
  Delay_us(240);

  return ack;

}


  1. 写字节函数

void DS18B20_WriteByte(unsigned char dat) {
unsigned char i;

  for (i = 0; i < 8; i++) {
      DQ = 0;  // 拉低总线
      _nop_(); _nop_();

      DQ = dat & 0x01;  // 写入数据位
      Delay_us(60);

      DQ = 1;  // 释放总线
      _nop_();

      dat >>= 1;  // 右移准备下一位
  }

}


  1. 读字节函数

unsigned char DS18B20_ReadByte(void) {
unsigned char i, dat = 0;

  for (i = 0; i < 8; i++) {
      dat >>= 1;

      DQ = 0;  // 拉低总线
      _nop_(); _nop_();

      DQ = 1;  // 释放总线
      _nop_(); _nop_();

      if (DQ) {  // 读取数据位
          dat |= 0x80;
      }

      Delay_us(60);
  }

  return dat;

}


  1. 读取温度函数

int DS18B20_ReadTemp(void) {
unsigned char temp_L, temp_H;
int temp;

  // 1. 初始化
  DS18B20_Init();

  // 2. 跳过ROM
  DS18B20_WriteByte(0xCC);

  // 3. 启动温度转换
  DS18B20_WriteByte(0x44);

  // 4. 等待转换完成(750ms)
  Delay_ms(750);

  // 5. 重新初始化
  DS18B20_Init();

  // 6. 跳过ROM
  DS18B20_WriteByte(0xCC);

  // 7. 读取暂存器
  DS18B20_WriteByte(0xBE);

  // 8. 读取温度数据
  temp_L = DS18B20_ReadByte();  // 低字节
  temp_H = DS18B20_ReadByte();  // 高字节

  // 9. 合成16位温度数据
  temp = temp_H;
  temp = (temp << 8) | temp_L;

  // 10. 转换为实际温度(×10便于显示)
  temp = temp * 0.625;  // 0.0625 × 10 = 0.625

  return temp;  // 返回温度×10(例如:256 = 25.6℃)

}


:video_game: 主函数示例

void main(void) {
int temp;

  // 初始化LCD/数码管等显示设备
  // ...

  while (1) {
      // 读取温度
      temp = DS18B20_ReadTemp();

      // 显示温度(temp/10 为整数部分,temp%10 为小数部分)
      // 例如:temp=256 显示为 25.6℃

      // 延时1秒
      Delay_ms(1000);
  }

}


:pushpin: 十一、STC15F2K60S1 特别注意事项

:warning: 与传统51的区别
┌──────────┬─────────────────────┬───────────────────┐
│ 项目 │ 传统51(AT89C51) │ STC15F2K60S1 │
├──────────┼─────────────────────┼───────────────────┤
│ 指令周期 │ 12T(12个时钟周期) │ 1T(1个时钟周期) │
├──────────┼─────────────────────┼───────────────────┤
│ 执行速度 │ 慢 │ 快12倍 │
├──────────┼─────────────────────┼───────────────────┤
│ 延时函数 │ 简单循环即可 │ 需要重新计算 │
├──────────┼─────────────────────┼───────────────────┤
│ 头文件 │ reg51.h │ STC15F2K60S2.h │
└──────────┴─────────────────────┴───────────────────┘
:light_bulb: 调试技巧

  1. 时序验证:使用示波器检查时序是否准确
  2. 延时校准:根据实际晶振频率调整延时函数
  3. 初始化检测:先测试初始化是否成功
  4. 分步调试:逐个函数测试,确保每步正确

:magnifying_glass_tilted_left: 常见问题

问题1:初始化失败

  • 检查硬件连接(数据线、上拉电阻4.7kΩ)
  • 检查延时函数是否准确
  • 检查晶振频率配置

问题2:读取温度为0或异常

  • 确保转换时间足够(750ms)
  • 检查读写时序
  • 验证指令顺序

问题3:温度不稳定

  • 增加滤波算法(多次采样平均)
  • 检查电源稳定性
  • 避免电磁干扰

:pushpin: 十二、蓝桥杯竞赛要点

:trophy: 考点总结

  1. 基础操作(必考)
    • 初始化时序
    • 温度读取
    • 数码管显示
  2. 时序控制(重点)
    • STC15F2K60S1的1T特性
    • 延时函数的准确性
    • 时序图的理解
  3. 数据处理
    • 温度数据格式转换
    • 整数和小数分离显示
    • 负温度处理

:light_bulb: 竞赛技巧

  1. 提前准备好延时函数:根据竞赛板晶振频率调试好
  2. 封装成函数库:便于快速调用
  3. 添加初始化检测:避免硬件故障浪费时间
  4. 测试负温度显示:准备好负号显示逻辑
  5. 优化读取频率:建议1秒读取一次,避免频繁操作

:pushpin: 附录:快速参考

常用指令速查

// 跳过ROM + 温度转换
DS18B20_Init();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 温度转换
Delay_ms(750); // 等待转换

// 跳过ROM + 读取温度
DS18B20_Init();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0xBE); // 读暂存器
temp_L = DS18B20_ReadByte();
temp_H = DS18B20_ReadByte();

温度显示格式

// 温度值 temp(已×10)
int integer = temp / 10; // 整数部分
int decimal = temp % 10; // 小数部分

// 显示格式:25.6℃
// integer = 25, decimal = 6