打印
[牛人杂谈]

单总线挂多个DS18B20

[复制链接]
785|37
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuotuzi|  楼主 | 2023-2-25 19:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include "DS18B20.h"
#include "Delay.h"
#include "stdio.h" // printf用

#define DS18B20_GPIO_NUM                                 GPIO_Pin_5
#define DS18B20_GPIO_X                                        GPIOC
#define RCC_APB2Periph_DS18B20_GPIO_X        RCC_APB2Periph_GPIOC

#define DS18B20_DQ_OUT_Low                        GPIO_ResetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)
#define DS18B20_DQ_OUT_High                        GPIO_SetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)
#define DS18B20_DQ_IN                                GPIO_ReadInputDataBit(DS18B20_GPIO_X,DS18B20_GPIO_NUM)

#define MaxSensorNum 8
unsigned char DS18B20_ID[MaxSensorNum][8];        // 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限
unsigned char DS18B20_SensorNum;                        // 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)

// 配置DS18B20用到的I/O口
void DS18B20_GPIO_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_DS18B20_GPIO_X, ENABLE);
        GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
        GPIO_SetBits(DS18B20_GPIO_X, DS18B20_GPIO_NUM);
}

// 引脚输入
void DS18B20_Mode_IPU(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
}

// 引脚输出
void DS18B20_Mode_Out(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);

}

// 复位,主机给从机发送复位脉冲
void DS18B20_Rst(void)
{
        DS18B20_Mode_Out();
        DS18B20_DQ_OUT_Low;                // 产生至少480us的低电平复位信号
        Delay_us(480);
        DS18B20_DQ_OUT_High;        // 在产生复位信号后,需将总线拉高
        Delay_us(15);
}

// 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲
u8 DS18B20_Answer_Check(void)
{
        u8 delay = 0;
        DS18B20_Mode_IPU(); // 主机设置为上拉输入
        // 等待应答脉冲(一个60~240us的低电平信号 )的到来
        // 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
        while (DS18B20_DQ_IN&&delay < 100)
        {
                delay++;
                Delay_us(1);
        }
        // 经过100us后,如果没有应答脉冲,退出函数
        if (delay >= 100)//Hu200
                return 1;
        else
                delay = 0;
        // 有应答脉冲,且存在时间不超过240us
        while (!DS18B20_DQ_IN&&delay < 240)
        {
                delay++;
                Delay_us(1);
        }
        if (delay >= 240)
                return 1;
        return 0;
}

// 从DS18B20读取1个位
u8 DS18B20_Read_Bit(void)
{
        u8 data;
        DS18B20_Mode_Out();
        DS18B20_DQ_OUT_Low; // 读时间的起始:必须由主机产生 >1us <15us 的低电平信号
        Delay_us(2);
        DS18B20_DQ_OUT_High;
        Delay_us(12);
        DS18B20_Mode_IPU();// 设置成输入,释放总线,由外部上拉电阻将总线拉高
        if (DS18B20_DQ_IN)
                data = 1;
        else
                data = 0;
        Delay_us(50);
        return data;
}

// 从DS18B20读取2个位
u8 DS18B20_Read_2Bit(void)//读二位 子程序
{
        u8 i;
        u8 dat = 0;
        for (i = 2; i > 0; i--)
        {
                dat = dat << 1;
                DS18B20_Mode_Out();
                DS18B20_DQ_OUT_Low;
                Delay_us(2);
                DS18B20_DQ_OUT_High;
                DS18B20_Mode_IPU();
                Delay_us(12);
                if (DS18B20_DQ_IN)        dat |= 0x01;
                Delay_us(50);
        }
        return dat;
}

// 从DS18B20读取1个字节
u8 DS18B20_Read_Byte(void)        // read one byte
{
        u8 i, j, dat;
        dat = 0;
        for (i = 0; i < 8; i++)
        {
                j = DS18B20_Read_Bit();
                dat = (dat) | (j << i);
        }
        return dat;
}

// 写1位到DS18B20
void DS18B20_Write_Bit(u8 dat)
{
        DS18B20_Mode_Out();
        if (dat)
        {
                DS18B20_DQ_OUT_Low;// Write 1
                Delay_us(2);
                DS18B20_DQ_OUT_High;
                Delay_us(60);
        }
        else
        {
                DS18B20_DQ_OUT_Low;// Write 0
                Delay_us(60);
                DS18B20_DQ_OUT_High;
                Delay_us(2);
        }
}

// 写1字节到DS18B20
void DS18B20_Write_Byte(u8 dat)
{
        u8 j;
        u8 testb;
        DS18B20_Mode_Out();
        for (j = 1; j <= 8; j++)
        {
                testb = dat & 0x01;
                dat = dat >> 1;
                if (testb)
                {
                        DS18B20_DQ_OUT_Low;// 写1
                        Delay_us(10);
                        DS18B20_DQ_OUT_High;
                        Delay_us(50);
                }
                else
                {
                        DS18B20_DQ_OUT_Low;// 写0
                        Delay_us(60);
                        DS18B20_DQ_OUT_High;// 释放总线
                        Delay_us(2);
                }
        }
}

//初始化DS18B20的IO口,同时检测DS的存在
u8 DS18B20_Init(void)
{
        DS18B20_GPIO_Config();
        DS18B20_Rst();
        return DS18B20_Answer_Check();
}

// 从ds18b20得到温度值,精度:0.1C,返回温度值(-550~1250),Temperature1返回浮点实际温度
float DS18B20_Get_Temp(u8 i)
{
        //u8 flag;
        u8 j;//匹配的字节
        u8 TL, TH;
        short Temperature;
        float Temperature1;
        DS18B20_Rst();
        DS18B20_Answer_Check();
        DS18B20_Write_Byte(0xcc);// skip rom
        DS18B20_Write_Byte(0x44);// convert
        DS18B20_Rst();
        DS18B20_Answer_Check();

        // DS18B20_Write_Byte(0xcc);// skip rom
        //匹配ID,i为形参
        DS18B20_Write_Byte(0x55);
        for (j = 0; j < 8; j++)
        {
                DS18B20_Write_Byte(DS18B20_ID[i][j]);
        }

        DS18B20_Write_Byte(0xbe);// convert
        TL = DS18B20_Read_Byte(); // LSB   
        TH = DS18B20_Read_Byte(); // MSB  
        if (TH & 0xfc)
        {
                //flag=1;
                Temperature = (TH << 8) | TL;
                Temperature1 = (~Temperature) + 1;
                Temperature1 *= 0.0625;
        }
        else
        {
                //flag=0;
                Temperature1 = ((TH << 8) | TL)*0.0625;
        }
        return Temperature1;
}

// 自动搜索ROM
void DS18B20_Search_Rom(void)
{
        u8 k, l, chongtuwei, m, n, num;
        u8 zhan[5];
        u8 ss[64];
        u8 tempp;
        l = 0;
        num = 0;
        do
        {
                DS18B20_Rst(); //注意:复位的延时不够
                Delay_us(480); //480、720
                DS18B20_Write_Byte(0xf0);
                for (m = 0; m < 8; m++)
                {
                        u8 s = 0;
                        for (n = 0; n < 8; n++)
                        {
                                k = DS18B20_Read_2Bit();//读两位数据

                                k = k & 0x03;
                                s >>= 1;
                                if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应
                                {
                                        DS18B20_Write_Bit(0);
                                        ss[(m * 8 + n)] = 0;
                                }
                                else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应
                                {
                                        s = s | 0x80;
                                        DS18B20_Write_Bit(1);
                                        ss[(m * 8 + n)] = 1;
                                }
                                else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位
                                {
                                        //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
                                        chongtuwei = m * 8 + n + 1;
                                        if (chongtuwei > zhan[l])
                                        {
                                                DS18B20_Write_Bit(0);
                                                ss[(m * 8 + n)] = 0;
                                                zhan[++l] = chongtuwei;
                                        }
                                        else if (chongtuwei < zhan[l])
                                        {
                                                s = s | ((ss[(m * 8 + n)] & 0x01) << 7);
                                                DS18B20_Write_Bit(ss[(m * 8 + n)]);
                                        }
                                        else if (chongtuwei == zhan[l])
                                        {
                                                s = s | 0x80;
                                                DS18B20_Write_Bit(1);
                                                ss[(m * 8 + n)] = 1;
                                                l = l - 1;
                                        }
                                }
                                else
                                {
                                        //没有搜索到
                                }
                        }
                        tempp = s;
                        DS18B20_ID[num][m] = tempp; // 保存搜索到的ID
                }
                num = num + 1;// 保存搜索到的个数
        } while (zhan[l] != 0 && (num < MaxSensorNum));
        DS18B20_SensorNum = num;
        //printf("DS18B20_SensorNum=%d\r\n",DS18B20_SensorNum);
}
DS18B20.h文件代码:
#ifndef __DS18B20_H
#define __DS18B20_H
  
#include "stm32f10x.h"

u8 DS18B20_Init(void);
u8 DS18B20_Read_Byte(void);
u8 DS18B20_Read_Bit(void);
u8 DS18B20_Answer_Check(void);
void  DS18B20_GPIO_Config(void);
void  DS18B20_Mode_IPU(void);
void  DS18B20_Mode_Out(void);
void  DS18B20_Rst(void);
void  DS18B20_Search_Rom(void);
void  DS18B20_Write_Byte(u8 dat);
float DS18B20_Get_Temp(u8 i);

#endif


使用特权

评论回复
沙发
dongnanxibei| | 2023-2-26 20:06 | 只看该作者
是不是理论上可以挂无数个,只要ROM地址不同。

使用特权

评论回复
板凳
jiekou001| | 2023-2-26 20:21 | 只看该作者
自动搜索ROM的原理是什么

使用特权

评论回复
地板
jiekou001| | 2023-2-26 20:22 | 只看该作者
Arduino的库很不错,可以参考参考。

使用特权

评论回复
5
643757107| | 2023-2-26 20:54 | 只看该作者
一直没学会搜索那个ROM的方法,看不懂。

使用特权

评论回复
6
小夏天的大西瓜| | 2023-2-27 14:26 | 只看该作者
DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点

使用特权

评论回复
7
星辰大海不退缩| | 2023-2-27 15:02 | 只看该作者
自动搜索没搞明白

使用特权

评论回复
8
AloneKaven| | 2023-3-1 20:08 | 只看该作者
搜索rom是怎么实现的啊?

使用特权

评论回复
9
bartonalfred| | 2023-4-16 22:21 | 只看该作者
在连接多个 DS18B20 温度传感器时,需要考虑总线的电气特性、传输速率等因素对通信稳定性和精度的影响。

使用特权

评论回复
10
豌豆爹| | 2023-4-17 15:13 | 只看该作者
自动搜索ROM是什么原理

使用特权

评论回复
11
youtome| | 2023-4-17 18:01 | 只看该作者
使用单总线通信协议读取和写入 DS18B20 温度传感器的数据。在通信过程中,需要使用每个传感器的唯一 ROM 码进行地址匹配,以区分不同的传感器。

使用特权

评论回复
12
jkl21| | 2023-4-18 16:20 | 只看该作者
将多个 DS18B20 温度传感器的数据线(DQ)和上拉电阻连接在一起,形成一个物理上共享的单总线。

使用特权

评论回复
13
wwppd| | 2023-4-18 17:57 | 只看该作者
需要注意防止总线上存在干扰信号和冲突情况。

使用特权

评论回复
14
gygp| | 2023-4-18 19:58 | 只看该作者
可以使用单总线协议同时连接多个 DS18B20 温度传感器。

使用特权

评论回复
15
Jacquetry| | 2023-4-18 23:05 | 只看该作者
自动搜寻ROM怎么实现啊?

使用特权

评论回复
16
huangcunxiake| | 2023-4-19 19:09 | 只看该作者
很少这么用, 但是很重要的场合都这么用。

使用特权

评论回复
17
chenqianqian| | 2023-4-19 21:21 | 只看该作者
现在还在用DS18B20来测温嘛?

使用特权

评论回复
18
Stahan| | 2023-4-19 23:05 | 只看该作者
如何自动匹配ROM码啊?

使用特权

评论回复
19
OKAKAKO| | 2023-4-20 13:24 | 只看该作者
一般情况下轮询读取应该就没问题,楼主这个程序比较经典

使用特权

评论回复
20
小小蚂蚁举千斤| | 2023-4-22 17:02 | 只看该作者
确实对自动获取ROM这部分不太清楚

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

164

主题

3192

帖子

7

粉丝