Рубрики
Проекты на ESP32

Подключение датчика BME280 к ESP32 с помощью ESP-IDF

В данной статье мы рассмотрим один из наиболее часто используемых датчиков — BME280, для получения показаний температуры, давления и влажности с помощью ESP32 и ESP-IDF. Будет кратко описано устройство датчика, его подключение к плате ESP32, а также настройка проекта в VS Code с расширением ESP-IDF для сбора данных с датчика и их отображения как на консоли, так и на OLED-дисплее SSD1306.

Про то, как подключать OLED-дисплей SSD1306 к плате ESP32 с помощью ESP-IDF, вы можете прочитать в этой статье.

Также на нашем сайте вы можете прочитать статью про подключение датчика BME280 к ESP32 с помощью Arduino IDE.

Датчик BME280

Датчик BME280 широко используется в электронных проектах для измерения температуры окружающей среды, барометрического давления и относительной влажности, где требуется низкое энергопотребление. Для передачи данных на микроконтроллер можно использовать протоколы связи I2C и SPI. Хотя датчик BME280 выпускается в различных версиях, мы будем использовать связь I2C для обмена данными с платой ESP32. Этот протокол основан на синхронной многомастерной системе, где плата ESP32 выступает в роли ведущего устройства, а датчик BME280 — в роли ведомого.

На приведенной ниже схеме показана распиновка датчика BME280, который мы будем использовать.

Как видно на приведенной выше схеме, датчик BME280 имеет четыре контакта. Два из них — это контакты питания, а два — контакты для связи по протоколу I2C.

VIN Это контакт питания, к которому подключено напряжение 3,3 В.
GND Это контакт заземления (общего провода, земли)
SCL Это контакт последовательного тактового сигнала, который будет генерировать тактовый сигнал.
SDA Этот контакт используется для отправки и приема данных.

Как видите, распиновка датчика BME280 интуитивно понятна и проста.

Контакты I2C ESP32

На приведенной ниже схеме показана распиновка ESP32, где стандартные контакты I2C выделены красным цветом. Это стандартные контакты I2C модуля ESP32 DEVKIT. Однако, если вы хотите использовать другие контакты GPIO в качестве контактов I2C, вам придется задать их в коде.

Также на нашем сайте вы можете прочитать статью про использование интерфейса I2C в ESP32 с помощью ESP-IDF.

Подключение BME280 к ESP32

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

  1. Плата ESP32.
  2. Датчик BME280.
  3. Соединительные провода.
  4. Макетная плата.

Подключение датчика BME280 к плате ESP32 достаточно простое, так как оно включает в себя лишь соединение 4 контактов (GND, VCC, SDA и SCL) с ESP32. Необходимо соединить вывод VCC с контактом 3,3 В, заземление с общим заземлением, контакт SCL датчика с контактом SCL платы ESP32, а контакт SDA датчика с контактом SDA платы ESP32.

В ESP32 по умолчанию для вывода SDA используется GPIO21, а для SCL — GPIO22.

Соединения между устройствами указаны в таблице ниже:

Датчик BME280 ESP32
GND GND
VCC 3.3V
SDA GPIO21 (I2C SDA)
SCL GPIO22 (I2C SCL)

Измерение показателей BME280 с помощью ESP32 и ESP-IDF

Мы создадим проект в VS Code с расширением ESP-IDF. Код будет считывать значения температуры, влажности и давления, используя драйвер I2C, предоставляемый ESP-IDF. Мы будем использовать библиотеку BME280, разработанную BoschSensortec.

Создание примера проекта

Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project и нажмите Enter.

Укажите название проекта и каталог. Мы назвали наш проект «BME280». Для платы ESP-IDF мы выбрали опцию custom board («пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.

В разделе «Расширение» выберите опцию ESP-IDF:

На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’) («Создать проект, используя шаблон sample_project»).

Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».

Это откроет проект, который мы создали на вкладке «Проводник». Внутри папки проекта находится несколько папок. Это справедливо для каждого проекта, который вы будете создавать с помощью ESP-IDF Explorer.

  • Для начала добавим необходимые заголовочные файлы для библиотек, требуемых для этого проекта. Создайте новую папку с именем ‘components/bme280’ и добавьте в неё следующие файлы, доступные по этой ссылке. Сюда входят все файлы, перечисленные ниже:

  • Теперь перейдите к файлу main.c. В папке main находится исходный код, то есть файл main.c будет находиться здесь. Перейдите в папку main > main.c  и откройте его. Скопируйте приведенный ниже код из этого файла и сохраните его.

Код программы ESP32 для отображения показаний с BME280

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

Для начала мы подключим необходимые библиотеки для этого проекта. Сюда входят драйвер i2c, драйвер gpio, библиотека логирования ESP, библиотека BME280 и библиотека FreeRTOS. Библиотека driver/i2c.h позволит ESP32 взаимодействовать с другими устройствами I2C, в нашем случае это датчик BME280. 

Далее мы определили контакты SCL и SDA для связи по протоколу I2C. Используйте эти контакты GPIO для соединения двух устройств. Вы также можете изменить эти контакты.

Этот код использует информационное логирование. Функция логирования принимает два аргумента. Первый аргумент — это тег, а второй — отформатированная строка. Поэтому эта глобальная переменная будет полезна при вызове функций ESP_LOGI(). Здесь «BME280» — это тег, который будет использоваться при логировании.

Инициализация ведущего устройства I2C (ESP32)

Следующая функция отвечает за инициализацию ведущего устройства I2C.

Сначала определяются параметры структуры i2c_config_t. Это включает в себя режим работы (в данном случае — ведущий), контакты связи I2C, настройку внутренних подтягивающих резисторов ESP32 и установку тактовой частоты I2C.

После установки параметров выполняется инициализация конфигурации I2C для конкретного порта. Это достигается путем вызова функции i2c_param_config(), которая принимает два параметра. Первый параметр — это порт I2C, а второй — указатель на константную структуру конфигурации типа i2c_config_t. На этом этапе выполняется настройка порта I2C.

Следующий шаг — установка драйвера I2C. Он принимает несколько параметров, перечисленных ниже:

  • Номер порта I2C.
  • Режим конфигурации, который мы устанавливаем (ведущий/ведомый)
  • Отключение буфера приема. Это размер буфера приема, применяемый к ведомому устройству.
  • Отключение буфера TX. Это размер буфера отправки, который также применяется к ведомому устройству.
  • Последний параметр — ‘intr_alloc_flags’, который задает флаги для выделенного прерывания. В нашем случае он равен ‘0’, поскольку в этом примере мы не используем прерывания.

Функции записи/чтения по шине I2C микроконтроллера BME280

Внутри функции BME280_I2C_bus_write() мы начинаем с создания и инициализации канала управления I2C с помощью функции i2c_cmd_link_create(). Эта функция вернет обработчик канала управления I2C.

После создания командной связи мы вызовем функцию i2c_master_start() и передадим ей командную связь в качестве параметра. Это позволит ведущему устройству I2C сгенерировать стартовый сигнал. Оно будет передавать все команды из очереди.

Примечание: эта функция вызывается только тогда, когда устройство выступает в роли ведущего устройства.

Затем вызывается функция i2c_master_write_byte(), которая используется для указания адреса ведомого устройства. Эта функция принимает три параметра: команду I2C link, однобайтовую команду I2C, которая будет записана в шину, и подтверждение разрешения для ведущего устройства. Здесь «(dev_addr << 1) | I2C_MASTER_WRITE» — это адрес ведомого устройства, который указывает, что ведущее устройство будет записывать данные в ведомое.

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

Затем мы вызываем функцию i2c_master_cmd_begin(), которая позволит ведущему устройству I2C начать отправку команд из очереди. Эта функция принимает три параметра. Первый параметр — номер порта I2C, второй — обработчик команд I2C, а третий — максимальное время ожидания, которое в данном случае установлено на 0,01 секунды.

После этого мы освободим канал связи, когда закончим отправку команд. Это достигается путем вызова функции i2c_cmd_link() и передачи в нее обработчика команд I2C в качестве параметра.

Внутри функции BME280_I2C_bus_read() выполняются те же шаги для создания связи и запуска шины I2C Master и записи байтов, что и в функции BME280_I2C_bus_write(). На этот раз команда, отправленная ведущим устройством для чтения данных с ведомого устройства, содержит адрес ESP_SLAVE_ADDR << 1) | I2C_MASTER_READ, который указан в качестве второго параметра в функции i2c_master_write_byte(). Однако теперь мы добавим команду в условие if, которое проверяет, если длина данных больше 1, то вызывается функция i2c_master_read() для чтения нескольких байтов по шине I2C. Она принимает четыре параметра. Первый параметр — обработчик команд I2C. Второй параметр — данные для передачи. Третий параметр — длина буфера данных в байтах. И, наконец, четвертый параметр — разрешение сигнала ACK для ведущего устройства.

Далее вызовите функцию i2c_master_read_byte() для чтения одного байта по шине I2C. При этом настройка такова, что ведущее устройство не передает бит ACK. После этого вызовите функцию i2c_master_stop(), чтобы добавить сигнал «STOP» в список заданных команд.

Затем мы вызываем функцию i2c_master_cmd_begin(), которая позволит ведущему устройству I2C начать отправку команд из очереди. После этого мы освободим канал передачи команд, когда закончим их отправку.

Чтение из BME280

Внутри функции bme280_reader_task() инициализируется датчик BME280, после чего данные с датчика непрерывно собираются и выводятся на последовательный терминал ESP-IDF.

Сначала определяются параметры структуры bme280_t. Это включает в себя запись по I2C, чтение по I2C, адрес ведомого устройства и задержку.

Объявите следующие переменные для хранения данных датчика BME280:

Инициализируйте датчик BME280, вызвав функцию bme280_init() и указав в качестве параметра указатель на структуру bme280_t.

Далее мы устанавливаем значение параметра передискретизации давления в регистре 0xF4 с битов 2 на 4, вызывая функцию bme280_set_overamp_pressure(). Эта функция принимает один параметр — значение передискретизации давления. Она может принимать любое из перечисленных ниже значений:

  • Пропущено: значение равно 0x00
  • BME280_OVERSAMP_1X: Значение равно 0x01
  • BME280_OVERSAMP_2X: Значение равно 0x02
  • BME280_OVERSAMP_4X: Значение равно 0x03
  • BME280_OVERSAMP_8X: Значение равно 0x04
  • BME280_OVERSAMP_16X: Значения равны 0x05, 0x06 и 0x07.

Аналогичным образом, мы устанавливаем значение параметра передискретизации температуры в битах регистра 0xF4 с 5 на 7, вызывая функцию bme280_set_overamp_temperature(). Эта функция принимает один параметр — значение передискретизации температуры. Она может принимать любое из перечисленных ниже значений:

  • Пропущено: значение равно 0x00
  • BME280_OVERSAMP_1X: Значение равно 0x01
  • BME280_OVERSAMP_2X: Значение равно 0x02
  • BME280_OVERSAMP_4X: Значение равно 0x03
  • BME280_OVERSAMP_8X: Значение равно 0x04
  • BME280_OVERSAMP_16X: Значения равны 0x05, 0x06 и 0x07.

Аналогичным образом, мы устанавливаем параметр передискретизации влажности в битах регистра 0xF2 с 0 на 2, вызывая функцию bme280_set_overamp_humidity(). Эта функция принимает один параметр — значение передискретизации влажности. Она может принимать любое из перечисленных ниже значений:

  • Пропущено: значение равно 0x00
  • BME280_OVERSAMP_1X
  • BME280_OVERSAMP_2X
  • BME280_OVERSAMP_4X
  • BME280_OVERSAMP_8X
  • BME280_OVERSAMP_16X

После этого мы запишем время работы в режиме ожидания с датчика в регистр 0xF5, биты 5-7, вызвав функцию bme280_set_standby_durn(). Эта функция принимает один параметр — значение времени работы в режиме ожидания. Она может принимать любое из перечисленных ниже значений:

  • BME280_STANDBY_TIME_1_MS
  • BME280_STANDBY_TIME_63_MS
  • BME280_STANDBY_TIME_125_MS
  • BME280_STANDBY_TIME_250_MS
  • BME280_STANDBY_TIME_500_MS
  • BME280_STANDBY_TIME_1000_MS
  • BME280_STANDBY_TIME_2000_MS
  • BME280_STANDBY_TIME_4000_MS

Затем мы зададим параметры фильтра в регистре 0xF5, биты 3 и 4, вызвав функцию bme280_set_filter(). Эта функция также принимает один параметр — значение коэффициента IIR-фильтра. Она может принимать любое из перечисленных ниже значений:

  • BME280_FILTER_COEFF_OFF
  • BME280_FILTER_COEFF_2
  • BME280_FILTER_COEFF_4
  • BME280_FILTER_COEFF_8
  • BME280_FILTER_COEFF_16

Наконец, мы установим режим энергопотребления датчика, вызвав функцию bme280_set_power_mode(). Эта функция принимает один параметр, обозначающий режим работы в регистре 0xF4, биты 0 и 1. Он может принимать любое из перечисленных ниже значений:

  • BME280_SLEEP_MODE
  • BME280_FORCED_MODE
  • BME280_NORMAL_MODE

Если все параметры датчика установлены успешно, мы запустим бесконечный цикл, который считывает и выводит данные датчика на консоль. Для считывания нескомпенсированных показаний давления, температуры и влажности мы вызываем функцию bme280_read_uncomp_pressure_temperature_humidity(). Эта функция принимает три параметра: значения нескомпенсированного давления, температуры и влажности соответственно. Если датчик BME280 измеряет правильно, показания датчика будут записаны на терминал. Функция bme280_compensate_temperature_double() выводит фактическую температуру из нескомпенсированной температуры. Функция bme280_compensate_pressure_double() выводит фактическое давление из нескомпенсированного давления. Аналогично, функция bme280_compensate_humidity_double() выводит фактическую влажность из нескомпенсированной влажности. В случае ошибки измерения или инициализации датчика будет выведено соответствующее сообщение.

После этого мы удалим задачу, используя функцию vTaskDelete(). Передача значения NULL в качестве параметра приведет к удалению вызывающей задачи.

app_main()

Внутри функции app_main() мы вызовем функцию i2c_master_init() для инициализации ведущего устройства I2C. Затем используем xTaskCreate() для создания задачи чтения данных с датчика BME280, которая будет получать показания датчика BME280 и непрерывно выводить их на консоль.

Компиляция скетча

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

После успешной прошивки кода вы сможете просмотреть показания температуры, давления и влажности на консоли.

Отображение показаний BME280 на OLED-дисплее

Теперь давайте создадим ещё один проект, в котором мы запрограммируем нашу плату ESP32 для сбора показаний датчика BME280 и их отображения на 0,96-дюймовом OLED-дисплее SSD1306.

Создание проекта

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

  • Для начала добавим необходимые заголовочные файлы для библиотек, требуемых для этого проекта. После добавления библиотек BME280 перейдём к добавлению библиотек ssd1306. В папке components создайте новую папку с именем ‘ssd1306’ и добавьте все файлы, доступные по этой ссылке. Это включает в себя все файлы, перечисленные ниже:

Настройки MenuConfig в ESP-IDF для OLED дисплея 

Для начала перейдем к menuconfig. Откройте редактор конфигурации ESP-IDF SDK. Прокрутите вниз и откройте раздел SSD1306 Configuration (конфигурации SSD1306). Здесь мы можем установить параметры конфигурации SSD1306 в соответствии с нашими потребностями. Это включает в себя интерфейс UART, тип панели, контакты SCL GPIO, SDA GPIO и контакт сброса GPIO. Здесь вы можете увидеть, что по умолчанию ESP-IDF использует интерфейс I2C, тип панели 128×64, контакт SCL GPIO 22, контакт SDA GPIO 21 и контакт сброса GPIO 33. Вы можете изменить эти параметры в соответствии с вашим OLED-дисплеем, а затем нажать кнопку «Сохранить» вверху. Мы оставим настройки конфигурации по умолчанию, поскольку они соответствуют нашему модулю.

Поскольку наш датчик BME280 также взаимодействует через интерфейс I2C, для обоих устройств будут использоваться одни и те же контакты связи.

Теперь перейдите к файлу main.c. В папке main находится исходный код, то есть файл main.c будет находиться здесь. Перейдите в папку main > main.c и откройте его. Скопируйте приведенный ниже код из этого файла и сохраните его.

Код ESP32 для отображения показаний BME280 на OLED-дисплее

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

Большая часть кода идентична коду предыдущего проекта, где мы непрерывно получали показания датчика BME280. Однако на этот раз вместо отображения показаний на терминале ESP-IDF мы стремимся отображать их на OLED-дисплее. Давайте рассмотрим части кода, где мы используем OLED-дисплей. Остальные функции для получения показаний температуры, давления и влажности от датчика BME280 остались прежними.

Внутри функции bme280_oled_task() мы сначала инициализируем интерфейс I2C. Интерфейс I2C будет сконфигурирован путем вызова функции i2c_master_init() и передачи в качестве параметров адреса структуры SSD1306_t, выводов SDA, SCL и Reset. Это настроит ведущее устройство ESP32 на прослушивание ведомых устройств на шине I2C.

После этого мы инициализируем OLED-дисплей, вызвав функцию ssd1306_init(). Она принимает три параметра. Первый параметр — это адрес структуры SSD1306_t, второй — ширина, а третий — высота дисплея в пикселях. Мы используем дисплей 128×64, поэтому ширина равна 128, а высота — 64.

Давайте очистим экран OLED-дисплея с помощью функции ssd1306_clear_screen(). Эта функция принимает два параметра. Первый — это адрес структуры SSD1306_t, а второй — переменная типа invert, которая имеет значение false. Это означает, что фон будет темным, а текст будет отображаться белым.

Во-вторых, контрастность экрана устанавливается с помощью функции ssd1306_contrast(). Эта функция принимает два параметра. Первый — это адрес структуры SSD1306_t, а второй — значение контрастности, которое представляет собой целочисленную переменную. Оно устанавливается равным 0xff.

После этого датчик BME280 настраивается и инициализируется. Если все параметры датчика установлены успешно, мы запускаем бесконечный цикл, который считывает и выводит данные датчика на OLED-дисплей. Для считывания нескомпенсированных показаний давления, температуры и влажности мы вызываем функцию bme280_read_uncomp_pressure_temperature_humidity().

Функция bme280_compensate_temperature_double() выводит фактическую температуру из нескомпенсированной. Функция bme280_compensate_pressure_double() выводит фактическое давление из нескомпенсированного давления. Аналогично, функция bme280_compensate_humidity_double() выводит фактическую влажность из нескомпенсированной влажности. Сначала мы преобразуем тип данных double в массив символов, округлим до двух десятичных знаков и добавим единицы измерения для каждого показания.

Если датчик BME280 измеряет правильно, показания датчика будут отображаться на OLED-дисплее. В случае ошибки измерения или инициализации датчика на консоль будет выведено соответствующее сообщение.

Для отображения показаний каждого датчика на OLED-экране мы вызовем функцию ssd1306_display_text. Она принимает пять параметров. Первый параметр — это адрес структуры SSD1306_t. Второй параметр — это номер страницы данных о составе, который устанавливается как ‘0’ для показаний температуры, ‘2’ для показаний давления и ‘4’ для показаний влажности. Третий параметр — это текст, который мы хотим отобразить. Это массив символов для каждого показания датчика. Четвертый параметр — это длина текста. Наконец, пятый параметр — это переменная типа invert, которая является логической переменной. Она устанавливается в значение false. Это означает, что у нас темный фон, и текст будет отображаться белым цветом. Эта функция будет вызываться отдельно для каждого показания датчика и будет обновляться каждую секунду.

Внутри функции app_main() мы вызовем xTaskCreate() для создания задачи bme280 oled, которая будет получать показания датчика BME280 и выводить их на OLED-дисплей каждую секунду.

Аппаратная конфигурация: OLED-дисплей с ESP32 и BME280.

Подключите три устройства, как показано в таблице и на принципиальной схеме ниже:

OLED-дисплей ESP32 BME280
VCC VCC=3.3V VCC
GND GND GND
SCL GPIO22 SCL
SDA GPIO21 SDA

Компиляция скетча

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

После успешной прошивки кода вы сможете увидеть в терминале ESP-IDF, что OLED-дисплей успешно сконфигурирован.

На OLED-экране начнут отображаться показания датчика BME280, включая температуру в градусах Цельсия, давление в гПа и влажность в процентах.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *