RT-Thread: 温度传感器DS18B20软件包添加及应用

5 篇文章 0 订阅
3 篇文章 0 订阅

关键词:温度传感器,DS18B20

调试环境:系统使用了 RT-Thread V4.0.2 ,编译器:RT-Thread Studio

说明:本笔记原始记录是在2020年完成, RT-Thread Studio 已经更新过多版,界面上可能对不上。

文档介绍:文档介绍使用 RT-Thread Studio 创建的 RT-Thread V4.0.2 RTOS 工程,并在工程中添加 DS18B20 的驱动软件包,使用软件包读取 DS18B20 的温度。

目录

1.利用系统配置功能,添加 DS18B20 的软件包

2.DS18B20源码修改

3.调试DS18B20源码

4.调试总结

5.问题分析


1.利用系统配置功能,添加 DS18B20 的软件包

 添加软件包

 添加后选择保存,编译,看是否有错误

 回到编译器,点击编译,增加的源码文件夹会自动出现在项目的目录里面

2.DS18B20源码修改

ds18b20_sample.c ,文件修改 IC 对应的IO;

找到如下代码,修改即可

/* Modify this pin according to the actual wiring situation */
#define DS18B20_DATA_PIN    GET_PIN(A, 12)

修改后编译,可能会出现头文件包含的问题。

由于我在项目中有个总的头文件,如下,所以新建了个头文件 ds18b20_sample.h ,里面只有个线程的声明。

#include "user_cfg.h"
//#include <stdlib.h>
//#include <rtthread.h>
//#include "sensor.h"
//#include "sensor_dallas_ds18b20.h"

/* Modify this pin according to the actual wiring situation */
#define DS18B20_DATA_PIN    GET_PIN(A, 12)

如果出现找不到头文件的情况,按如下流程设置,右键点击项目,选择属性

3.调试DS18B20源码

DS18B20 源码修改 , ds18b20_sample.c

修改源码后,通过串口看收到的温度数据始终是 0 ;

通过逻辑分析仪器抓了 IC 的数据管脚的数据,发现IC有发出正确的温度数据,但是单片机没能准确读取到数据。

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author         Notes
 * 2019-07-24     WillianChan    the first version
 */

#include "user_cfg.h"
//#include <stdlib.h>
//#include <rtthread.h>
//#include "sensor.h"
//#include "sensor_dallas_ds18b20.h"

/* Modify this pin according to the actual wiring situation */
#define DS18B20_DATA_PIN    GET_PIN(A, 12)  /* YLTEST IC于MCU连接的IO 配置  */

static void read_temp_entry(void *parameter)
{
    rt_device_t dev = RT_NULL;
    struct rt_sensor_data sensor_data;
    rt_size_t res;

    dev = rt_device_find(parameter);
    if (dev == RT_NULL)
    {
        rt_kprintf("Can't find device:%s\n", parameter);
        return;
    }

    if (rt_device_open(dev, RT_DEVICE_FLAG_RDWR) != RT_EOK)
    {
        rt_kprintf("open device failed!\n");
        return;
    }
    rt_device_control(dev, RT_SENSOR_CTRL_SET_ODR, (void *)100);

    while (1)
    {
        res = rt_device_read(dev, 0, &sensor_data, 1);
        if (res != 1)
        {
            rt_kprintf("read data failed!size is %d\n", res);
            rt_device_close(dev);
            return;
        }
        else
        {
            if (sensor_data.data.temp >= 0)
            {
                rt_kprintf("temp:%3d.%dC, timestamp:%5d\n",
                           sensor_data.data.temp / 10,
                           sensor_data.data.temp % 10,
                           sensor_data.timestamp);
            }
            else
            {
                rt_kprintf("temp:-%2d.%dC, timestamp:%5d\n",
                           abs(sensor_data.data.temp / 10),
                           abs(sensor_data.data.temp % 10),
                           sensor_data.timestamp);
            }
        }
        rt_thread_mdelay(2000); /* YLTEST 调整了传感器的读取间隔为 2秒 */
    }
}

int ds18b20_read_temp_sample(void)
{
    rt_thread_t ds18b20_thread;

    ds18b20_thread = rt_thread_create("18b20tem",
                                      read_temp_entry,
                                      "temp_ds18b20",
                                      1024,
                                      10,   /* YLTEST 调整了线程的优先级*/
                                      50);  /* YLTEST 调整了时间片大小 */
    if (ds18b20_thread != RT_NULL)
    {
        rt_thread_startup(ds18b20_thread);
    }

    return RT_EOK;
}
//INIT_APP_EXPORT(ds18b20_read_temp_sample); /* YLTEST线程自动初始化代码注销,改成了在main函数添加线程运行代码。*/

static int rt_hw_ds18b20_port(void)
{
    struct rt_sensor_config cfg;
    
    cfg.intf.user_data = (void *)DS18B20_DATA_PIN;
    rt_hw_ds18b20_init("ds18b20", &cfg);
    
    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_ds18b20_port);

代码跟踪调试

调试发现读取温度的函数进入了这个文件 sensor_dallas_ds18b20.c

如下代码是读取温度传感器发出温度数据的函数,调试发现 存储温度的变量 TL,TH 读出的数据始终是 255;

int32_t ds18b20_get_temperature(rt_base_t pin)
{
    uint8_t TL, TH;
    int32_t tem;
    
    ds18b20_start(pin);
    ds18b20_init(pin);
    ds18b20_write_byte(pin, 0xcc);
    ds18b20_write_byte(pin, 0xbe);
    TL = ds18b20_read_byte(pin);    /* LSB first */
    TH = ds18b20_read_byte(pin);
    if (TH > 7)
    {
        TH =~ TH;
        TL =~ TL;
        tem = TH;
        tem <<= 8;
        tem += TL;
        tem = (int32_t)(tem * 0.0625 * 10 + 0.5);
        return -tem;
    }
    else
    {
        tem = TH;
        tem <<= 8;
        tem += TL;
        tem = (int32_t)(tem * 0.0625 * 10 + 0.5);
        return tem;
    }
}

 进一步跟进如下函数

TL = ds18b20_read_byte(pin);    /* LSB first */

这个函数是 读取 温度传感器发出的温度数据,读 1 个字节的函数。

调试发现,读字节函数中变量 dat 数据也每次都是 255 ,所以问题还在函数内部调用的函数

j = ds18b20_read_bit(pin); 出了问题

static uint8_t ds18b20_read_byte(rt_base_t pin)
{
    uint8_t i, j, dat;
    dat = 0;

    for (i = 1; i <= 8; i++)
    {
        j = ds18b20_read_bit(pin);
        dat = (j << 7) | (dat >> 1);
    }

    return dat;
}

如下标记 //YLTEST 的代码是我修改了时间的部分,按这些数据修改后,函数就能够准确读到温度传感器的温度数据。

static uint8_t ds18b20_read_bit(rt_base_t pin)
{
    uint8_t data;

    rt_pin_mode(pin, PIN_MODE_OUTPUT);
    rt_pin_write(pin, PIN_LOW);
    rt_hw_us_delay(1);//YLTEST
    rt_pin_write(pin, PIN_HIGH);
    rt_pin_mode(pin, PIN_MODE_INPUT);
    /* maybe 12us, maybe 5us, whatever...I have no idea */
    rt_hw_us_delay(2);//YLTEST

    if(rt_pin_read(pin))
        data = 1;
    else
        data = 0;

    rt_hw_us_delay(30);//YLTEST

    return data;
}

4.调试总结

1:解决问题主要还是 逻辑分析仪 帮了大忙,逻辑分析仪抓到了数据,并按 1 WIRE 准确解析了协议,再根据 IC 的协议文档,看明白了协议格式和数据的含义,通过手工算了 温度数据,发现温度是准确的。这也缩小了问题点的范围,让我能够准确的知道问题就是读取温度数据这部分出的问题。如下图箭头指的部分。

 2:IC 规格书中读数据的时序介绍

3:网络上查资料,关于 1-wire 协议的讲解

解析单总线协议(1-wire)_zhengqijun_的博客-CSDN博客

4:逻辑分析仪抓包的时间分析

通过下图发现,源码的时序设置已经超过了 IC 的时序要求,所以导致MCU没能按准确的时序读到数据。按前面代码中的方式修改时序后,MCU读取数据正常。

5.问题分析

1:软件包出现这样的时序问题,有可能是我的开发板使用的是内部晶振,导致实际延时偏慢。

2:目前没有验证是不是和晶振时钟配置相关。后续有空,再调整一下单片机时钟看看。

3:经过测试发现,上次测试的代码是用的系统内部默认时钟,改成外部8M晶振,72M主频后,再用原来的时间设置,读取数据正常。 2020/06/13 21:56

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值