DS18B20 例程【STM32F103C8T6】

不介绍原理,自行百度或必应,可参考 DS18B20温度传感器原理详解

数据手册:DS18B20(嘉立创)   中文版:DS18B20(中文版)

文件结构参考正点原子即可

1 硬件连接

2 部分代码示例

2.1 宏定义与头文件

#ifndef __DS18B20_H
#define __DS18B20_H

#include "public.h"

#define DS18B20_GPIO        GPIOB
#define DS18B20_PIN_TX      GPIO_Pin_10
#define DS18B20_PIN_RX      GPIO_Pin_11

typedef enum
{
    DS18B20_RES_9BITS   = 0x1F,    // 温度转换分辨率 9 bits
    DS18B20_RES_10BITS  = 0x3F,
    DS18B20_RES_11BITS  = 0x5F,
    DS18B20_RES_12BITS  = 0x7F,
} DS18B20_RES_E_TYPE;

typedef struct
{
    u8 temp_lsb;
    u8 temp_msb;
    u8 th_reg_ub1;
    u8 tl_reg_ub2;
    u8 config_reg;
    u8 reserved;
    u8 user_byte3;
    u8 user_byte4;
    u8 crc;
} DS18B20_SCRATCHPAD_S_TYPE;

typedef struct
{
    u8 negative_flag;
    float temperature;
    DS18B20_SCRATCHPAD_S_TYPE scratchpad;
} DS18B20_STATUE_S_TYPE;

void DS18B20_Init(void);
void DS18B20_GetTemperature(void);
void DS18B20_Test(void);

#endif
#include "ds18b20.h"
#include "lcd.h"

#define DS18B20_SET_BUS         GPIO_SetBits(DS18B20_GPIO, DS18B20_PIN_TX)
#define DS18B20_RESET_BUS       GPIO_ResetBits(DS18B20_GPIO, DS18B20_PIN_TX)
#define DS18B20_READ_BUS        GPIO_ReadInputDataBit(DS18B20_GPIO, DS18B20_PIN_RX)

DS18B20_STATUE_S_TYPE ds18b20 = { 0 };

2.2 时序

2.2.1 复位信号

void DS18B20_ResetSig(void)
{
    DS18B20_RESET_BUS;
    delay_ms(1);
    DS18B20_SET_BUS;
}

2.2.2 存在信号

u8 DS18B20_PresenceSig(void)
{
    u16 i = 0;
    u16 time = 0;
    // u16 delay = 0;

    delay_us(10);                                       // 调试后,按实际延时等待时间
    for (i = 0; i < 480; i++)
    {
        if (!DS18B20_READ_BUS)
        {
            time++;
            // if (!delay) { delay = i; }               // delay 变量用于确定等待时间
        }
        delay_us(1);
    }

    if ((time >= 30) && (time <= 240)) { return TRUE; } // 调试后,按实际确定 "存在信号" 持续时间

    return FALSE;
}

2.2.3 写位

void DS18B20_WriteBit(u8 bit)
{
    delay_us(2);            // 读/写 时序的间隔
    DS18B20_RESET_BUS;      // 下降沿, 开始 "写" 时序
    if (bit)                // 写 "1"
    {
        delay_us(5);        // 15 us 内拉高总线
        DS18B20_SET_BUS;    // 写 "1", 释放总线
        delay_us(60);       // 时序至少持续 60 us
    }
    else                    // 写 "0"
    {
        delay_us(60);       // 时序至少持续 60 us
        DS18B20_SET_BUS;    // 释放总线
    }
}

2.2.4 读位

u8 DS18B20_ReadBit(void)
{
    u8 bit = 0;

    delay_us(2);            // 读/写 时序的间隔
    DS18B20_RESET_BUS;      // 下降沿, 开始 "读" 时序
    delay_us(2);            // 至少保持 1 us
    DS18B20_SET_BUS;        // 释放总线
    delay_us(15);           // 从下降沿开始, 至少保持 15 us
    bit = DS18B20_READ_BUS; // 读取总线
    delay_us(50);           // 时序至少持续 60 us

    return bit;
}

3 代码汇总

3.1 ds18b20.c

#include "ds18b20.h"

#define DS18B20_SET_BUS         GPIO_SetBits(DS18B20_GPIO, DS18B20_PIN_TX)
#define DS18B20_RESET_BUS       GPIO_ResetBits(DS18B20_GPIO, DS18B20_PIN_TX)
#define DS18B20_READ_BUS        GPIO_ReadInputDataBit(DS18B20_GPIO, DS18B20_PIN_RX)

DS18B20_STATUE_S_TYPE ds18b20 = { 0 };

/**************************************************
* Desc:     DS18B20 复位信号
**************************************************/
static void DS18B20_ResetSig(void)
{
    DS18B20_RESET_BUS;
    delay_ms(1);
    DS18B20_SET_BUS;
}

/**************************************************
* Desc:     DS18B20 存在信号
* Return:   TRUE: 检测到 DS18B20, FALSE: 未检测到
**************************************************/
static u8 DS18B20_PresenceSig(void)
{
    u16 i = 0;
    u16 time = 0;
    // u16 delay = 0;

   delay_us(10);                                       // 调试后,按实际延时等待时间
    for (i = 0; i < 480; i++)
    {
        if (!DS18B20_READ_BUS)
        {
            time++;
            // if (!delay) { delay = i; }                  // delay 变量用于确定等待时间
        }
        delay_us(1);
    }

    if ((time >= 30) && (time <= 240)) { return TRUE; } // 调试后,按实际确定 "存在信号" 持续时间

    return FALSE;
}

/**************************************************
* Desc:     DS18B20 写位
* Para: In: bit: 位值, 0 或 1
**************************************************/
static void DS18B20_WriteBit(u8 bit)
{
    delay_us(2);            // 读/写 时序的间隔
    DS18B20_RESET_BUS;      // 下降沿, 开始 "写" 时序
    if (bit)                // 写 "1"
    {
        delay_us(5);        // 15 us 内拉高总线
        DS18B20_SET_BUS;    // 写 "1", 释放总线
        delay_us(60);       // 时序至少持续 60 us
    }
    else                    // 写 "0"
    {
        delay_us(60);       // 时序至少持续 60 us
        DS18B20_SET_BUS;    // 释放总线
    }
}

/**************************************************
* Desc:     DS18B20 读位
* Return:   bit:    读到的位值, 0 或 1
**************************************************/
static u8 DS18B20_ReadBit(void)
{
    u8 bit = 0;

    delay_us(2);            // 读/写 时序的间隔
    DS18B20_RESET_BUS;      // 下降沿, 开始 "读" 时序
    delay_us(2);            // 至少保持 1 us
    DS18B20_SET_BUS;        // 释放总线
    delay_us(15);           // 从下降沿开始, 至少保持 15 us
    bit = DS18B20_READ_BUS; // 读取总线
    delay_us(50);           // 时序至少持续 60 us

    return bit;
}

/**************************************************
* Desc:     DS18B20 写字节
* Para: In: data: 要写入的数据
**************************************************/
void DS18B20_WriteByte(u8 data)
{
    u8 i = 0;

    for (i = 0; i < 8; i++)
    {
        DS18B20_WriteBit(data & 0x01);
        data >>= 1;
    }
}

/**************************************************
* Desc:     DS18B20 读字节
* Return:   data: 读到的数据
**************************************************/
u8 DS18B20_ReadByte(void)
{
    u8 i = 0;
    u8 data = 0;

    for (i = 0; i < 8; i++)
    {
        data = data | (DS18B20_ReadBit() << 7);
        data = (i == 7) ? data : (data >> 1);
    }

    return data;
}

/**************************************************
* Desc:     DS18B20 开始一次温度转换
**************************************************/
static void DS18B20_StartConversion(void)
{
    DS18B20_ResetSig();
    if (!DS18B20_PresenceSig()) { return; }
    DS18B20_WriteByte(0xCC);            // 跳过 ROM
    DS18B20_WriteByte(0x44);            // 开始一次温度转换
    while (!DS18B20_ReadBit());         // 等待转换完成
}

/**************************************************
* Desc:     DS18B20 写入 SCRATCHPAD
* Other:    写入顺序: TH reg, TL reg, config reg,
*           config reg, user byte3, user byte4
*           如果未使用报警功能, 则TH reg, TL reg
*           当做用户字节使用
**************************************************/
static void DS18B20_WriteScratchPad(void)
{
    u8 i = 0;
    u8 *addr;
    u8 max_write_byte = 5;                              // SCRATCHPAD 最大 5 字节可写入

    /* 要写入的数据 */
    ds18b20.scratchpad.th_reg_ub1 = 0x50;                // 温度报警上限: 0x50(+80°C)
    ds18b20.scratchpad.tl_reg_ub2 = 0x8A;                // 温度报警下限: 0x8A(-10°C)
    ds18b20.scratchpad.config_reg = DS18B20_RES_12BITS;  // 温度转换分辨率: 12 bits
    ds18b20.scratchpad.user_byte3 = 0x00;                // 用户字节, 按需使用
    ds18b20.scratchpad.user_byte4 = 0x00;

    DS18B20_ResetSig();
    if (!DS18B20_PresenceSig()) { return; }
    DS18B20_WriteByte(0xCC);            // 跳过 ROM
    DS18B20_WriteByte(0x4E);            // 写 SCRATCHPAD
    /* 由于 config reg 和 user byte 3 之间存在 reserved, 因此循环数必须 + 1 */
    for (i = 0; i < (max_write_byte + 1); i++)
    {
        if (i == 3) { continue; }       // 跳过 reserved 字节, 该字节不可被写入
        addr = &ds18b20.scratchpad.th_reg_ub1 + i;
        DS18B20_WriteByte(*addr);
    }
}

/**************************************************
* Desc:     DS18B20 读取 SCRATCHPAD
**************************************************/
static void DS18B20_ReadScratchPad(void)
{
    u8 i = 0;
    u8 *addr;
    u8 max_read_byte = 9;                // SCRATCHPAD 最大 9 字节可读取

    DS18B20_ResetSig();
    if (!DS18B20_PresenceSig()) { return; }
    DS18B20_WriteByte(0xCC);            // 跳过 ROM
    DS18B20_WriteByte(0xBE);            // 读 SCRATCHPAD
    for (i = 0; i < max_read_byte; i++)
    {
        addr = &ds18b20.scratchpad.temp_lsb + i;
        *addr = DS18B20_ReadByte();
    }
}

/**************************************************
* Desc:     DS18B20 将数据从 SCRATCHPAD 复制到 EEPROM
* Other:    功能为断电保存, 下次上电时自动从 EPPROM 读取配置
**************************************************/
static void DS18B20_CopyScratchPad(void)
{
    DS18B20_ResetSig();
    if (!DS18B20_PresenceSig()) { return; }
    DS18B20_WriteByte(0xCC);            // 跳过 ROM
    DS18B20_WriteByte(0x48);            // 开始复制 SCRATCHPAD
    while (!DS18B20_ReadBit());         // 等待复制完成
}

/**************************************************
* Desc:     DS18B20 将数据从 EEPROM 复制到 SCRATCHPAD
**************************************************/
static void DS18B20_RecallE2(void)
{
    DS18B20_ResetSig();
    if (!DS18B20_PresenceSig()) { return; }
    DS18B20_WriteByte(0xCC);            // 跳过 ROM
    DS18B20_WriteByte(0xB8);            // 开始复制 SCRATCHPAD
    while (!DS18B20_ReadBit());         // 等待复制完成
}

/**************************************************
* Desc:     DS18B20 初始化
**************************************************/
void DS18B20_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin   = DS18B20_PIN_TX;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DS18B20_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin   = DS18B20_PIN_RX;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_Init(DS18B20_GPIO, &GPIO_InitStructure);
    GPIO_SetBits(DS18B20_GPIO, DS18B20_PIN_TX);
}

/**************************************************
* Desc:     DS18B20 获取一次温度
**************************************************/
void DS18B20_GetTemperature(void)
{
    u8 shift_size = 0;
    u8 neg_flag = 0;
    u8 temp_msb = 0, temp_lsb = 0;
    u16 temp_reg = 0;
    float temperature = 0.0;

    DS18B20_StartConversion();
    DS18B20_ReadScratchPad();

    temp_msb = ds18b20.scratchpad.temp_msb;
    temp_lsb = ds18b20.scratchpad.temp_lsb;

    if (temp_msb > 7)     // 零下温度, 取反后 + 1
    {
        temp_msb = ~temp_msb;
        temp_lsb = ~temp_lsb;
        temp_reg = ((temp_msb << 8) | temp_lsb) + 1;
        temp_reg &= 0x07FF;
        neg_flag = 1;
    }
    else
    {
        temp_reg = (temp_msb << 8) | temp_lsb;
        temp_reg &= 0x7FF;
    }
    shift_size = (ds18b20.scratchpad.config_reg >> 5);  // 计算分辨率对应运算值
    temperature = (float)temp_reg / (2 << shift_size);

    ds18b20.negative_flag = neg_flag;
    ds18b20.temperature   = temperature;
}

/**************************************************
* Desc:     DS18B20 测试
**************************************************/
void DS18B20_Test(void)
{
    DS18B20_GetTemperature();
    delay_ms(1000);
}

3.2 ds18b20.h

#ifndef __DS18B20_H
#define __DS18B20_H

#include "stm32f10x.h"
#include "delay.h"

#define DS18B20_GPIO        GPIOB
#define DS18B20_PIN_TX      GPIO_Pin_10
#define DS18B20_PIN_RX      GPIO_Pin_11

#define FALSE       0
#define TRUE        1

typedef enum
{
    DS18B20_RES_9BITS   = 0x1F,    // 温度转换分辨率 9 bits
    DS18B20_RES_10BITS  = 0x3F,
    DS18B20_RES_11BITS  = 0x5F,
    DS18B20_RES_12BITS  = 0x7F,
} DS18B20_RES_E_TYPE;

typedef struct
{
    u8 temp_lsb;
    u8 temp_msb;
    u8 th_reg_ub1;
    u8 tl_reg_ub2;
    u8 config_reg;
    u8 reserved;
    u8 user_byte3;
    u8 user_byte4;
    u8 crc;
} DS18B20_SCRATCHPAD_S_TYPE;

typedef struct
{
    u8 negative_flag;
    float temperature;
    DS18B20_SCRATCHPAD_S_TYPE scratchpad;
} DS18B20_STATUE_S_TYPE;

void DS18B20_Init(void);
void DS18B20_GetTemperature(void);
void DS18B20_Test(void);

#endif

3.3 main.c

#include "ds18b20.h"
#include "stm32f10x.h"

int main(void)
{
    SystemInit();
    delay_init();

    DS18B20_Init();
    while (1)
    {
        DS18B20_Test();
    }
}

4 备注

240506:内容大概会不断完善

240507:存在信号时间调试方法

1. 在 if ((time >= 30) && (time <= 240)) { return TRUE; } 这一行加入断点

2. 调试->运行,到该断点时,在Call Stack 里查看变量值

3. 29行 delay_us() 小于 变量值

4. 40行 time最小值 计算方式按照图中方法,小于该值即可

5. 调试一次即可(大概)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值