DS18B20 温度读取模块笔记
一、 底层驱动核心 (OneWire.c)
底层驱动的核心在于时序控制和读写逻辑。为了方便记忆,我们将其拆解为“三个基础动作”和“一个组合大招”。
1. 硬件引脚定义
蓝桥杯 CT107D 板子上,DS18B20 连接在 P1.4。
C
sbit DQ = P1^4; // 必须背下来的引脚定义
2. 核心延时函数 (关键)
单总线通信对时间非常敏感,STC15F2K60S2 速度快,延时需要特别注意。
C
// 单总线专用延时,不同于主函数的Delay
void Delay_OneWire(unsigned int t)
{
// STC15系列速度快,如果官方驱动给的是t*=12,
// 在比赛提供的驱动中通常不需要改,直接用提供的即可。
// 如果是自己写,注意不要让它跑太快。
while(t--);
}
3. 三个基础动作 (初始化、写、读)
这部分通常在比赛提供的资源包里有,只需理解,重点是记忆 init 的返回值判断。
-
初始化 (
init_ds18b20): 复位 → 检测存在脉冲。 -
写字节 (
Write_DS18B20): 低位先行 (LSB)。 -
读字节 (
Read_DS18B20): 低位先行 (LSB)。
4. 组合大招:读取温度函数 (read_t) 


这是你需要重点记忆和手写的部分,它把底层的复杂操作封装成一个简单函数供主函数调用。
逻辑口诀: 复位跳过转换,复位跳过读取。
C
float read_t()
{
unsigned char low, high; // 存放温度的低8位和高8位
// --- 第一步:启动温度转换 ---
init_ds18b20(); // 1. 复位
Write_DS18B20(0xcc); // 2. 跳过ROM (因为总线上只有一个设备)
Write_DS18B20(0x44); // 3. 发送温度转换命令
// --- 第二步:读取温度数据 ---
init_ds18b20(); // 4. 再次复位
Write_DS18B20(0xcc); // 5. 跳过ROM
Write_DS18B20(0xbe); // 6. 发送读取暂存器命令
low = Read_DS18B20(); // 7. 先读低字节
high = Read_DS18B20(); // 8. 后读高字节
// --- 第三步:合成数据并转化 ---
// high << 8 | low : 合成16位整数
// / 16.0 : DS18B20的分辨率是0.0625,除以16等于乘以0.0625
return ((high << 8) | low) / 16.0;
}
二、 主函数调用逻辑 (Main.c)
主函数的关键在于消除上电初期的 85°C 异常显示以及数据的提取显示。
1. 上电初始化 (消除 85°C) 
DS18B20 上电默认寄存器值为 85°C。为了避免开机瞬间显示 85,需要在进入 while(1) 之前先读一次并延时。
C
void main()
{
read_t(); // 先读一次,触发转换(这次的值虽然不准或者是85,但我们不显示)
Delay750ms(); // 等待转换完成(DS18B20最高精度转换需要750ms以上)
System_Init(); // 硬件初始化(关蜂鸣器等)
Timer0Init(); // 定时器初始化
while (1)
{
Key_Proc();
Seg_Proc();
Led_Proc();
}
}
2. 周期性读取与显示处理 (Seg_Proc)
为了不影响数码管扫描和按键,温度读取放在减速后的逻辑中。
C
void Seg_Proc()
{
// 减速处理:每500ms读取一次温度,太快了数码管会闪烁,且传感器反应不过来
if(Seg_Slow_Down) return;
Seg_Slow_Down = 1;
// 1. 获取温度
t = read_t();
// 2. 数据分离 (显示 XX.X)
// 假设温度是 25.6 度
// 十位:25.6 / 10 = 2.56 -> 取整2 -> %10 -> 2
Seg_Buf[0] = (unsigned char)t / 10 % 10;
// 个位:25.6 % 10 -> 5 (注意:float取模行为不同编译器不同,通常强转int再取模更稳)
// 你的写法:(unsigned char)t % 10 是安全的
Seg_Buf[1] = (unsigned char)t % 10;
// 小数位:25.6 * 10 = 256 -> (int)256 % 10 -> 6
Seg_Buf[2] = (unsigned int)(t * 10) % 10;
// 3. 别忘了点亮小数点!
// 你的代码定义了 Seg_Point 数组,需要在 Timer0Server 里配合使用
// 假设你要在第2位数码管(下标1)点亮小数点:
// Seg_Point[1] = 1; // 需要在初始化或这里手动赋值
}
三、 避坑与记忆清单 (Cheatsheet)
-
引脚定义:
sbit DQ = P1^4;(蓝桥杯板载)。 -
公式记忆:
-
读取顺序:先低后高 (
lowthenhigh)。 -
计算公式:
((high << 8) | low) / 16.0。
-
-
流程记忆:
-
CC 44 (转换):Init → Skip(CC) → Convert(44)。
-
CC BE (读取):Init → Skip(CC) → Read(BE)。
-
-
上电避坑:
read_t()+Delay750ms()放在while(1)之前。 -
类型转换:在拆分显示小数时,一定要把
t * 10强制转换为整型(unsigned int)再取模,否则计算结果可能出错。