muggle 发表于 2012-12-3 23:48:37

麻瓜学习笔记:02_OneWare总线多个DS18B20数据读取

本帖最后由 弘毅 于 2017-6-17 16:20 编辑

OneWare总线,意思就是一条数据线就可以工作,而且支持多个传感器,相关资料很多,大家可以到网上查阅。因为感兴趣做家庭环境监测,就了解了一下相关的资料。最简单的就是连接一个DS18B20,其实多个连接也很简单,可以使用寄生供电或者独立供电。

DS18B20的接法如附图所示,可以一个,也可以多个,两线或者三线都可以工作。多个传感器三线接法与单个类似,传感器直接GVS并联就可以,4.7K电阻只要接一个就可以。网友评论有时两线不稳定,所以如果不受到接线条件限制,最好还是三线。

连接完成,当然要读取数据,因为连接在一条总线上面,通过读取相应地址传感器,就能得到需要的参数,其实还是很简单。大家一般使用OneWare库,如果使用DallasTemperature库就更简单,下面是DallasTemperature自带的程序,贴在下面供大家参考。

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 12

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

int numberOfDevices; // Number of temperature devices found

DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address

void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");

// Start up the library
sensors.begin();

// Grab a count of devices on the wire
numberOfDevices = sensors.getDeviceCount();

// locate devices on the bus
Serial.print("Locating devices...");

Serial.print("Found ");
Serial.print(numberOfDevices, DEC);
Serial.println(" devices.");

// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");

// Loop through each device, print out address
for(int i=0;i<numberOfDevices; i++)
{
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i))
        {
                Serial.print("Found device ");
                Serial.print(i, DEC);
                Serial.print(" with address: ");
                printAddress(tempDeviceAddress);
                Serial.println();
               
                Serial.print("Setting resolution to ");
                Serial.println(TEMPERATURE_PRECISION,DEC);
               
                // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
                sensors.setResolution(tempDeviceAddress, TEMPERATURE_PRECISION);
               
               Serial.print("Resolution actually set to: ");
                Serial.print(sensors.getResolution(tempDeviceAddress), DEC);
                Serial.println();
        }else{
                Serial.print("Found ghost device at ");
                Serial.print(i, DEC);
                Serial.print(" but could not detect address. Check power and cabling");
        }
}

}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
// method 1 - slower
//Serial.print("Temp C: ");
//Serial.print(sensors.getTempC(deviceAddress));
//Serial.print(" Temp F: ");
//Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

// method 2 - faster
float tempC = sensors.getTempC(deviceAddress);
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");


// Loop through each device, print out temperature data
for(int i=0;i<numberOfDevices; i++)
{
    // Search the wire for address
    if(sensors.getAddress(tempDeviceAddress, i))
        {
                // Output the device ID
                Serial.print("Temperature for device: ");
                Serial.println(i,DEC);
               
                // It responds almost immediately. Let's print out the data
                printTemperature(tempDeviceAddress); // Use a simple function to print out the data
        }
        //else ghost device! Check your power requirements and cabling
       
}
delay(10000);
Serial.println(":");
Serial.println(":");
Serial.println(":");
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
    if (deviceAddress < 16) Serial.print("0");
    Serial.print(deviceAddress, HEX);
}
}


我只增加了十秒延时,还有打印分割,总体没有变动。大家使用以前,检查一下数模输入接线端口是否正确即可。


程序运行以后,输出如下结果到串口。Dallas Temperature IC Control Library Demo
Locating devices...Found 3 devices.
Parasite power is: OFF
Found device 0 with address: 2828843B0400009F
Setting resolution to 12
Resolution actually set to: 12
Found device 1 with address: 28D8AA3B040000B7
Setting resolution to 12
Resolution actually set to: 12
Found device 2 with address: 28DC6754040000AF
Setting resolution to 12
Resolution actually set to: 12
Requesting temperatures...DONE
Temperature for device: 0
Temp C: 18.62 Temp F: 65.52
Temperature for device: 1
Temp C: 19.00 Temp F: 66.20
Temperature for device: 2
Temp C: 19.06 Temp F: 66.31
:
:
:


抛砖引玉,供大家参考。。。


ttyp 发表于 2012-12-4 08:55:18

一直想做多个的1wire传感器的实验呢,后面2图没看懂,5V直接接地?

muggle 发表于 2012-12-4 09:41:19

ttyp 发表于 2012-12-4 08:55 static/image/common/back.gif
一直想做多个的1wire传感器的实验呢,后面2图没看懂,5V直接接地?

确实如此,五伏直接接地,供电由数据线控制对内置电容充电,解决供电问题。这种连接方法叫寄生供电,只需要两条导线就可以连接多个传感器,比如说电话线。

ttyp 发表于 2012-12-4 09:50:27

muggle 发表于 2012-12-4 09:41 static/image/common/back.gif
确实如此,五伏直接接地,供电由数据线控制对内置电容充电,解决供电问题。这种连接方法叫寄生供电,只需 ...

谢谢LZ,原来这就是寄生供电方式啊,早闻大名了,不过貌似寄生供电不稳定哦

Damn_intuition 发表于 2012-12-4 09:59:27

DS18B20的接法如附图所示,可以一个,也可以多个,两线或者三线都可以工作。多个传感器三线接法与单个类似,传感器直接GVS并联就可以,4.7K电阻只要接一个就可以。网友评论有时两线不稳定,所以如果不受到接线条件限制,最好还是三线。
DS18B20在进行温度转换或者将高速缓存里面的数据复制到EEPROM中时,所需的电流会达到1.5mA,超出了电容所能提供的电流

Damn_intuition 发表于 2012-12-4 10:00:43

http://www.geek-workshop.com/forum.php?mod=viewthread&tid=198
开始接触的朋友可以结合一下弘毅的文章。

ttyp 发表于 2012-12-4 10:02:46

Damn_intuition 发表于 2012-12-4 09:59 static/image/common/back.gif
DS18B20在进行温度转换或者将高速缓存里面的数据复制到EEPROM中时,所需的电流会达到1.5mA,超出了电容所 ...

这里有篇文章貌似不错
http://www.docin.com/p-380142311.html

电流10ma

ttyp 发表于 2012-12-4 10:31:03

http://blog.sina.com.cn/s/blog_69bcf45201016phr.html

这位同学说的比较好了

ttyp 发表于 2012-12-4 11:33:11

1温度采集系统的硬件设计
DS18B20作为一种单总线器件,只有3个管脚,具有非常简单的外部结构,因而对应的硬件电路连接也比较简单明了。
1.1供电方式选择
DS18B20温度传感器有寄生电源和外部电源两种供电方式。
VDD引脚做接地处理,DS18B20从单线信号线上汲取能量。要想使DS18B20进行精确的温度转换,I/O线必须保证在温度转换期间提供足够的能量,由于每个DS18B20在温度转换期间工作电流达到1mA,当几个温度传感器挂在同一根I/O线上进行多点测温时,只靠4.7k上拉电阻就无法提供足够的能量,造成无法转换温度或温度误差极大。对寄生电源供电方式进行了改进,也适用于多点测温的应用场合,但要多占用一根端口线。
外部电源方式,顾名思义,即VDD引脚直接接入工作电源VDD的方式,此时不需要强上拉,也不存在电源电流不足的问题,能够保证转换精度,适于组成多点测温系统。
本研究中电动汽车由12个单体铅酸蓄电池提供能量,通过比较该传感器的两种供电方式,选用了外部电源方式。这样,一方面可以解决供电电流不足和需要强上拉的问题,另一方面可以充分发挥DS18B20宽电源电压范围的优点,保证整个系统的稳定工作。
1.2温度采集单总线与主控制器连接方式的确定
单总线与控制器供电连接方式分为直接连接方式和接口芯片方式两种,其中,接口芯片方式主要是为了解决在单总线器件较多的情况下微控制器驱动能力不足的问题。
一般认为,采用外部电源的供电方式时,单总线上可以挂接任意多个单总线温度传感器,但这仅仅是理论上的结论。实验表明,当单总线上挂接的DS18B20超过8个,就需要解决芯片的总线驱动问题,否则整个系统将不能正常工作。本设计中,共需要12个DS18B20来完成电动货车12个单体电池的温度采集工作,因此解决总线驱动问题是我们要做的工作之一。
如果使用DS1481或DS1482等接口芯片,需要占用主控制器的4个I/O端口。如前所述,在电池能量管理系统中,鉴于其本身功能的复杂性,应尽量少地占用芯片的I/O端口,且此种接口芯片方式控制也较为复杂,所以在实际应用中有一定的局限性。
该驱动电路在直接连接方式基础上增加了驱动和与门电路,比直接连接方式仅多占用一条I/O口,和接口芯片方式相比,减少了端口资源的利用,并具有相对简单的控制操作方式。
对于要在单总线上挂接12个单总线器件的问题,显然可以选择上述单总线驱动电路,占用两条I/O线,实现轻松挂接12个器件的目的。但是出于在满足功能需要的前提下,尽量简化系统设计和降低成本的目的,我们摒弃了上面的两种驱动方式,而选择了一种最为简单的折中设计两个单总线并联,即占用微控制器的两个I/O口连接单总线器件,每个单总线上挂接6个温度传感器的方式,如图4所示。显然,这样的配置方案既简单,又很好地解决了总线驱动能力不足的问题,并且尽量节省了芯片端口使用。通过合理设计,优化程序可使得系统处在稳定可靠的工作状态。
实验表明,在采用外接电源供电方式的情况下,一条单总线线路完全可以解决12个单总线器件的驱动问题,但设计两条单总线连接线路,可以提高系统运行的可靠性。
2.软件设计
DS18B20需要较为复杂的软件程序做支持,由于采用单总线数据传输方式,DS18B20的数据输入输出均由同一单总线来完成。因此,操作中必须严格遵守数据手册中所规定的读写时序。对于纯电动汽车电池能量管理系统的温度采集部分,设计时提出如下要求:
(1)系统上电后应能自动检测挂接在总线上的元器件数目,并能对故障元器件进行识别定位;
(2)能实时监测12个单体电池温度值,能实现超限报警功能以及时采取降温措施;
(3)保证温度读取的正确性,防范错误的非预期发生。
实际上,上面的3个功能要求转化到程序设计中,就是在能够完成基本的温度读取工作的前提下,充分利用好Dallas半导体公司单总线器件的搜索ROM(搜索算法采用的是二叉树型结构)功能并随时对采集的重要数据进行循环冗余码(CRC)验证。软件设计的程序框图如图5所示。
在运行初始化程序之后,首先运行搜索ROM子程序。通过该搜索过程,可以得到挂接在总线上的器件数目和其各自的64位唯一序列号。若在搜索过程中总线无响应(搜索算法采用二叉树型结构),则图5程序流程图表明总线上没有器件挂接。一般地,对于多个DS18B20温度传感器组网系统,此种情况较少见,若在搜索整个网络时检测不到器件的存在,单总线和微控制器之间线路出问题的可能性最大,应首先对单总线和微控制器之间的线路采取相应的检修措施。若搜索过程结束,发现总线上器件数目不足12,则表明有器件损坏或脱离总线,此时进入检错子程序,找出问题元器件并修正。需要说明的是,系统温度超限报警值选择由系统主机设置。尽管DS18B20可进行告警命令搜索,即设置器件的高低温限值,然后搜索超限的元器件,但是这样的搜索命令往往要花费较长的时间,由于电动汽车电池管理系统本身就有实时监测12个单体电池温度的需要,因此通过在程序中添加判断语句的方式来完成告警搜索就显的更加快捷。软件设计中,为保证采集温度的准确度,要求对所有采集到的温度值进行CRC验证,只有通过CRC验证的温度值才会被系统接收和采纳,进而进行下一步需要的温度值处理。虽然CRC验证工作会加大程序执行的时间,但由于温度值具有不能突变的特性,即温度采集的实时性要求稍差,这里CRC可能造成的延时也是完全可以接受的。
在软件设计时应注意以下几点:
1)在进行软件设计时,要考虑如果有器件损坏,则有效器件的个数要进行相应处理,并可在温度显示时有选择地剔除。
2)对于报警,处理温度超限子程序会存在误报可能性。
3实验及实验结果
应用Philips公司P87C591微控制芯片,根据系统软硬件设计方案搭建实际系统电路。鉴于整车设计尚未完成,因此只对12路温度传感器进行了模拟测温实验,并在1602液晶上进行显示,同时与现场温度计测量值进行比较,该系统的传感器测量结果与直接测量结果基本吻合,能准确反映各路温度值。
本系统可实现DS18B20温度传感器的全量程测温。采用12位分辨率,对应可辨分辨温度为0.0625,能够满足精度要求,其读取温度值完全可以满足电动汽车电池温度采集需要。
将上述软件设计思想通过编程语言实现后,系统不但能在上电时对温度传感器数目进行准确辨识,而且可以在测量值超过温度限值时及时提供温度告警,并且鉴于双单总线的设计,即使在一条总线脱离控制器的情况下,系统依然能够提供基于6组测量数据的温度平均值,这为电动汽车的热管理提供了很好的保障。
4结束语
温度是电池管理系统延长电池使用寿命和进行准确SOC预测等工作的重要指标之一,应用DS18B20对温度采集系统进行合理的组网设计,可以较准确地测量得到蓄电池组各单体的温度值,并具有一定的抗干扰能力和可靠工作的能力,很好地满足了电池管理系统温度参数采集的需要。 

ZT,留着以后看:lol

benzking 发表于 2012-12-4 17:51:28

能再写得易懂些么,程序加点注释和再多点讲解吧

muggle 发表于 2012-12-4 19:52:01

benzking 发表于 2012-12-4 17:51 static/image/common/back.gif
能再写得易懂些么,程序加点注释和再多点讲解吧

这就是<OneWire.h>和 <DallasTemperature.h>两个库文件配合使用的例程,没什么可讲的,结构也很简单。我用它是来测试手里的DS18B20是否正常工作,以及得到将来编程使用的地址内码。

有什么具体问题,可以提出来,大家一起研究分享。:)

星夜幻 发表于 2012-12-5 10:54:18

搜索oneWare总线,google直接给了本帖…………,还以为有很多资料呢……

muggle 发表于 2012-12-5 22:59:14

星夜幻 发表于 2012-12-5 10:54 static/image/common/back.gif
搜索oneWare总线,google直接给了本帖…………,还以为有很多资料呢……

这只是一点点经验分享,不是很全面,抱歉

详细可以看弘毅的教学贴
http://www.geek-workshop.com/forum.php?mod=viewthread&tid=198

星夜幻 发表于 2012-12-6 08:21:52

muggle 发表于 2012-12-5 22:59 static/image/common/back.gif
这只是一点点经验分享,不是很全面,抱歉

详细可以看弘毅的教学贴


我嘎嘎,楼主已经很强悍啦,我的意思是,想多了解些,结果找到的资料还不如直接看贴子……呵呵

zintiger 发表于 2012-12-15 22:01:24

弱弱地问一下,每个传感器都是有唯一的地址码?与生俱来的?
页: [1] 2 3
查看完整版本: 麻瓜学习笔记:02_OneWare总线多个DS18B20数据读取