一个IO上挂接多个DS18B20

32 篇文章 2 订阅

【本文发布于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));
    
}



待完善文字说明

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值