一个IO上挂接多个DS18B20

这篇具有很好参考价值的文章主要介绍了一个IO上挂接多个DS18B20。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【本文发布于https://blog.csdn.net/Stack_/article/details/132733884,未经许可不得转载,转载须注明出处】


找一张二叉树的图片,结合代码以及代码注释去理解。


#define DS18B20_PORT                              PORT5
#define DS18B20_PIN                               PIN2

#define DS18B20_NUM                                     5


#define DS18B20_PIN_MODE_IN(PORTx, PINx)           //配置为输入

#define DS18B20_PIN_MODE_OUT(PORTx, PINx)          //配置为开漏输出

#define DS18B20_PIN_GET(PORTx, PINx)              PORT_GetBit(PORTx, PINx)


typedef struct {
    uint8_t Online[DS18B20_NUM];    //是否在线
    uint8_t Valid[DS18B20_NUM];     //温度值是否有效
    int32_t Temperature[DS18B20_NUM];   //4位小数
    uint8_t ROM_Code[DS18B20_NUM][8];   //64位rom code
} ds18b20_t;    
                                                    
extern ds18b20_t   ds18b20_data;

void DS18B20_Init(void);
void DS18B20_Proc(void);



ds18b20_t   ds18b20_data;


/**
  * @brief
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
static bool DS18B20_Online_Check(PORT_TypeDef PORTx, PIN_TypeDef PINx)
{
    uint32_t wait = 0;

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);
    DELAY_US(10);
    PORT_ClrBit(PORTx, PINx);
    DELAY_US(700);
    PORT_SetBit(PORTx, PINx);

    DS18B20_PIN_MODE_IN(PORTx, PINx);
    DELAY_US(30);
    if (!DS18B20_PIN_GET(PORTx, PINx))	//有应答
    {
        UserTimer_Reset(&wait);
        while (!DS18B20_PIN_GET(PORTx, PINx) && UserTimer_Read(&wait) < 2);	//等待应答信号结束,最长等待1~2ms
        if (DS18B20_PIN_GET(PORTx, PINx))
            return true;
        else
            return false;
    }
    else
    {
        return false;
    }
}



/**
  * @brief
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
static void DS18B20_Write(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t val)
{
    uint8_t i;

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);

    for (i = 0; i < 8; i++)
    {
        PORT_SetBit(PORTx, PINx);
        DELAY_US(4);
        PORT_ClrBit(PORTx, PINx);
        DELAY_US(1);
        if (val & 0x01)
            PORT_SetBit(PORTx, PINx);
        else
            PORT_ClrBit(PORTx, PINx);
        DELAY_US(66);
        val >>= 1;
    }

    PORT_SetBit(PORTx, PINx);
}



/**
  * @brief  读2个bit
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
static uint8_t DS18B20_Read2Bit(PORT_TypeDef PORTx, PIN_TypeDef PINx)
{
    uint8_t i;
    uint8_t val = 0;

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);

    for (i = 0; i < 2; i++)
    {
        val <<= 1;
        DS18B20_PIN_MODE_OUT(PORTx, PINx);
        PORT_SetBit(PORTx, PINx);
        DELAY_US(4);
        PORT_ClrBit(PORTx, PINx);
        DELAY_US(1);
        PORT_SetBit(PORTx, PINx);
        DS18B20_PIN_MODE_IN(PORTx, PINx);
        DELAY_US(5);
        if (DS18B20_PIN_GET(PORTx, PINx))
            val |= 0x01;
        DELAY_US(60);
    }

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);

    return val;
}
/**
  * @brief
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
static void DS18B20_Write1Bit(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t val)
{
    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);

    PORT_SetBit(PORTx, PINx);
    DELAY_US(4);
    PORT_ClrBit(PORTx, PINx);
    DELAY_US(1);
    if (val & 0x01)
        PORT_SetBit(PORTx, PINx);
    else
        PORT_ClrBit(PORTx, PINx);
    DELAY_US(66);

    PORT_SetBit(PORTx, PINx);
}

/**
  * @brief  读N个字节
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
static void DS18B20_Read(PORT_TypeDef PORTx, PIN_TypeDef PINx, uint8_t *bytes_array, uint8_t n_bytes)
{
    uint8_t i, j;
    uint8_t val = 0;

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);

    for (i = 0; i < n_bytes; i++)
    {
        for (j = 0; j < 8; j++)
        {
            val >>= 1;
            DS18B20_PIN_MODE_OUT(PORTx, PINx);
            PORT_SetBit(PORTx, PINx);
            DELAY_US(4);
            PORT_ClrBit(PORTx, PINx);
            DELAY_US(1);
            PORT_SetBit(PORTx, PINx);
            DS18B20_PIN_MODE_IN(PORTx, PINx);
            DELAY_US(5);
            if (DS18B20_PIN_GET(PORTx, PINx))
                val |= 0x80;
            DELAY_US(60);
        }
        bytes_array[i] = val;
    }

    DS18B20_PIN_MODE_OUT(PORTx, PINx);
    PORT_SetBit(PORTx, PINx);
}

/**
  * @brief  获取总线上各器件的ID
  * @note   二叉树遍历获取ROM CODE
  * @param  None
  * @retval None
  * @author PWH
  * @date   2023/2
  */
static void DS18B20_Search_ROMCode(void)
{
    #define _00_OVER_ONE_DS18B20_BIT_DIFFERENT      0x00    //有超过1个的设备,且它们在这一位上的值有0也有1
    #define _01_DS18B20_BITS_SAME_0                 0x01    //可能只有一个,或者有多个且它们的这一位的值都为0
    #define _10_DS18B20_BITS_SAME_1                 0x02    //可能只有一个,或者有多个且它们的这一位的值都为1
    #define _11_DS18B20_ALL_OFFLINE                 0x03    //总线无响应,不存在设备
    bool sta;
    uint8_t bit_val, code_val;
    uint8_t i, j;
    uint8_t num = 0;
    uint8_t stack_top[DS18B20_NUM], stack_top_cnt = 0; //记录栈顶(存在分叉的节点),一次遍历,最多有DS18B20_NUM-1次冲突
    uint8_t deep;   //记录当前深度
    uint8_t node_choice[64];    //记录该分叉点选择的路线
    uint8_t node_now;
    
    memset(stack_top, 0, sizeof(stack_top));
    memset(node_choice, 0, sizeof(node_choice));
    
    sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
    
    if (sta)
    {
        do {
        
            DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
            
            DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xF0); //Search ROM 指令
            
            node_now = deep = 0;
            
            for (i = 0; i < 8; i++)
            {
                code_val = 0;
                
                for (j = 0; j < 8; j++) //i * j = 64位rom code
                {
                    code_val >>= 1;
                    
                    bit_val = DS18B20_Read2Bit(DS18B20_PORT, DS18B20_PIN);  //读取2bit(bit1为实际值,bit0为实际值的补码)
                    deep++;     //每读一次,深度加一,深度1-64
                    
                    switch (bit_val)
                    {
                        case _00_OVER_ONE_DS18B20_BIT_DIFFERENT:    //冲突,分叉节点,选择一条未走过的路径
                            if (deep > stack_top[stack_top_cnt])    //当前冲突点深度大于记录的最新的冲突点,为新的冲突点,选择左边(0)路线
                            {
                                DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 0); 
                                node_choice[deep - 1] = 0;
                                stack_top[++stack_top_cnt] = deep;   //增加记录,记录最深/最新的一个冲突点(未走完2条路线的)
                            }
                            else if (deep < stack_top[stack_top_cnt])   //当前冲突点深度小于最深的冲突点,未到达上次记录的点,采用上次该点的值,选择上次在该点选择的路线
                            {
                                code_val |= (node_choice[deep - 1] << 7);
                                DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, node_choice[deep - 1]);
                            }
                            else    //到达上次记录的最深的冲突点,选择新路线(1)
                            {
                                code_val |= 0x80;
                                DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 1);
                                node_choice[deep - 1] = 1;
                                stack_top_cnt--;    //该分叉点的路线都走过了,减去该节点
                            }
                            break;
                        case _01_DS18B20_BITS_SAME_0:
                            DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 0);    //无冲突,无节点   通知此位为非0的后续不要响应(实际不存在非0的)
                            node_choice[deep - 1] = 0;
                            break;
                        case _10_DS18B20_BITS_SAME_1:
                            DS18B20_Write1Bit(DS18B20_PORT, DS18B20_PIN, 1);    //无冲突,无节点   通知此位为非1的后续不要响应(实际不存在非1的)
                            code_val |= 0x80;
                            node_choice[deep - 1] = 1;
                            break;
                        case _11_DS18B20_ALL_OFFLINE:
                            
                            break;
                        default:
                            
                            break;
                    }
                }
                ds18b20_data.ROM_Code[num][i] = code_val;
            }
            
            ds18b20_data.Online[num] = 1;
            
            printf("搜索ROM CODE %d : 0x", num);
            for (i = 0; i < 8; i++)
            {
                printf("%.2x", ds18b20_data.ROM_Code[num][7 - i]);
            }
            printf("\r\n");
            /*
            [17:10:34.852] [      7796][0000:00:07.795]#0 ROM CODE is : 0x6203139794034828
            [17:10:34.882] [      7822][0000:00:07.821]#1 ROM CODE is : 0xb9031397945fcf28
            [17:10:34.884] [      7848][0000:00:07.848]#2 ROM CODE is : 0x3103139794203428
            [17:10:34.930] [      7874][0000:00:07.874]#3 ROM CODE is : 0x3603029794140728
            [17:10:34.962] [      7900][0000:00:07.900]#4 ROM CODE is : 0xc70304979422c328
            */
                
            num++;
            
        } while (stack_top[stack_top_cnt] && num < DS18B20_NUM);    //
    }
    else
    {
        printf("搜索ROM CODE无器件\r\n");
    }
}

/**
  * @brief
  * @note   main while调用
  * @param  None
  * @retval None
  * @author PWH
  * @date   2022/10
  */
void DS18B20_Proc(void)
{
    static uint32_t timer = 0;
    static uint8_t Num = 0;
    uint16_t temp;
    int32_t temperature;
    const uint16_t temper_decimal[16] = {0, 625, 1250, 1875, 2500, 3125, 3750, 4375, 5000, 5625, 6250, 6875, 7500, 8125, 8750, 9375};
    bool sta;
    static uint8_t step = 0;
    static uint32_t interval = 1000;
    uint8_t i;
    uint8_t array[8];
    uint8_t *array_p = array + 7;
    static bool f_search = false;
    
    if (timer < TIMEOUT_1S * 3) //电源稳定后搜索
    {
        UserTimer_Reset(&timer);
        return;
    }
        
    if (f_search == false)
    {
        f_search = true;
        DS18B20_Search_ROMCode();
    }
    
    if (UserTimer_Read(&timer) > interval)
    {        
        if (step == 0)  //发转换命令,转换时间为750ms
        {
            sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
            if (sta == true)
            {
                DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xCC);   //跳过ID读取
                DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0x44);   //开始转换温度         
            }
            else
            {
                printf("DS总线无应答\r\n");
            }
        }
        else //读取温度
        {
            sta = DS18B20_Online_Check(DS18B20_PORT, DS18B20_PIN);
            if (sta == true)
            {
                DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0x55); //匹配 ROM 指令
                for (i = 0; i < 8; i++)
                {
                    DS18B20_Write(DS18B20_PORT, DS18B20_PIN, ds18b20_data.ROM_Code[Num][i]);    //发送8字节rom code
                }
                DS18B20_Write(DS18B20_PORT, DS18B20_PIN, 0xBE);

                DS18B20_Read(DS18B20_PORT, DS18B20_PIN, array, 2);
                temp = _bytes2short(array[1], array[0]);
                
                if (temp & 0xf800)
                {
                    temperature = ~(temp & 0x07ff) + 1;
                    temperature = (temperature >> 4) * 10000 + temper_decimal[temperature & 0x000f];
                    temperature = -temperature;
                }
                else
                {
                    temperature = temp;
                    temperature = (temperature >> 4) * 10000 + temper_decimal[temperature & 0x000f];
                }
                
                if (temperature >= -550000 && temperature <= 1250000)
                {
                    ds18b20_data.Temperature[Num] = temperature;
                    ds18b20_data.Valid[Num] = 1;
                }
                else
                {
                    ds18b20_data.Valid[Num] = 0;
                    printf("#%d数据无效 - %d\r\n", Num, temperature);
                }
            }
            else
            {
                printf("读取温度无应答\r\n");
            }
        }

        if (++Num >= DS18B20_NUM || !ds18b20_data.Online[Num])
        {
            Num = 0;
            UserTimer_Reset(&timer);
            #if (0)
            if (step)
            {
                printf("\r\n");
                for (uint8_t j = 0; j < DS18B20_NUM; j++)
                    printf("#%d = %.3f℃, ", j + 1, (float)ds18b20_data.Temperature[j] / 10000);
                printf("\r\n");
            }
            #endif
            step = !step;
            if (step) interval = 1000;
            else interval = 500;
        }
    }
}

/**
  * @brief  初始化
  * @note
  * @param  None
  * @retval None
  * @author PWH
  * @date   2023/2
  */
void DS18B20_Init(void)
{
    DS18B20_PIN_INIT(DS18B20_PORT, DS18B20_PIN);
    memset(ds18b20_data.Online, 0, sizeof(ds18b20_data));
    
}



待完善文字说明文章来源地址https://www.toymoban.com/news/detail-698116.html

到了这里,关于一个IO上挂接多个DS18B20的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • DS18B20测量温度

    一般在使用DS18B20时会按照以下步骤进行温度转换并读取: 1、主机发送复位脉冲 2、DS18B20响应 3、发送0xCC命令跳过ROM命令 4、发送功能命令 5、发送功能命令0x44启动温度转换 6、判断温度转换是否完成(为读取1Bit数据为1表示完成) 7、下一个初始化序列开始读取温度 8、然后按

    2023年04月08日
    浏览(45)
  • DS18B20使用说明

    基础介绍引脚介绍 DS18B20是单总线协议的典型代表,同时也是单总线协议最广泛的应用场景,是常用的数字温度传感器,其输出的是数字信号。具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20数字温度传感器接线方便,封装成后可应用于多种场合。 DS18B20 的温

    2024年02月09日
    浏览(34)
  • stm32之DS18B20

            DS18B20与stm32之间也是通过单总线进行数据的传输的。单总线协议在DHT11中已经介绍过。虽说这两者外设都是单总线,但时序电路却很不一样,DS18B20是更为麻烦一点的。  举例(原码补码反码转换_原码反码补码转换_王小小鸭的博客-CSDN博客):  将这两个字节的数

    2024年02月10日
    浏览(41)
  • DS18B20温度测量程序文件(简单通用)

    DS18B20是一个非常简单的温度传感器,对于像我这样单片机萌新是比较友好的。网上关于它的介绍非常多,包括原理、引脚、通信、以及51单片机、STM32的各种代码等等。本人写了一个简单的ds18b20.c库文件分享给大家,该文件内的函数可以实现单个元件的单次测温功能,温度精

    2024年02月05日
    浏览(42)
  • DS18B20温度传感器工作原理

    目录 管脚描述 综述 访问DS18B20的事件序列 通信时序 VDD:电源引脚,当采用寄生电源的时候,VDD必须连接到地 DQ:单总线运用的数据输入/输出,当采用寄生电源供电时,同时向设备提供电源 GND:地 ①DS18B20片内的ROM中都存在独一无二的64位编码,在后期通信时,是用此编码进

    2024年02月09日
    浏览(43)
  • 【mcuclub】温度传感器DS18B20

        VCC:外接供电电源输入端。 DQ: 数字信号输入/输出端。 GND:电源地线 为什么接上拉电阻: 因为DS18B20的数据口是漏极开路,如果不接上拉电阻,则只能输出低电平和高阻态,不能输出高电平,因此需要外接上拉电阻,否则无法输出1。DS18B20的工作电流约为1mA,VCC一般为

    2023年04月22日
    浏览(44)
  • Linux下ds18b20驱动开发获取温度

    对ds18b20不了解的可以查看这篇文章,讲解的比较详细的:STM32一线协议-DS18B20温度传感器采样实现 源码是根据上一届学长的,想要参考的可以去拜访一下gitee:代码链接 (1)修改设备树 在路径 linux-imx/arch/arm/boot/dts/ 下修改设备树 igkboard.dts : 主节点: 从节点: 在源码路径下

    2023年04月22日
    浏览(79)
  • STM32——DS18B20温度传感器

    一、DS18B20介绍 (一)DS18B20技术性能特征 1、独特的单总线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯,大大提高了系统的抗干扰性。 2、测温范围  -55°C~+125°C 3、支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只

    2024年01月19日
    浏览(45)
  • 【单片机】17-温度传感器DS18B20

    (1)测温度的方式:物理(汞柱,气压),电子(金属电性能随温度变化) (2)早期:热敏电阻(模拟接口---》 A/D转换 ) (3)现代:专用sensor(数字接口,如I2C,DS18B20单总线接口等) DS18B20 可编程分辨率单总线 温度传感器 (1)内置集成ADC,外部数字接口 (2) 单总线

    2024年02月04日
    浏览(53)
  • 基于51单片机的DS18B20温度显示

    本讲内容:       了解温度传感器DS18B20的使用,并通过一个例程展示温度传感器DS18B20测温过程。 DS18B20简介:       DS18B20 是单线数字温度传感器,即“一线器件”,其具有独特的优点:     (1)采用单总线的接口方式 与微处理器连接时 仅需要一条口线即可实现微处理器

    2024年02月12日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包