ESP8266 NodeMCU с датчиком BMP388 – барометр/альтиметр (Arduino IDE)

BMP388 – это крошечный и точный абсолютный барометрический датчик давления. Благодаря своей точности он часто используется для оценки высоты в приложениях для дронов. Он также может использоваться для навигации в помещении/на улице, GPS-приложений и других задач. В этом руководстве вы узнаете, как использовать датчик давления BMP388 с платой Arduino – мы покажем схему подключения и пример кода.

ESP8266 NodeMCU с датчиком BMP388 барометр альтиметр Arduino IDE

В этом руководстве мы рассмотрим:

У нас есть похожее руководство для платы ESP32: :doc:`ESP32 с датчиком BMP388 барометр/альтиметр (Arduino) </esp32/rnt/esp32-bmp388-arduino/index>`_

Знакомство с барометрическим датчиком BMP388

BMP388 – это точный, маломощный, малошумящий абсолютный барометрический датчик давления, который измеряет абсолютное давление и температуру. Поскольку давление изменяется с высотой, мы также можем оценить высоту с высокой точностью. По этой причине этот датчик удобен для приложений дронов и навигации. Вы также можете использовать его для других приложений:

  • расчёт вертикальной скорости;

  • интернет вещей;

  • прогноз погоды и метеостанции;

  • медицинские приложения;

  • фитнес-приложения;

  • и другие…

Мы используем датчик BMP388 в виде модуля, как показано на рисунке ниже. Он также доступен в других форматах.

Передняя сторона модуля датчика BMP388 - высота, давление, температура

На следующем рисунке показана другая сторона датчика.

Задняя сторона модуля датчика BMP388 - высота, давление, температура

Технические характеристики BMP388

В следующей таблице показаны основные характеристики датчика BMP388. Для получения дополнительной информации обратитесь к даташиту.

Диапазон работы

300–1250 гПа (давление), -40…+85 °C (температура)

Интерфейс

I2C и SPI

Средний типичный ток потребления

3,4 мкА при 1 Гц

Абсолютная точность давления (тип.), P=900…1100 гПа (T=25…40 °C)

±0,5 гПа

Относительная точность давления (тип.), P=900…1100 гПа (T=25…40 °C)

±0,08 гПа

Шум давления (наименьшая полоса пропускания, наивысшее разрешение)

0,03 Па

Максимальная частота дискретизации

200 Гц

Распиновка BMP388

Вот распиновка модуля BMP388, который мы используем – она может немного отличаться для других модулей.

VIN

Питание датчика (5 В)

3V3

Питание датчика (3,3 В)

GND

Общий GND

SCK

Вывод SCL для I2C-связи; вывод SCK для SPI-связи

SDO

Вывод SDO (MISO) для SPI-связи

SDI

Вывод SDI (MOSI) для SPI-связи; вывод SDA для I2C-связи

CS

Вывод выбора чипа (Chip Select) для SPI-связи

INT

Вывод прерывания

Интерфейс BMP388

Как упоминалось ранее, датчик BMP388 поддерживает интерфейсы I2C и SPI.

ESP8266 NodeMCU датчик BMP388 высота давление температура Arduino

BMP388 I2C

Для использования протокола связи I2C используйте следующие выводы:

BMP388

ESP8266

SDI (SDA)

GPIO 4 (D2)

SCK (SCL)

GPIO 5 (D1)

BMP388 SPI

Для использования протокола связи SPI используйте следующие выводы:

BMP388

ESP8266

SCK

GPIO 14 (D5)

SDI (MOSI)

GPIO 13 (D7)

SDO (MISO)

GPIO 12 (D6)

CS (Chip Select)

GPIO 15 (D8)

Необходимые компоненты

ESP8266 NodeMCU модуль датчика BMP388 высота давление температура

Для выполнения этого руководства вам понадобятся следующие компоненты:

Вы можете использовать ссылки выше или перейти напрямую на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!

Схема – ESP8266 NodeMCU с BMP388

BMP388 может обмениваться данными по протоколам связи I2C или SPI.

ESP8266 с BMP388 через I2C

Следуйте следующей схеме подключения, чтобы подключить BMP388 к ESP8266 с использованием выводов I2C по умолчанию.

Схема подключения ESP8266 BMP388 I2C с Arduino

ESP8266 с BMP388 через SPI

В качестве альтернативы вы можете захотеть использовать протокол связи SPI. В этом случае следуйте следующей схеме подключения, чтобы подключить BMP388 к ESP8266 с использованием выводов SPI по умолчанию.

Схема подключения ESP8266 BMP388 SPI с Arduino

Подготовка Arduino IDE

Мы будем программировать плату ESP8266 с помощью Arduino IDE. Поэтому убедитесь, что у вас установлено дополнение ESP8266. Следуйте следующему руководству:

Если вы хотите использовать VS Code с расширением PlatformIO, следуйте следующему руководству, чтобы узнать, как программировать ESP8266:

Установка библиотеки Adafruit BMP3XX

Существуют различные библиотеки, совместимые с датчиком BMP388 и ESP8266. В этом руководстве мы будем использовать библиотеку Adafruit BMP3XX.

Следуйте следующим шагам для установки библиотеки в вашу Arduino IDE:

Откройте Arduino IDE и перейдите в Sketch > Include Library > Manage Libraries. Должен открыться менеджер библиотек.

Найдите «adafruit bmp3xx» в поле поиска и установите библиотеку.

Установка библиотеки Adafruit bmp3xx в Arduino IDE

Установка библиотеки Adafruit_Sensor

Для использования библиотеки BMP3XX вам также нужно установить библиотеку Adafruit_Sensor. Следуйте следующим шагам для установки библиотеки в вашу Arduino IDE:

Перейдите в Sketch > Include Library > Manage Libraries и введите «Adafruit Unified Sensor» в поле поиска. Прокрутите вниз, чтобы найти библиотеку, и установите её.

Установка библиотеки Adafruit Unified Sensor Driver

После установки библиотек перезапустите Arduino IDE.

Код – чтение давления, высоты и температуры BMP388

Лучший способ познакомиться с новым датчиком – начать с базового примера, предоставленного библиотекой.

После установки библиотеки BMP3XX откройте Arduino IDE и перейдите в File > Examples > Adafruit BMP3XX Library > bmp3XX_simpletest. Мы внесли несколько изменений, чтобы сделать его полностью совместимым с ESP8266.

/***************************************************************************
  This is a library for the BMP3XX temperature & pressure sensor. Designed
  specifically to work with the Adafruit BMP388 Breakout
  ----> http://www.adafruit.com/products/3966
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. Adafruit invests time and resources providing this open
  source code, please support Adafruit and open-source hardware by
  purchasing products from Adafruit!
  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/

// Complete project details: https://RandomNerdTutorials.com/esp8266-nodemcu-bmp388-arduino/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"

#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BMP3XX bmp;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println("Adafruit BMP388 / BMP390 test");

  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
  //if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode
  //if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode
    Serial.println("Could not find a valid BMP3 sensor, check wiring!");
    while (1);
  }

  // Set up oversampling and filter initialization
  bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
  bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
  bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
  bmp.setOutputDataRate(BMP3_ODR_50_HZ);
}

void loop() {
  if (! bmp.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }
  Serial.print("Temperature = ");
  Serial.print(bmp.temperature);
  Serial.println(" *C");

  Serial.print("Pressure = ");
  Serial.print(bmp.pressure / 100.0);
  Serial.println(" hPa");

  Serial.print("Approx. Altitude = ");
  Serial.print(bmp.readAltitude(SEALEVELPRESSURE_HPA));
  Serial.println(" m");

  Serial.println();
  delay(2000);
}

Просмотреть исходный код

Давление на уровне моря

Для получения более точных результатов давления и высоты мы рекомендуем настроить давление на уровне моря для вашего местоположения в переменной SEALEVELPRESSURE_HPA:

#define SEALEVELPRESSURE_HPA (1013.25)

Стандартное значение составляет 1013,25 гПа. Для получения более точных результатов проверьте давление на уровне моря в вашем местоположении. Вы можете использовать этот сайт для проверки давления на уровне моря.

Как работает код

Продолжайте читать этот раздел, чтобы узнать, как работает код, или перейдите к разделу Демонстрация.

Библиотеки

Код начинается с подключения необходимых библиотек: библиотека Wire для использования I2C, библиотека SPI (если вы хотите использовать SPI вместо I2C), Adafruit_Sensor и Adafruit_BMP3XX для взаимодействия с датчиком BMP388.

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_BMP3XX.h"

SPI-связь

Мы предпочитаем использовать протокол связи I2C с датчиком. Однако код подготовлен на случай, если вы хотите использовать SPI. Следующие строки кода определяют выводы SPI.

#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15

Давление на уровне моря

Создаётся переменная SEALEVELPRESSURE_HPA.

#define SEALEVELPRESSURE_HPA (1013.25)

Эта переменная сохраняет давление на уровне моря в гектопаскалях (эквивалентно миллибарам). Эта переменная используется для оценки высоты при заданном давлении путём сравнения его с давлением на уровне моря. В этом примере используется значение по умолчанию, но для точных результатов замените значение текущим давлением на уровне моря в вашем местоположении. Вы можете использовать этот сайт для проверки давления на уровне моря.

setup()

В setup() запускается последовательная связь.

Serial.begin(115200);

Инициализация датчика BMP388 I2C

В этом примере по умолчанию используется протокол связи I2C. Следующая строка запускает объект Adafruit_BMP3XX с именем bmp на выводах I2C ESP8266 по умолчанию: GPIO 5 (SCL), GPIO 4 (SDA).

if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire

Для использования SPI вам нужно закомментировать эту предыдущую строку и раскомментировать одну из следующих строк для аппаратного SPI (использование выводов SPI по умолчанию и выбор вывода CS) или программного SPI (использование любых выводов).

//if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode
//if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode

Настройте следующие параметры (передискретизация и фильтр) для датчика.

// Set up oversampling and filter initialization
bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
bmp.setOutputDataRate(BMP3_ODR_50_HZ);

Для увеличения разрешения необработанных данных датчика он поддерживает передискретизацию. Мы будем использовать параметры передискретизации по умолчанию, но вы можете их изменить.

  • setTemperatureOversampling(): установка передискретизации температуры.

  • setPressureOversampling(): установка передискретизации давления.

Эти методы могут принимать один из следующих параметров:

  • BMP3_NO_OVERSAMPLING

  • BMP3_OVERSAMPLING_2X

  • BMP3_OVERSAMPLING_4X

  • BMP3_OVERSAMPLING_8X

  • BMP3_OVERSAMPLING_16X

  • BMP3_OVERSAMPLING_32X

Функция setIIRFilterCoeff() устанавливает коэффициент фильтра (в отсчётах). Он может быть:

  • BMP3_IIR_FILTER_DISABLE (без фильтрации)

  • BMP3_IIR_FILTER_COEFF_1

  • BMP3_IIR_FILTER_COEFF_3

  • BMP3_IIR_FILTER_COEFF_7

  • BMP3_IIR_FILTER_COEFF_15

  • BMP3_IIR_FILTER_COEFF_31

  • BMP3_IIR_FILTER_COEFF_63

  • BMP3_IIR_FILTER_COEFF_127

Установите частоту выходных данных с помощью функции setOutputDataRate(). Она может принимать одну из следующих опций:

BMP3_ODR_200_HZ, BMP3_ODR_100_HZ, BMP3_ODR_50_HZ, BMP3_ODR_25_HZ, BMP3_ODR_12_5_HZ, BMP3_ODR_6_25_HZ, BMP3_ODR_3_1_HZ, BMP3_ODR_1_5_HZ, BMP3_ODR_0_78_HZ, BMP3_ODR_0_39_HZ, BMP3_ODR_0_2_HZ, BMP3_ODR_0_1_HZ, BMP3_ODR_0_05_HZ, BMP3_ODR_0_02_HZ, BMP3_ODR_0_01_HZ, BMP3_ODR_0_006_HZ, BMP3_ODR_0_003_HZ или BMP3_ODR_0_001_HZ

loop()

В loop() мы получим измерения от датчика BMP388.

Сначала сообщите датчику о необходимости получить новые показания с помощью bmp.performReading().

if (! bmp.performReading()) {
  Serial.println("Failed to perform reading :(");
  return;
}

Затем получите и выведите показания температуры, давления и высоты следующим образом:

Serial.print("Temperature = ");
Serial.print(bmp.temperature);
Serial.println(" *C");

Serial.print("Pressure = ");
Serial.print(bmp.pressure / 100.0);
Serial.println(" hPa");

Serial.print("Approx. Altitude = ");
Serial.print(bmp.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");

Вы получаете каждое конкретное показание следующим образом:

  • bmp.temperature: возвращает показание температуры

  • bmp.pressure: возвращает показание давления

  • bmp.readAltitude(SEALEVELPRESSURE_HPA): возвращает оценку высоты

Демонстрация

После ввода давления на уровне моря для вашего местоположения вы можете загрузить код на вашу плату. В Arduino IDE перейдите в Tools > Boards и выберите вашу плату. Затем в Tools > Port выберите COM-порт.

После загрузки откройте Serial Monitor на скорости 115200 бод. Показания будут выведены в Serial Monitor.

BMP388 высота давление отображение Serial Monitor

Обратите внимание, что если вы увеличите высоту датчика, это отразится в показании высоты. Оценка высоты довольно точная. Она может обнаруживать небольшие изменения в диапазоне сантиметров или дюймов. Вы можете проверить это, сравнив получаемую высоту с высотой вашего местоположения. Чтобы узнать высоту вашего местоположения, вы можете использовать этот сайт.


Веб-сервер ESP8266 NodeMCU с BMP388

В этом разделе мы приводим пример веб-сервера, который вы можете создать с ESP8266 для отображения показаний BMP388 на веб-странице.

ESP8266 NodeMCU датчик BMP388 высота давление температура Arduino веб-сервер

Установка библиотек – Async Web Server

Для создания веб-сервера вам необходимо установить следующие библиотеки. Нажмите на ссылки ниже, чтобы скачать библиотеки.

Эти библиотеки недоступны для установки через менеджер библиотек Arduino, поэтому вам нужно скопировать файлы библиотек в папку библиотек Arduino. В качестве альтернативы, в Arduino IDE вы можете перейти в Sketch > Include Library > Add .zip Library и выбрать только что скачанные библиотеки.

Код

Затем загрузите следующий код на вашу плату (введите ваш SSID и пароль).

/*********
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-bmp388-arduino/
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP3XX.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

//Uncomment if using SPI
/*#define BMP_SCK 14
#define BMP_MISO 12
#define BMP_MOSI 13
#define BMP_CS 15*/

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BMP3XX bmp;

float temp;
float pres;
float alt;

AsyncWebServer server(80);
AsyncEventSource events("/events");

unsigned long lastTime = 0;
unsigned long timerDelay = 30000;  // send readings timer

void getBMPReadings(){
  if (! bmp.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }
  temp = bmp.temperature;
  pres = bmp.pressure / 100.0;
  alt = bmp.readAltitude(SEALEVELPRESSURE_HPA);
}

String processor(const String& var){
  getBMPReadings();
  //Serial.println(var);
  if(var == "TEMPERATURE"){
    return String(temp);
  }
  else if(var == "PRESSURE"){
    return String(pres);
  }
 else if(var == "ALTITUDE"){
    return String(alt);
  }
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>BMP388 Web Server</title>
  <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">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p {  font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #0F7173; color: white; font-size: 1.4rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
    .reading { font-size: 2rem; }
    .card.temperature { color: #272932; }
    .card.altitude { color: #D8A47F; }
    .card.pressure { color: #F05D5E; }
  </style>
</head>
<body>
  <div class="topnav">
    <h3>BMP388 WEB SERVER</h3>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card pressure">
        <h4><i class="fas fa-angle-double-down"></i> PRESSURE</h4><p><span class="reading"><span id="pres">%PRESSURE%</span> hPa</span></p>
      </div>
      <div class="card altitude">
        <h4><i class="fas fa-long-arrow-alt-up"></i> ALTITUDE</h4><p><span class="reading"><span id="alt">%ALTITUDE%</span> m</span></p>
      </div>
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> TEMPERATURE</h4><p><span class="reading"><span id="temp">%TEMPERATURE%</span> &deg;C</span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');

 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);

 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);

 source.addEventListener('temperature', function(e) {
  console.log("temperature", e.data);
  document.getElementById("temp").textContent = e.data;
 }, false);

 source.addEventListener('pressure', function(e) {
  console.log("pressure", e.data);
  document.getElementById("pres").textContent = e.data;
 }, false);

 source.addEventListener('altitude', function(e) {
  console.log("altitude", e.data);
  document.getElementById("alt").textContent = e.data;
 }, false);
}
</script>
</body>
</html>)rawliteral";

void setup() {
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);

  // Set device as a Wi-Fi Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Setting as a Wi-Fi Station..");
  }
  Serial.print("Station IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  // Init BMEP388 sensor
  if (!bmp.begin_I2C()) {   // hardware I2C mode, can pass in address & alt Wire
  //if (! bmp.begin_SPI(BMP_CS)) {  // hardware SPI mode
  //if (! bmp.begin_SPI(BMP_CS, BMP_SCK, BMP_MISO, BMP_MOSI)) {  // software SPI mode
    Serial.println("Could not find a valid BMP3 sensor, check wiring!");
    while (1);
  }
  // Set up oversampling and filter initialization
  bmp.setTemperatureOversampling(BMP3_OVERSAMPLING_8X);
  bmp.setPressureOversampling(BMP3_OVERSAMPLING_4X);
  bmp.setIIRFilterCoeff(BMP3_IIR_FILTER_COEFF_3);
  bmp.setOutputDataRate(BMP3_ODR_50_HZ);

  //Get readings when initializing
  getBMPReadings();

  // Handle Web Server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", index_html, processor);
  });

  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    getBMPReadings();
    Serial.printf("Pressure = %.2f hPa \n", pres);
    Serial.printf("Altitude = %.2f m \n", alt);
    Serial.printf("Temperature = %.2f ºC \n", temp);
    Serial.println();

    // Send Events to the Web Server with the Sensor Readings
    events.send("ping",NULL,millis());
    events.send(String(pres).c_str(),"pressure",millis());
    events.send(String(alt).c_str(),"altitude",millis());
    events.send(String(temp).c_str(),"temperature",millis());

    lastTime = millis();
  }
}

Просмотреть исходный код

Демонстрация

После загрузки откройте Serial Monitor на скорости 115200 бод, чтобы получить IP-адрес ESP8266.

Откройте браузер и введите IP-адрес. Вы должны получить доступ к веб-серверу с последними показаниями датчика. Вы можете получить доступ к веб-серверу с вашего компьютера, планшета или смартфона в вашей локальной сети.

Простой веб-сервер ESP8266 NodeMCU BMP388 альтиметр

Показания обновляются автоматически на веб-сервере с помощью Server-Sent Events. Вы можете ознакомиться с :doc:`руководством по Server-Sent Events </esp32/rnt/esp8266-nodemcu-web-server-sent-events-sse/index>`_, чтобы узнать, как это работает.

Заключение

BMP388 – это маленький и очень точный датчик давления, который позволяет оценивать высоту с большой точностью. Датчик также измеряет температуру. Он отлично подходит для навигации на открытом воздухе/в помещении, дронов, метеостанций и других приложений.

В этом руководстве вы узнали, как использовать датчик с платой разработки ESP8266 и Arduino IDE. Мы надеемся, что это руководство по началу работы было полезным. Кроме того, у нас есть руководства для других популярных датчиков:

Узнайте больше о ESP8266 с помощью наших ресурсов:

Спасибо за чтение.