视界信息网
Article

蓝桥杯单片机“野路子”:DS18B20温度读取的血泪史(任务ID#12335)

发布时间:2026-01-22 09:30:34 阅读量:6

.article-container { font-family: "Microsoft YaHei", sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto; }
.article-container h1

蓝桥杯单片机“野路子”:DS18B20温度读取的血泪史(任务ID#12335)

摘要:又是一年蓝桥杯,我的IAP15F2K61S2又要裸奔了…第十届蓝桥杯单片机省赛DS18B20温度读取,看似简单,实则坑深。分享任务编号#12335选手的“野路子”解决方案,拒绝学院派教条,一切以“够用就好”为原则,带你避开那些让人崩溃的坑,目标:活着拿到省三!

蓝桥杯单片机“野路子”:DS18B20温度读取的血泪史(任务ID#12335)

又是一年2026蓝桥杯,我的IAP15F2K61S2又要裸奔了… 没办法,谁让咱是野生选手呢,学院派的那些花里胡哨的理论,咱玩不转,只能靠着实践出真知,硬着头皮往里冲。

问题描述:DS18B20温度读取,看似简单,实则坑深

第十届蓝桥杯单片机省赛,DS18B20温度读取,这玩意儿看似简单,不就是个单总线通信嘛,网上一搜一大堆代码。但是!蓝桥杯的坑,只有踩过才知道有多深!

最常见的坑,就是时序问题。DS18B20对时序要求非常严格,稍微有点偏差,就读不出数据,或者读出来的数据是乱码。尤其是在蓝桥杯的赛场上,时间就是生命,要是死磕时序,那估计省三都没戏。

还有就是,DS18B20的初始化,必须严格按照datasheet的要求来,任何一点疏忽,都可能导致初始化失败。而且,初始化失败了,还不会报错,只会让你读出来的数据一直是85度,让你怀疑人生。

当年,任务编号#12335选手我,就死在了这个DS18B20上,硬是调试了一下午,才发现是时序的问题。当时的心情,简直比吃了苍蝇还难受。

“野路子”解决方案:不求最佳,但求够用

痛定思痛,我决定放弃学院派的那些“最佳实践”,走一条“野路子”,一切以“够用就好”为原则。

我的解决方案是:延时函数大法好!

我知道,学院派肯定会鄙视我,说我这是“阻塞式编程”,效率低下。但是,在蓝桥杯的赛场上,效率算个屁!能把温度读出来,才是王道!

我的思路是,直接用延时函数来模拟DS18B20的时序,简单粗暴,但是有效!

// DS18B20 初始化
unsigned char DS18B20_Init(void)
{
    unsigned char reval=0;

    DQ = 1;
    delay_us(5); // 略微提前拉低
    DQ = 0;
    delay_us(500); // 延时 480~960us
    DQ = 1;
    delay_us(60);   // 延时 15~60us
    reval = DQ;
    delay_us(500); // 延时 480~960us

    DQ = 1;

    return reval; // 返回值: 0=成功, 1=失败
}

// 读取一个字节
unsigned char DS18B20_ReadByte(void)
{
    unsigned char i, dat = 0;

    for (i = 0; i < 8; i++)
    {
        DQ = 0;
        delay_us(2);
        DQ = 1;
        delay_us(12); // 延时大于15us
        dat = (dat >> 1) | (DQ << 7);
        delay_us(50); // 延时大于45us
    }
    return dat;
}

// 写入一个字节
void DS18B20_WriteByte(unsigned char dat)
{
    unsigned char i;

    for (i = 0; i < 8; i++)
    {
        DQ = 0;
        delay_us(2);
        DQ = dat & 0x01;
        delay_us(60); // 延时大于60us
        DQ = 1;
        dat >>= 1;
    }
}

// 读取温度
int DS18B20_ReadT(void)
{
    unsigned char TL, TH;
    int temp;

    DS18B20_Init();
    DS18B20_WriteByte(0xCC); // skip ROM
    DS18B20_WriteByte(0x44); // convert temperature
    delay_ms(750); // 转换时间

    DS18B20_Init();
    DS18B20_WriteByte(0xCC); // skip ROM
    DS18B20_WriteByte(0xBE); // read scratchpad

    TL = DS18B20_ReadByte();
    TH = DS18B20_ReadByte();

    temp = TH;
    temp <<= 8;
    temp |= TL;

    return temp;
}


这段代码的核心思想就是,用精确的延时函数来保证时序的正确性。当然,这种方法的缺点也很明显,就是会占用大量的CPU时间,导致程序的效率降低。但是,在蓝桥杯的赛场上,只要能把温度读出来,效率什么的,都是浮云。

另外,我还发现一个坑,就是DS18B20的转换时间。datasheet上说,转换时间是750ms。但是,我在实际测试中发现,如果延时时间不够,读出来的数据还是会出错。所以,我干脆把延时时间增加到1秒,这样就万无一失了。

经验教训:实践是检验真理的唯一标准

通过这次踩坑经历,我深刻体会到,实践是检验真理的唯一标准。不要迷信datasheet,也不要迷信网上的代码,只有自己动手调试,才能找到真正的解决方案。

我还总结了一些经验教训:

  • 时序是关键: DS18B20对时序要求非常严格,必须严格按照datasheet的要求来。实在不行,就用延时函数大法,简单粗暴,但是有效。
  • 初始化很重要: DS18B20的初始化,必须严格按照datasheet的要求来,任何一点疏忽,都可能导致初始化失败。
  • 转换时间要足够: DS18B20的转换时间,要足够长,否则读出来的数据可能会出错。datasheet上说750ms,我建议延时1秒,万无一失。
  • 多用示波器: 如果有示波器,可以用示波器来观察DS18B20的时序,这样可以更准确地调试代码。当然,像任务编号#12335这种穷逼选手,只能靠猜了。
  • 3σ原则的应用: 在比赛过程中, 偶尔会出现读取到的温度值突变的情况. 这可能是由于干扰或者DS18B20本身的问题导致的. 借鉴统计学中的3σ原则, 我们可以对读取到的温度值进行简单的滤波处理. 例如, 连续读取5次温度值, 计算其平均值和标准差. 如果某个温度值与平均值的偏差超过3倍标准差, 则认为该值为异常值, 舍弃不用. 这样可以有效提高系统的鲁棒性。
步骤 操作 注意事项
1 初始化DS18B20 检查引脚连接是否正确,延时时间是否足够
2 发送跳过ROM命令 0xCC,确保所有设备都能响应
3 发送温度转换命令 0x44,启动温度转换
4 延时等待转换完成 至少750ms,建议1秒
5 再次初始化DS18B20 确保读取数据前设备状态正常
6 发送跳过ROM命令 0xCC
7 发送读取暂存器命令 0xBE,准备读取温度数据
8 读取温度数据 读取两个字节,分别代表温度的低位和高位

结尾:蓝桥杯的意义在于让你明白自己有多菜…

希望我的这些经验能帮到你,祝你早日脱坑,拿到省三!记住,蓝桥杯单片机省赛的意义不在于拿奖,而在于让你明白自己有多菜… 另外,吐槽一下,这国信长天单片机竞赛实训平台,是真的难用!

参考来源: