ESP32 и датчик температуры DS18B20 в Arduino IDE (один датчик, несколько датчиков, веб-сервер)
Это подробное руководство по датчику температуры DS18B20 с ESP32 в Arduino IDE. Мы покажем вам, как подключить датчик, установить необходимые библиотеки и написать код для получения показаний с одного и нескольких датчиков. В конце мы создадим простой веб-сервер для отображения показаний датчика.
Вам также могут быть полезны другие руководства по DS18B20:
Знакомство с датчиком температуры DS18B20
Датчик температуры DS18B20 - это цифровой датчик температуры с однопроводным интерфейсом (one-wire). Это означает, что для связи с ESP32 ему требуется только одна линия данных (и GND).
Он может питаться от внешнего источника питания или получать питание от линии данных (так называемый «паразитный режим»), что устраняет необходимость во внешнем источнике питания.
Каждый датчик температуры DS18B20 имеет уникальный 64-битный серийный код. Это позволяет подключить несколько датчиков к одной линии данных. Таким образом, вы можете получать температуру с нескольких датчиков, используя всего один GPIO.
Датчик температуры DS18B20 также доступен в водонепроницаемом исполнении.
Вот краткое описание наиболее важных характеристик датчика температуры DS18B20:
Связь по однопроводной шине (one-wire bus)
Диапазон напряжения питания: от 3,0 В до 5,5 В
Диапазон рабочих температур: от -55°C до +125°C
Точность +/-0,5°C (в диапазоне от -10°C до 85°C)
Для получения дополнительной информации обратитесь к даташиту DS18B20.
Необходимые компоненты
Для выполнения этого руководства вам понадобятся следующие компоненты:
ESP32 (ознакомьтесь с лучшими платами разработки ESP32)
Датчик температуры DS18B20 (один или несколько датчиков) – водонепроницаемая версия
Вы можете использовать приведенные выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Схема подключения – ESP32
Как упоминалось ранее, датчик температуры DS18B20 может питаться через вывод VDD (нормальный режим) или получать питание от линии данных (паразитный режим). Вы можете выбрать любой режим.
Если вы используете ESP32, следуйте одной из этих двух схем подключения.
Паразитный режим
Нормальный режим
Подготовка Arduino IDE
Мы будем программировать ESP32 с помощью Arduino IDE, поэтому убедитесь, что у вас установлено дополнение для ESP32, прежде чем продолжить:
Установка библиотек
Для работы с датчиком температуры DS18B20 вам необходимо установить библиотеку OneWire от Paul Stoffregen и библиотеку Dallas Temperature. Выполните следующие шаги для установки этих библиотек.
Откройте Arduino IDE и перейдите в Sketch > Include Library > Manage Libraries. Должен открыться менеджер библиотек.
Введите «onewire» в поле поиска и установите библиотеку OneWire от Paul Stoffregen.
Затем найдите «Dallas» и установите библиотеку DallasTemperature от Miles Burton.
После установки библиотек перезапустите Arduino IDE.
Код (один DS18B20)
После установки необходимых библиотек вы можете загрузить код в ESP32. Следующий код считывает температуру с датчика DS18B20 и отображает показания в мониторе порта Arduino IDE.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com
*********/
#include <OneWire.h>
#include <DallasTemperature.h>
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
void setup() {
// Start the Serial Monitor
Serial.begin(115200);
// Start the DS18B20 sensor
sensors.begin();
}
void loop() {
sensors.requestTemperatures();
float temperatureC = sensors.getTempCByIndex(0);
float temperatureF = sensors.getTempFByIndex(0);
Serial.print(temperatureC);
Serial.println("ºC");
Serial.print(temperatureF);
Serial.println("ºF");
delay(5000);
}
Существует множество различных способов получения температуры с датчиков DS18B20. Однако если вы используете только один датчик, это один из самых простых и удобных способов.
Как работает код
Начните с подключения библиотек OneWire и DallasTemperature.
#include <OneWire.h>
#include <DallasTemperature.h>
Создайте экземпляры, необходимые для датчика температуры. Датчик температуры подключен к GPIO 4.
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
В функции setup() инициализируйте монитор порта на скорости 115200 бод.
Serial.begin(115200);
Инициализируйте датчик температуры DS18B20:
sensors.begin();
Перед получением температуры необходимо вызвать метод requestTemperatures().
sensors.requestTemperatures();
Затем получите температуру в градусах Цельсия с помощью метода getTempCByIndex(), как показано ниже:
float temperatureC = sensors.getTempCByIndex(0);
Или используйте getTempFByIndex() для получения температуры в градусах Фаренгейта.
float temperatureF = sensors.getTempFByIndex(0);
Методы getTempCByIndex() и getTempFByIndex() принимают индекс датчика температуры. Поскольку мы используем только один датчик, его индекс равен 0. Если вы хотите считывать данные с нескольких датчиков, используйте индекс 0 для одного датчика, индекс 1 для другого и так далее.
Наконец, выведите результаты в монитор порта.
Serial.print(temperatureC);
Serial.println("ºC");
Serial.print(temperatureF);
Serial.println("ºF");
Новые показания температуры запрашиваются каждые 5 секунд.
delay(5000);
Демонстрация
После загрузки кода вы должны увидеть показания датчика в мониторе порта:
Получение температуры с нескольких датчиков DS18B20
Датчик температуры DS18B20 использует протокол связи one-wire, и каждый датчик имеет уникальный 64-битный серийный код, поэтому вы можете считывать температуру с нескольких датчиков, используя всего один GPIO. Вам нужно просто соединить все линии данных вместе, как показано на следующей схеме:
Код (несколько DS18B20)
Затем загрузите следующий код. Он сканирует все устройства на GPIO 4 и выводит температуру для каждого из них. (Этот скетч основан на примере из библиотеки DallasTemperature).
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com
*********/
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged TO GPIO 4
#define ONE_WIRE_BUS 4
// 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);
// Number of temperature devices found
int numberOfDevices;
// We'll use this variable to store a found device address
DeviceAddress tempDeviceAddress;
void setup(){
// start serial port
Serial.begin(115200);
// 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.");
// 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();
} else {
Serial.print("Found ghost device at ");
Serial.print(i, DEC);
Serial.print(" but could not detect address. Check power and cabling");
}
}
}
void loop(){
sensors.requestTemperatures(); // Send the command to get temperatures
// 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);
// Print the data
float tempC = sensors.getTempC(tempDeviceAddress);
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
}
delay(5000);
}
// function to print a device address
void printAddress(DeviceAddress deviceAddress) {
for (uint8_t i = 0; i < 8; i++){
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
Демонстрация
В этом примере мы используем три датчика температуры DS18B20. Вот что мы получаем в мониторе порта Arduino IDE.
У нас есть отдельная статья о том, как подключить несколько датчиков температуры DS18B20 к ESP32. Просто перейдите к следующему руководству:
Отображение показаний температуры DS18B20 на веб-сервере
Для создания веб-сервера мы используем библиотеку ESPAsyncWebServer, которая предоставляет удобный способ создания асинхронного веб-сервера. Создание асинхронного веб-сервера имеет ряд преимуществ. Мы рекомендуем кратко ознакомиться с документацией библиотеки на её странице GitHub.
Установка библиотек ESPAsyncWebServer и AsyncTCP
Для создания веб-сервера в рамках данного проекта вам необходимо установить следующие библиотеки в Arduino IDE.
ESPAsyncWebServer от ESP32Async
AsyncTCP от ESP32Async
Вы можете установить эти библиотеки через менеджер библиотек Arduino IDE. Перейдите в Sketch > Include Library > Manage Libraries и найдите названия библиотек.
Код (асинхронный веб-сервер DS18B20)
Откройте Arduino IDE и скопируйте следующий код.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com
*********/
// Import required libraries
#ifdef ESP32
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#else
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#endif
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is connected to GPIO 4
#define ONE_WIRE_BUS 4
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// Variables to store temperature values
String temperatureF = "";
String temperatureC = "";
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String readDSTemperatureC() {
// Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
if(tempC == -127.00) {
Serial.println("Failed to read from DS18B20 sensor");
return "--";
} else {
Serial.print("Temperature Celsius: ");
Serial.println(tempC);
}
return String(tempC);
}
String readDSTemperatureF() {
// Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
sensors.requestTemperatures();
float tempF = sensors.getTempFByIndex(0);
if(int(tempF) == -196){
Serial.println("Failed to read from DS18B20 sensor");
return "--";
} else {
Serial.print("Temperature Fahrenheit: ");
Serial.println(tempF);
}
return String(tempF);
}
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.ds-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP DS18B20 Server</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="ds-labels">Temperature Celsius</span>
<span id="temperaturec">%TEMPERATUREC%</span>
<sup class="units">°C</sup>
</p>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="ds-labels">Temperature Fahrenheit</span>
<span id="temperaturef">%TEMPERATUREF%</span>
<sup class="units">°F</sup>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperaturec").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperaturec", true);
xhttp.send();
}, 10000) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperaturef").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperaturef", true);
xhttp.send();
}, 10000) ;
</script>
</html>)rawliteral";
// Replaces placeholder with DS18B20 values
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATUREC"){
return temperatureC;
}
else if(var == "TEMPERATUREF"){
return temperatureF;
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
Serial.println();
// Start up the DS18B20 library
sensors.begin();
temperatureC = readDSTemperatureC();
temperatureF = readDSTemperatureF();
// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
// Print ESP Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html, processor);
});
server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", temperatureC.c_str());
});
server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", temperatureF.c_str());
});
// Start server
server.begin();
}
void loop(){
if ((millis() - lastTime) > timerDelay) {
temperatureC = readDSTemperatureC();
temperatureF = readDSTemperatureF();
lastTime = millis();
}
}
Вставьте свои сетевые учетные данные в следующие переменные, и код заработает сразу.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Как работает код
В следующих абзацах мы объясним, как работает код. Продолжайте чтение, если хотите узнать больше, или перейдите к разделу «Демонстрация», чтобы увидеть конечный результат.
Импорт библиотек
Сначала импортируйте необходимые библиотеки для платы ESP32:
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
Создание экземпляра датчика DS18B20
Определите GPIO, к которому подключен вывод данных DS18B20. В данном случае он подключен к GPIO 4.
#define ONE_WIRE_BUS 4
Создайте экземпляры, необходимые для инициализации датчика:
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
Настройка сетевых учетных данных
Вставьте свои сетевые учетные данные в следующие переменные, чтобы ESP32 мог подключиться к вашей локальной сети.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Создайте объект AsyncWebServer на порту 80.
AsyncWebServer server(80);
Функции чтения температуры
Затем мы создаем две функции для чтения температуры.
Функция readDSTemperatureC() возвращает показания в градусах Цельсия.
String readDSTemperatureC() {
// Call sensors.requestTemperatures() to issue a global temperature and Requests to all devices on the bus
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
if(tempC == -127.00){
Serial.println("Failed to read from DS18B20 sensor");
return "--";
} else {
Serial.print("Temperature Celsius: ");
Serial.println(tempC);
}
return String(tempC);
}
Если датчик не может получить корректное показание, он возвращает -127. Поэтому у нас есть условие if, которое возвращает два тире (–) в случае, если датчик не может получить показания.
if(tempC == -127.00){
Serial.println("Failed to read from DS18B20 sensor");
return "--";
Функция readDSTemperatureF() работает аналогичным образом, но возвращает показания в градусах Фаренгейта.
Показания возвращаются в виде строкового типа. Для преобразования float в строку используется функция String().
return String(tempC);
Создание веб-страницы
Следующий шаг – создание веб-страницы. HTML и CSS, необходимые для создания веб-страницы, сохраняются в переменной index_html.
В HTML-тексте мы имеем TEMPERATUREC и TEMPERATUREF между знаками %. Это заполнитель (placeholder) для значений температуры.
Это означает, что текст %TEMPERATUREC% является чем-то вроде переменной, которая будет заменена фактическим значением температуры от датчика. Заполнители в HTML-тексте должны быть помещены между знаками %.
Мы подробно объяснили, как работают HTML и CSS, используемые в этом веб-сервере, в предыдущем руководстве. Если вы хотите узнать больше, обратитесь к следующему проекту:
Процессор
Теперь нам нужно создать функцию processor(), которая заменит заполнители в нашем HTML-тексте фактическими значениями температуры.
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATUREC"){
return readDSTemperatureC();
}
else if(var == "TEMPERATUREF"){
return readDSTemperatureF();
}
return String();
}
Когда запрашивается веб-страница, мы проверяем, есть ли в HTML какие-либо заполнители. Если находится заполнитель %TEMPERATUREC%, мы возвращаем температуру в градусах Цельсия, вызывая созданную ранее функцию readDSTemperatureC().
if(var == "TEMPERATUREC"){
return readDSTemperatureC();
}
Если заполнитель – %TEMPERATUREF%, мы возвращаем температуру в градусах Фаренгейта.
else if(var == "TEMPERATUREF"){
return readDSTemperatureF();
}
Функция setup()
В функции setup() инициализируйте монитор порта для целей отладки.
Serial.begin(115200);
Инициализируйте датчик температуры DS18B20.
sensors.begin();
Подключитесь к локальной сети и выведите IP-адрес ESP32.
WiFi.begin(ssid, password);
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
// Print ESP8266 Local IP Address
Serial.println(WiFi.localIP());
Наконец, добавьте следующие строки кода для обработки запросов веб-сервера.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDSTemperatureC().c_str());
});
server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDSTemperatureF().c_str());
});
Когда мы делаем запрос к корневому URL, мы отправляем HTML-текст, хранящийся в переменной index_html. Нам также нужно передать функцию processor, которая заменит все заполнители правильными значениями.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
Нам нужно добавить два дополнительных обработчика для обновления показаний температуры. Когда мы получаем запрос на URL /temperaturec, нам нужно просто отправить обновленное значение температуры. Это обычный текст, и он должен быть отправлен как char, поэтому мы используем метод c_str().
server.on("/temperaturec", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDSTemperatureC().c_str());
});
Тот же процесс повторяется для температуры в градусах Фаренгейта.
server.on("/temperaturef", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDSTemperatureF().c_str());
});
Наконец, мы можем запустить сервер.
server.begin();
Поскольку это асинхронный веб-сервер, нам не нужно писать ничего в функции loop().
void loop(){
}
Вот примерно так и работает этот код.
Демонстрация
После загрузки кода откройте монитор порта Arduino IDE на скорости 115200 бод. Нажмите кнопку RST на плате ESP32, и через несколько секунд должен отобразиться ваш IP-адрес.
В вашей локальной сети откройте браузер и введите IP-адрес ESP32.
Теперь вы можете видеть температуру в градусах Цельсия и Фаренгейта на вашем веб-сервере. Показания датчика обновляются автоматически без необходимости обновления веб-страницы.
Заключение
Мы надеемся, что это руководство было для вас полезным. У нас есть руководства для других датчиков и модулей с ESP32, которые могут вам понравиться:
Если вы хотите узнать больше о ESP32, ознакомьтесь с нашим курсом или бесплатными ресурсами по ESP32:
Спасибо за чтение.
Источник: ESP32 DS18B20 Temperature Sensor with Arduino IDE (Single, Multiple, Web Server)