目的
DS18B20是常用的温度传感器,功能够用、使用简单,本文将用Arduino第三方的库来驱动DS18B20获取温度值。
DS18B20元件官方链接如下:
https://www.maximintegrated.com/cn/products/sensors/DS18B20.html
快速使用
相关库引入
两个库均在GitHub上,可以在release标签页中下载最新项目文件。
- OneWire库
项目地址:https://github.com/PaulStoffregen/OneWire
使用时需要包含OneWire.h 文件
、OneWire.cpp 文件
、util 文件夹
; - DallasTemperature库
项目地址:https://github.com/milesburton/Arduino-Temperature-Control-Library
使用时需要包含DallasTemperature.h 文件
、DallasTemperature.cpp 文件
;
下载两个库的zip包后在Arduino IDE中选择:项目 > 加载库 > 添加一个 .ZIP库
,两个库添加完成后就可以使用了。
如果你想将库文件都包含在自己的项目中那可以将相关文件和文件加放到项目文件夹里,然后修改DallasTemperature.h
文件头部#include <OneWire.h>
为#include "OneWire.h"
,之后在项目中使用时用""
引用DallasTemperature.h
即可,比如#include "DallasTemperature.h"
。
使用步骤
- 引入相关库;
- 声明
OneWire
和DallasTemperature
对象; - 使用
DallasTemperature
的begin
方法初始化总线; - 发送温度转换请求;
- 读取温度值;
使用演示
演示一
以下演示是最简单的使用方式,但是性能上损失较大:
// #include <OneWire.h> //可以不引入,因为DallasTemperature.h中已经引入了OneWire.h
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //1-wire数据总线连接在IO4
OneWire oneWire(ONE_WIRE_BUS); //声明
DallasTemperature sensors(&oneWire); //声明
void setup(void)
{
Serial.begin(115200);
Serial.println("");
sensors.begin(); //初始化总线
}
void loop(void)
{
Serial.println("发起温度转换");
sensors.requestTemperatures(); //向总线上所有设备发送温度转换请求,默认情况下该方法会阻塞
Serial.println("温度转换完成");
float tempC = sensors.getTempCByIndex(0); //获取索引号0的传感器摄氏温度数据
if (tempC != DEVICE_DISCONNECTED_C) //如果获取到的温度正常
{
Serial.print("当前温度是: ");
Serial.print(tempC);
Serial.println(" ℃\n");
}
delay(2000);
}
演示二
以下演示是一种非阻塞获取温度的方式,性能上消耗较少:
// #include <OneWire.h> //可以不引入,因为DallasTemperature.h中已经引入了OneWire.h
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //1-wire数据总线连接在IO4
OneWire oneWire(ONE_WIRE_BUS); //声明
DallasTemperature sensors(&oneWire); //声明
void setup(void)
{
Serial.begin(115200);
Serial.println("");
sensors.begin(); //初始化总线
sensors.setWaitForConversion(false); //设置为非阻塞模式
}
unsigned long previousMillis = 0; //毫秒时间记录
const long interval = 1000; //时间间隔
void loop(void)
{
//以下段落相当于每秒读取前次温度,并发起新一次温度转换
unsigned long currentMillis = millis(); //读取当前时间
if (currentMillis - previousMillis >= interval) //如果和前次时间大于等于时间间隔
{
previousMillis = currentMillis; //更新时间记录
float tempC = sensors.getTempCByIndex(0); //获取索引号0的传感器摄氏温度数据
if (tempC != DEVICE_DISCONNECTED_C) //如果获取到的温度正常
{
Serial.print("\n当前温度是: ");
Serial.print(tempC);
Serial.println(" ℃");
}
Serial.println("发起温度转换");
sensors.requestTemperatures(); //发起新的温度转换
}
delay(20);
Serial.print(".");
}
上图可以看到在转换温度过程中用户还可以做别的事(这里打印了".")
演示三
以下演示中展示了更多DallasTemperature库中的方法:
// #include <OneWire.h> //可以不引入,因为DallasTemperature.h中已经引入了OneWire.h
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 4 //1-wire数据总线连接在IO4
OneWire oneWire(ONE_WIRE_BUS); //声明
DallasTemperature sensors(&oneWire); //声明
DeviceAddress myDS18B20; //声明一个地址对象
void setup(void)
{
Serial.begin(115200);
Serial.println("");
sensors.begin(); //初始化总线
Serial.print("总线上DS18系列设备数量为:");
Serial.println(sensors.getDS18Count());
Serial.print("总线是否需要寄生供电(1-true; 0-false):");
Serial.println(sensors.isParasitePowerMode());
Serial.print("总线上设备数据最大分辨率为:");
Serial.println(sensors.getResolution());
sensors.setResolution(9); //设置总线上所有设备数据分辨率
sensors.getAddress(myDS18B20, 0); //获取索引号0的设备地址(设备序列号)
}
void loop(void)
{
Serial.println("\n发起温度转换");
sensors.requestTemperaturesByAddress(myDS18B20); //向总线上指定地址传感器发送温度转换请求
Serial.println("温度转换完成");
int16_t temp = sensors.getTemp(myDS18B20); //获取指定地址传感器温度数据
if (temp != DEVICE_DISCONNECTED_RAW) //如果获取到的温度正常
{
Serial.print("当前温度数据是: ");
Serial.println(temp);
Serial.print("当前摄氏是: ");
Serial.println(DallasTemperature::rawToCelsius(temp));
}
delay(5000);
}
相关库说明
OneWire库
这是用于1-Wire总线通讯的库,1-Wire总线是达拉斯半导体(已经被美信收购)推出的一种总线技术,一根线完成数据双向通讯,甚至总线上的设备还能从这条线取电。对于布线和现场施工来说这个技术蛮好的,但是这方面方便了别的地方就需要牺牲点了,具体来说1-Wire总线对通讯时间控制有些要求,通常通过程序来读写的话就需要牺牲一些性能了,因为读写过程中很多时候是阻塞的,OneWire库中可以看到很多延时存在。只用OneWire库就可以操作DS18B20了,可以参考该库的例程。
下面是OneWire库中部分方法说明(这个库不用太在意因为我们主要用的是下面那个库):
OneWire(uint8_t pin) { begin(pin); }
构造方法,指定总线接入的pin号;void begin(uint8_t pin)
初始化总线接口;uint8_t reset(void)
复位总线,如果总线上有可用设备则返回1,没有则返回0;void select(const uint8_t rom[8])
选择指定设备,rom[8]为设备序列号;void skip(void)
发送跳过指令(0xCC);void write(uint8_t v, uint8_t power = 0)
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0)
uint8_t read(void)
void read_bytes(uint8_t *buf, uint16_t count)
void write_bit(uint8_t v)
uint8_t read_bit(void)
读写相关操作;void depower(void)
停止向总线供电;void reset_search()
void target_search(uint8_t family_code)
bool search(uint8_t *newAddr, bool search_mode = true)
搜索设备相关操作;static uint8_t crc8(const uint8_t *addr, uint8_t len)
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0)
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0)
计算CRC校验;
DallasTemperature库
这个库在上面那个库之上再封装了一层,方便直接使用DS18B20等系列的温度传感器。这个库中温度转换可以设置为阻塞或非阻塞模式,阻塞模式下运行温度转换请求方法时会阻塞一段时间。这个库中访问设备可以通过设备地址(序列号)或是索引,通过索引方式访问相对会耗更多时间。
部分方法说明如下:
DallasTemperature(OneWire*)
构造函数;void begin(void)
初始化总线,获取总线上有多少OneWire设备和其中多少为DS18等系列设备;uint8_t getDS18Count(void)
返回DS18等系列设备数量;bool getAddress(uint8_t* deviceAddress, uint8_t index)
获取指定索引设备的地址到deviceAddress对象;bool isConnected(const uint8_t* deviceAddress, uint8_t* scratchPad)
返回指定地址(序列号)设备是否连接到总线,并读取设备寄存器数据到scratchPad对象;uint8_t getResolution()
返回全局设备最大分辨率;void setResolution(uint8_t newResolution)
设置所有设备数据分辨率;uint8_t getResolution(const uint8_t* deviceAddress)
返回指定地址(序列号)设备分辨率;bool setResolution(const uint8_t* deviceAddress, uint8_t newResolution, bool skipGlobalBitResolutionCalculation)
设置指定地址(序列号)设备分辨率;void setWaitForConversion(bool flag)
设置温度转换时是否阻塞,true则阻塞,默认为true;bool getWaitForConversion(void)
返回温度转换时是否阻塞;void setCheckForConversion(bool flag)
设置是否在阻塞时检查转换完成,true则检查,默认为true;bool getCheckForConversion(void)
返回是否在阻塞时检查转换完成;void requestTemperatures(void)
向总线上所有设备发送温度转换指令,阻塞模式下该方法将阻塞一定时间;
阻塞时间和全局设备最大分辨率以及是否在阻塞时检查转换完成标志有关,
分辨率影响: 9:最大94ms;10:最大188ms;11:最大375ms;其它:最大750ms;bool requestTemperaturesByAddress(const uint8_t* deviceAddress)
向总线上指定地址(序列号)设备发送温度转换指令,阻塞模式下该方法将阻塞一定时间;bool requestTemperaturesByIndex(uint8_t deviceIndex)
向总线上指定索引设备发送温度转换指令,阻塞模式下该方法将阻塞一定时间;int16_t getTemp(const uint8_t* deviceAddress)
返回指定地址(序列号)设备温度数据,数据分辨率为1/128℃,如果发生错误则返回DEVICE_DISCONNECTED_RAW(-7040,默认值);
为了兼容性考虑这里温度数据的分辨率和DS18B20有所不同,DS18B20默认分别率为1/16℃;float getTempC(const uint8_t* deviceAddress)
返回指定地址(序列号)设备摄氏温度,如果发生错误则返回DEVICE_DISCONNECTED_C(-127,默认值);float getTempF(const uint8_t* deviceAddress)
返回指定地址(序列号)设备华氏温度,如果发生错误则返回DEVICE_DISCONNECTED_F(-196.6,默认值);float getTempCByIndex(uint8_t deviceIndex)
float getTempFByIndex(uint8_t deviceIndex)
返回指定索引设备温度,如果发送错误则返回默认值;bool isParasitePowerMode(void)
返回是否需要总线寄生供电,需要则返回true;警报相关方法不在此列出,请自行查询源码
static float toFahrenheit(float)
将摄氏温度转为华氏温度;static float toCelsius(float)
将华氏温度转为摄氏温度;static float rawToCelsius(int16_t)
将原始温度转换为摄氏温度;static float rawToFahrenheit(int16_t)
将原始温度转换为华氏温度;
总结
基于OneWire和DallasTemperature库使用DS18B20主要内容就是上面这些了,更多信息可以参考美信对于1-Wire总线的引用笔记:
https://www.maximintegrated.com/cn/app-notes/index.mvp/id/126
https://www.maximintegrated.com/cn/app-notes/index.mvp/id/187