DS18B20 温度传感器笔记(STC15F2K60S1版)
一、DS18B20 基本特性
- 多路采集能力:使得分布式温度采集应用更加简单
- 无需外围元件:内部集成所有必要电路
- 数据线供电:供电范围为 3.0V 至 5.5V
- 测量范围:-55℃ 至 +125℃(-67℉ 至 +257℉)
- 精度:-10℃ 至 85℃ 范围内具有 ±0.5℃ 的精度
- 可编程分辨率:内部温度采集精度可由用户自定义为 9-Bits 至 12-Bits
图片路径
二、内部寄存器结构
暂存器(Scratchpad)映射
┌──────────┬────────────┬──────────┬──────────────────────────┐
│ 字节 │ 名称 │ 默认值 │ 说明 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 0 │ 温度LSB │ 0x50 │ 温度低字节 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 1 │ 温度MSB │ 0x05 │ 温度高字节 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 2 │ TH寄存器 │ 用户定义 │ 最大温度——温度报警寄存器 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 3 │ TL寄存器 │ 用户定义 │ 最小温度——温度报警寄存器 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 4 │ 配置寄存器 │ 0x7F │ 配置精度 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 5-7 │ 保留 │ - │ 内部使用 │
├──────────┼────────────┼──────────┼──────────────────────────┤
│ Byte 8 │ CRC │ - │ 校验码 │
└──────────┴────────────┴──────────┴──────────────────────────┘
三、温度数据格式
温度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
四、温度报警寄存器
图片路径
TH/TL寄存器说明:
- bit 7:符号位
- bit 0-6:温度值
重要限制:
- 只能比较整数部分,不能比较小数
- 例如:只能比较 +26℃,但不能比较 +26.5℃
(实际应用中不常用)
五、配置寄存器
图片路径
寄存器格式:
- 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(默认)
六、通信协议流程
图片路径
三步通信流程
- 初始化 DS18B20
↓ - 执行 ROM 指令
↓ - 执行 DS18B20 功能指令
单个设备简化方案:
- 如果仅使用单个DS18B20,可以直接跳过ROM指令
- 跳过ROM指令的字节是 0xCC
- (同一条单总线上,只接了一个 DS18B20 温度传感器)
七、时序详解
- 初始化时序
主机操作:
- 如果我给一个信号,它能给我一个信号说明初始化成功
图片路径
时序要求:
- 主机拉低总线 ≥ 480μs
- 释放总线,等待DS18B20应答
- DS18B20拉低总线 60-240μs 表示应答成功
- 写时序
图片路径
写0时序:
- 拉低总线 60-120μs
写1时序:
- 拉低总线 1-15μs,然后释放
STC15F2K60S1 注意事项:
- STC15系列是 1T单片机(传统51是12T)
- 延时函数需要重新计算
- 每个机器周期 = 1/系统时钟频率
- 读时序
图片路径
读取流程:
- 拉低总线 1-15μs
- 释放总线
- 在15μs内读取数据位
- 等待至少45μs
数据读取:
- 每次读取1位数字
- 读取速度:根据晶振频率调整(STC15F2K60S1 通常使用 11.0592MHz 或 12MHz)
八、ROM 指令集
图片路径
常用ROM指令:
- 0xCC:跳过ROM(单个设备时使用,最常用)
- 0x33:读ROM
- 0x55:匹配ROM
- 0xF0:搜索ROM
- 0xEC:报警搜索
蓝桥杯提示:
- 我们只需要了解**跳过ROM指令(0xCC)**即可
九、功能指令集
图片路径
常用功能指令:
- 0x44:温度转换(启动温度采集)
- 0xBE:读暂存器(读取温度数据)
- 0x4E:写暂存器
- 0x48:复制暂存器到EEPROM
- 0xB8:重调EEPROM
重点掌握:
- 需要了解温度转换(0x44)与读取暂存器(0xBE)
十、STC15F2K60S1 代码实现
硬件配置
#include <STC15F2K60S2.h> // STC15F2K60S1头文件
#include <intrins.h>
// 引脚定义
sbit DQ = P1^4; // DS18B20数据线
// 系统时钟配置(根据实际晶振修改)
#define FOSC 11059200L // 11.0592MHz
// #define FOSC 12000000L // 12MHz
延时函数(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();
}
}
}
延时说明:
- 以上延时基于 11.0592MHz 晶振
- 如果使用其他频率,需要重新计算
- 建议使用示波器验证时序准确性
核心函数框架
下面的代码需要我们自己写:
- 初始化函数
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;
}
- 写字节函数
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; // 右移准备下一位
}
}
- 读字节函数
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;
}
- 读取温度函数
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℃)
}
主函数示例
void main(void) {
int temp;
// 初始化LCD/数码管等显示设备
// ...
while (1) {
// 读取温度
temp = DS18B20_ReadTemp();
// 显示温度(temp/10 为整数部分,temp%10 为小数部分)
// 例如:temp=256 显示为 25.6℃
// 延时1秒
Delay_ms(1000);
}
}
十一、STC15F2K60S1 特别注意事项
与传统51的区别
┌──────────┬─────────────────────┬───────────────────┐
│ 项目 │ 传统51(AT89C51) │ STC15F2K60S1 │
├──────────┼─────────────────────┼───────────────────┤
│ 指令周期 │ 12T(12个时钟周期) │ 1T(1个时钟周期) │
├──────────┼─────────────────────┼───────────────────┤
│ 执行速度 │ 慢 │ 快12倍 │
├──────────┼─────────────────────┼───────────────────┤
│ 延时函数 │ 简单循环即可 │ 需要重新计算 │
├──────────┼─────────────────────┼───────────────────┤
│ 头文件 │ reg51.h │ STC15F2K60S2.h │
└──────────┴─────────────────────┴───────────────────┘
调试技巧
- 时序验证:使用示波器检查时序是否准确
- 延时校准:根据实际晶振频率调整延时函数
- 初始化检测:先测试初始化是否成功
- 分步调试:逐个函数测试,确保每步正确
常见问题
问题1:初始化失败
- 检查硬件连接(数据线、上拉电阻4.7kΩ)
- 检查延时函数是否准确
- 检查晶振频率配置
问题2:读取温度为0或异常
- 确保转换时间足够(750ms)
- 检查读写时序
- 验证指令顺序
问题3:温度不稳定
- 增加滤波算法(多次采样平均)
- 检查电源稳定性
- 避免电磁干扰
十二、蓝桥杯竞赛要点
考点总结
- 基础操作(必考)
- 初始化时序
- 温度读取
- 数码管显示
- 时序控制(重点)
- STC15F2K60S1的1T特性
- 延时函数的准确性
- 时序图的理解
- 数据处理
- 温度数据格式转换
- 整数和小数分离显示
- 负温度处理
竞赛技巧
- 提前准备好延时函数:根据竞赛板晶振频率调试好
- 封装成函数库:便于快速调用
- 添加初始化检测:避免硬件故障浪费时间
- 测试负温度显示:准备好负号显示逻辑
- 优化读取频率:建议1秒读取一次,避免频繁操作
附录:快速参考
常用指令速查
// 跳过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