AHT20 + BMP280 — цифровая метеостанция
Два независимых датчика на одной шине I2C: AHT20 измеряет температуру и влажность, BMP280 — температуру и атмосферное давление.
AHT20 + BMP280 — цифровая метеостанция на I2C
Два независимых датчика на одной шине I2C, на одной плате-модуле:
| Датчик | Что измеряет | I2C-адрес |
|---|---|---|
| AHT20 | температура, влажность воздуха | 0x38 (фиксированный) |
| BMP280 | температура, атмосферное давление, высота над уровнем моря | 0x76 или 0x77 |
Каждый датчик — отдельный класс-драйвер, их можно использовать независимо друг от друга в других проектах.
Файлы компонента
| Файл | Назначение |
|---|---|
include/Aht20Driver.h / src/Aht20Driver.cpp | Драйвер AHT20 |
include/Bmp280Driver.h / src/Bmp280Driver.cpp | Драйвер BMP280 |
src/main.cpp | Тестовый стенд: опрос обоих датчиков раз в 2 секунды, вывод в Serial |
THEORY.md | Как физически работают датчики, откуда берутся формулы |
WIRING.md | Схема подключения к ESP32 |
PREZ.md | Короткая презентация проекта (5 слайдов-тезисов) |
Про сборку/прошивку/монитор через PlatformIO CLI — см. корневой README, команды одинаковы для всех компонентов репозитория.
API драйверов
Оба драйвера следуют одному и тому же паттерну:
Aht20Driver aht20(Wire); // Dependency Injection: шина I2C передаётся в конструктор
Bmp280Driver bmp280(Wire);
aht20.begin(I2C_SDA, I2C_SCL); // true, если датчик отозвался на шине
bmp280.begin(I2C_SDA, I2C_SCL);
aht20.update(); // опросить датчик, вернёт true при успехе
const Aht20Driver::Data &d = aht20.getData(); // d.temperatureC, d.humidityPercent
aht20.isAlive(); // false, если давно не было успешного обмена (обрыв шины/датчика)
Bmp280Driver::Data дополнительно содержит pressurePa (давление в Паскалях, СИ) и altitudeM (оценочная высота, м — по барометрической формуле, требует корректного setSeaLevelPressureHpa()). Разбор физики и формул — в THEORY.md.
Почему два класса, а не один
AHT20 и BMP280 — разные чипы с разными датащитами и разными адресами I2C, которые просто физически напаяны на одну плату. Разделение на Aht20Driver/Bmp280Driver позволяет использовать любой из них отдельно (например, только BMP280 в проекте высотомера) без притаскивания второго. src/main.cpp — единственное место, где они используются вместе.
Теория: как работают AHT20 и BMP280
1. AHT20 — влажность и температура
AHT20 — это две отдельные измерительные схемы под одним корпусом:
- Влажность измеряется ёмкостным сенсором: между двумя электродами находится полимерная плёнка, которая впитывает водяной пар из воздуха. Чем больше влаги впитала плёнка, тем выше её диэлектрическая проницаемость — а значит, выше ёмкость конденсатора, который эта плёнка образует. Электроника чипа измеряет эту ёмкость и переводит её в проценты относительной влажности (%RH — сколько водяного пара в воздухе относительно максимума, который воздух может удержать при этой температуре).
- Температура измеряется отдельным полупроводниковым датчиком внутри того же корпуса.
Оба значения приходят уже откалиброванными с завода — драйверу не нужно ничего компенсировать самому, за это отвечает Adafruit_AHTX0 внутри Aht20Driver::update().
Характеристики (Aosong AHT20 datasheet V1.0, Table 1–2, стр.2):
| Параметр | Диапазон | Точность (typical) |
|---|---|---|
| Влажность | 0…100 %RH | ±2 %RH |
| Температура | −40…+85 °C | ±0.3 °C |
Время отклика — около 8 секунд на 63% полного отклика для влажности (датчик “думает” не мгновенно, воде нужно время впитаться в плёнку). Именно поэтому в src/main.cpp:7 стенд опрашивает датчики раз в 2 секунды, а не постоянно — более частый опрос не даст более свежих данных.
2. BMP280 — давление, температура, высота
BMP280 меряет давление пьезорезистивным элементом: тонкая кремниевая мембрана прогибается под давлением воздуха, а электроника чипа переводит этот прогиб в цифровое значение через 12 калибровочных коэффициентов, зашитых в чип на заводе (см. BMP280_REGISTER_DIG_* в Adafruit_BMP280 — тот самый смысл фразы “компенсация” в даташите).
Характеристики (Bosch BMP280 datasheet DS001, rev.1.26, Table 2, стр.7):
| Параметр | Диапазон | Точность |
|---|---|---|
| Давление | 300…1100 гПа | абсолютная typ. ±1 гПа (0…65 °C); относительная ±0.12 гПа (изменение давления между двумя своими же измерениями, эквивалент ±1 м высоты) |
| Температура | −40…+85 °C | ±0.5 °C при 25 °C, до ±1.0 °C в 0…65 °C |
Важно не путать эти две точности: ±1 гПа — это на сколько показание датчика может отличаться от истинного давления. А ±0.12 гПа — это на сколько может “дрожать” разница между двумя последовательными измерениями одного и того же датчика при постоянном давлении. Для задачи “заметить, что человек поднялся на этаж” важна вторая цифра, а не первая — драйверу не нужна абсолютная точность, важна стабильность.
Расчёт высоты
Чем выше над уровнем моря, тем разреженнее воздух и тем ниже давление. Зависимость приближённо описывается барометрической формулой; в Bmp280Driver::update() (src/Bmp280Driver.cpp) она вызывается через Adafruit_BMP280::readAltitude(seaLevelhPa). Чтобы формула дала верную высоту, ей нужно знать текущее давление на уровне моря (QNH) — это метеорологическая величина, которая меняется день ото дня. Без актуального QNH высота будет посчитана относительно “средней” атмосферы (1013.25 гПа — значение по умолчанию в Bmp280Driver.h:60), и ошибка может достигать десятков метров. Задать реальное QNH можно через setSeaLevelPressureHpa().
3. Почему два датчика уживаются на одной шине I2C
I2C — это шина, где на двух проводах (SDA — данные, SCL — тактовый сигнал) может сидеть много устройств одновременно. Ведущий (ESP32) обращается к конкретному устройству по его адресу — как по номеру квартиры на одной лестничной клетке. Пока адреса разные, устройства не мешают друг другу:
- AHT20 всегда отвечает на
0x38(адрес зашит в чип, не настраивается — Aosong AHT20 datasheet V1.0, п.7.3, стр.12). - BMP280 отвечает на
0x76или0x77в зависимости от того, куда на плате подключен вывод SDO (Bosch BMP280 datasheet DS001, rev.1.26, разд. 5.2). На большинстве готовых модулей SDO подтянут к VDD, поэтому используется0x77— это же значение стоит по умолчанию вBmp280Driver.h:21,27.
4. Единицы измерения давления в этом компоненте
Оба датчика Bosch (и библиотека Adafruit) работают в паскалях (Па) — это единица СИ, поэтому Bmp280Driver::Data::pressurePa хранит именно паскали (Bmp280Driver.h:14). В российской школьной традиции атмосферное давление принято мерить в мм рт.ст., поэтому тестовый стенд переводит паскали в мм рт.ст. только для вывода на экран — см. PA_TO_MMHG в src/main.cpp:10. Коэффициент 133.322 — это физическое определение единицы “миллиметр ртутного столба” (вес столбика ртути высотой 1 мм при стандартном g), а не что-то специфичное для датчика.
Схема подключения AHT20 + BMP280
Оба датчика сидят на одной и той же паре проводов SDA/SCL — они различаются не пинами, а адресами I2C (подробнее — THEORY.md, раздел 3). Пины по умолчанию в src/main.cpp: I2C_SDA = 21, I2C_SCL = 22.
1. Схема для ESP32 (I2C)
┌─────────────────┐
│ ESP32 │
│ │
│ 3V3 ├───────┬───────┐
│ │ │ │
│ GND ├───────┼───┐ │
│ │ │ │ │
│ GPIO21 ├───────┼───┼───┤ SDA
│ (SDA) │ │ │ │
│ GPIO22 ├───────┼───┼───┤ SCL
│ (SCL) │ │ │ │
└─────────────────┘ │ │ │
│ │ │
┌───────┴───┴───┴───────┐
│ AHT20 + BMP280 │
│ Module │
│ │
│ VIN GND SCL SDA │
└───────────────────────┘2. Параметры подключения
- Питание: 3.3V (VIN модуля обычно имеет стабилизатор, но рекомендуется 3.3V).
- Шина I2C: Требует подтягивающих резисторов (обычно 4.7 кОм - 10 кОм), на большинстве модулей они уже установлены.
- Пины ESP32:
- SDA: GPIO 21
- SCL: GPIO 22
3. Рекомендации
- Используйте короткие провода для I2C (до 30-50 см).
- При использовании длинных проводов рекомендуется снизить скорость шины до 100 кГц.
Методический план урока: метеостанция, шина I2C и цена точности
Паспорт урока
| Параметр | Значение |
|---|---|
| Место в курсе | Sensors/Meteo — первый урок с двумя датчиками на одной шине |
| Длительность | 45 мин (или 2 × 45 с экспериментом «этаж») |
| Возраст | 13–16, материал двухуровневый |
| Оборудование | ESP32, модуль AHT20+BMP280, 4 провода; для эксперимента — лестница в здании |
| Предварительные знания | Serial-монитор, понятие протокола, класс-драйвер |
| Предмет | Физика (давление, влажность, атмосфера), информатика (шина, адресация), математика (погрешность) |
Образовательные цели
По итогам урока ученик умеет:
| № | Цель | Блум | Миллер | Чем доказывается |
|---|---|---|---|---|
| 6.1 | Объяснить, как два датчика работают на двух проводах | понимать | знает как | Ответ через адреса устройств |
| 6.2 | Найти адрес устройства на шине сканером I2C | применять | делает | Найдены 0x38 и 0x77 |
| 6.3 | Различить абсолютную и относительную точность | анализировать | показывает как | Верный выбор для задачи «этаж» |
| 6.4 | Объяснить, почему опрос чаще не даёт свежих данных | понимать | знает как | Ответ через время отклика |
| 6.5 | Спроектировать измерение под заданную задачу | создавать | показывает как | Обоснованная схема опыта |
Чего на этом уроке делать НЕ надо. Не разбирать временны́е диаграммы I2C (старт-условие, ACK, тактирование) и не выводить барометрическую формулу. Первое — материал курса схемотехники, второе — физики старших классов. Урок держится на двух открытиях: много устройств на двух проводах и точность бывает разная.
Что должно быть готово заранее
- Модуль подключён и проверен: оба датчика отвечают, значения идут
- Записано текущее QNH (давление на уровне моря) по метеосводке
- Известна высота этажа здания — для проверки эксперимента
- Подготовлен скетч-сканер I2C (или готов вывод
begin()обоих драйверов) - Стакан тёплой воды или влажная тряпка — для демонстрации отклика влажности
- Проверено: SDA и SCL не перепутаны
Полезный реквизит. Влажная тряпка или дыхание на датчик даёт мгновенно видимую реакцию влажности. Это превращает абстрактные проценты в наблюдаемое явление и обычно вызывает больше интереса, чем любые слайды.
Сценарий занятия (45 минут)
| Время | Блок | Что делает педагог | Что делают ученики |
|---|---|---|---|
| 0–6 | Завязка | Считает провода, задаёт вопрос | Обнаруживают несоответствие |
| 6–14 | Шина и адреса | Ведёт модель «лестничная клетка» | Запускают сканер, находят адреса |
| 14–22 | Как меряют | Разбирает физику двух датчиков | Дышат на датчик, наблюдают |
| 22–32 | Точность | Ставит задачу «заметить этаж» | Решают, какая точность нужна |
| 32–40 | Практика | Раздаёт задания | Работают по уровням |
| 40–45 | Итог и ДЗ | Фиксирует выводы | Записывают в журнал |
Ключевой методический принцип — противоречие в начале. Два датчика, четыре провода, из них два — питание. Ребёнок видит несоответствие раньше, чем услышит слово «шина». Объяснение приходит как разрешение загадки, а не как новая тема.
Блок 1. Завязка (0–6 мин)
Показать модуль, не объясняя.
«Здесь два разных датчика: один меряет влажность, другой давление. Сколько проводов нужно, чтобы подключить два прибора?»
Обычный ответ — четыре или больше. Показать реальное подключение: четыре провода всего, из них два — питание и земля. На данные остаётся два.
«Два провода на два прибора. Как они не путаются? И что будет, если я добавлю третий датчик — понадобится ещё два провода?»
Ответ «нет, те же два» удивляет и держит внимание весь следующий блок.
Блок 2. Шина и адреса (6–14 мин)
Модель «лестничная клетка»
«Представьте подъезд: одна лестница ведёт ко всем квартирам. Почтальон не строит отдельную лестницу к каждой двери — он поднимается по общей и называет номер квартиры. Отзывается только нужная.»
Записать соответствие:
| В подъезде | На шине I2C |
|---|---|
| Общая лестница | Два провода: SDA (данные), SCL (такт) |
| Номер квартиры | Адрес устройства |
| Почтальон | Ведущее устройство — ESP32 |
| Жильцы | Датчики |
Находим адреса на практике
Запустить сканер шины. На экране появятся 0x38 и 0x77.
«
0x38— это AHT20, влажность.0x77— BMP280, давление. Числа шестнадцатеричные, но сейчас важно не это, а то, что они разные.»
Главный вопрос блока:
«А если поставить два одинаковых датчика влажности? У них же один и тот же адрес.»
Довести до вывода: будет конфликт — как две квартиры с одним номером. Именно
поэтому у BMP280 адрес переключаемый (0x76 или 0x77, вывод SDO на плате),
а у AHT20 — жёстко зашит, и два таких на одной шине не уживутся.
Это настоящая инженерная проблема, а не учебная условность — материал THEORY.md, раздел 3.
Блок 3. Как они меряют (14–22 мин)
3.1. Базовый уровень (13–14 лет)
Влажность — через впитывание.
Внутри плёнка, которая впитывает воду из воздуха. Чем больше впитала — тем сильнее меняются её электрические свойства. Датчик меряет это изменение.
Сразу демонстрация: подышать на датчик. Влажность подскакивает. Убрать — медленно возвращается.
Давление — через прогиб.
Тонкая кремниевая мембрана прогибается под весом воздуха, как натянутая плёнка на барабане. Чем сильнее давит — тем больше прогиб.
3.2. Углублённый уровень (15–16 лет)
Добавить важное наблюдение из демонстрации:
«Заметили, что влажность растёт быстро, а падает медленно? Почему?»
Довести до времени отклика: около 8 секунд на 63% изменения — воде нужно время впитаться и испариться. Отсюда следствие, которое стоит подчеркнуть:
В коде датчики опрашиваются раз в 2 секунды, а не постоянно. Опрашивать чаще бессмысленно — датчик физически не успевает измениться. Частый опрос даст те же числа, только нагрузит процессор.
Это важный инженерный принцип: частота опроса определяется физикой явления, а не возможностями процессора.
Блок 4. Точность: главный сюжет урока (22–32 мин)
Поставить задачу и дать подумать:
«Можно ли по датчику давления понять, что вы поднялись на один этаж?»
Дать высказаться, затем выложить два числа из даташита (THEORY.md, раздел 2):
| Что за точность | Значение | Что означает |
|---|---|---|
| Абсолютная | ±1 гПа | Насколько показание может отличаться от истинного давления |
| Относительная | ±0,12 гПа | Насколько «дрожат» два измерения одного датчика подряд |
Один этаж — примерно 3 метра, это около 0,36 гПа разницы давления.
«Сравните с обеими цифрами. По какой из них этаж заметен?»
Вывод, к которому нужно прийти:
- По абсолютной (±1 гПа) — не заметен, разница тонет в погрешности.
- По относительной (±0,12 гПа) — заметен уверенно, втрое больше дрожания.
Почему это важнее, чем кажется. Датчик может «врать» на 1 гПа постоянно — но врать одинаково. Для задачи «изменилось ли?» систематическая ошибка не мешает: она вычитается сама. Для задачи «сколько именно?» — мешает.
Это одна из самых переносимых идей курса: правильная характеристика прибора зависит от вопроса, который вы задаёте. Стоит проговорить явно.
Если есть второй урок — эксперимент
Спуститься с модулем на этаж ниже, записать давление, подняться, записать снова. Посчитать разницу и сравнить с расчётом. Обычно сходится — и производит сильное впечатление.
Блок 5. Практика по уровням (32–40 мин)
Уровень A (базовый)
- Записать показания всех четырёх величин (температура ×2, влажность, давление).
- Подышать на датчик и описать, как меняются показания и как быстро.
- Объяснить, почему температура выводится дважды и почему значения слегка разные.
Уровень B (средний)
- Перевести давление из паскалей в мм рт. ст. вручную и сверить с выводом программы. Коэффициент и его смысл — THEORY.md, раздел 4.
- Измерить время отклика влажности: подышать и засечь, за сколько секунд значение вырастет и вернётся. Сравнить с 8 секундами из даташита.
- Задать реальное QNH через
setSeaLevelPressureHpa()по метеосводке и сравнить вычисленную высоту с фактической высотой школы.
Уровень C (продвинутый)
- Оценить, можно ли этим датчиком отличить открытое окно от закрытого. Спланировать опыт, провести, сделать вывод.
- Объяснить письменно, почему два датчика температуры на одной плате показывают разные значения, и какое из них считать верным.
- Предложить алгоритм «детектор подъёма по лестнице»: какие показания брать, как часто, какой порог выбрать, чтобы не срабатывать на погоду. Подсказка: погода меняет давление медленно, лестница — быстро.
Ответы на вопросы, которые прозвучат
«Почему температура с двух датчиков разная?» Они в разных корпусах, греются по-разному, и каждый имеет свою погрешность (±0,3 °C у AHT20, до ±1 °C у BMP280). Разница в полградуса — норма. Более точным для воздуха считается AHT20.
«Датчик показывает 750 мм, а по радио говорят 745. Кто врёт?» Никто. Метеослужба приводит давление к уровню моря (QNH), а датчик меряет здесь, на вашей высоте. Разница и есть ваша высота над морем.
«Влажность 40% — это много или мало?» Относительная влажность показывает долю от максимума, который воздух держит при этой температуре. Тёплый воздух держит больше. Поэтому 40% летом и зимой — разное количество воды. Комфортным для человека считается 40–60%.
«Можно повесить десять датчиков на эти два провода?» Да, пока адреса разные и провода не слишком длинные. У I2C есть предел по ёмкости линии — на длинных проводах связь рассыпается. Для стола это не проблема.
«Зачем в коде isAlive(), если датчик вот он?»
Провод может отойти во время работы. Без проверки программа продолжит показывать
последние прочитанные значения, и никто не заметит, что они устарели. Молчаливый
отказ хуже явного.
Итог урока: что записать в журнал
- На шине I2C много устройств живут на двух проводах, различаясь адресами.
- Частота опроса определяется физикой датчика, а не желанием программиста.
- Абсолютная точность и относительная — разные вещи; какая важнее, решает задача.
Проверка понимания (экспресс, 2 минуты)
| Вопрос | Ожидаемый ответ |
|---|---|
| Два одинаковых AHT20 на одной шине — заработают? | Нет, одинаковый зашитый адрес 0x38 |
| Зачем опрашивать раз в 2 с, а не 100 раз в секунду? | Датчик не успевает измениться, данные те же |
| Какая точность нужна, чтобы заметить этаж? | Относительная, ±0,12 гПа |
| Почему датчик и метеосводка расходятся? | Сводка приведена к уровню моря |
Типичные затруднения
| Затруднение | Причина | Что делать |
|---|---|---|
| «Два прибора — два кабеля» | Модель «каждому своё соединение» | Вернуться к подъезду и номерам квартир |
| Считают обе точности одним числом | Слово «точность» кажется однозначным | Разобрать на задаче «заметить этаж» |
| Ждут мгновенной реакции влажности | Привычка к цифровым приборам | Засечь время секундомером |
| Путают SDA и SCL | Похожие названия | Подписать провода цветом |
Домашнее задание
Обязательная часть: записать показания домашнего термометра или гигрометра утром и вечером. Объяснить, почему влажность в квартире зимой обычно ниже, чем летом.
Уровень A: найти, какое давление считается нормальным для вашего города, и сравнить с показаниями датчика на уроке.
Уровень B: выяснить, на какой высоте над уровнем моря находится ваш город, и посчитать, какое давление там должно быть по барометрической формуле. Сравнить с измеренным.
Уровень C: прочитать раздел 2 THEORY.md и письменно объяснить, почему для альпиниста важна абсолютная точность, а для шагомера-высотомера в телефоне — относительная.
Связь с курсом
| Что дальше | Где |
|---|---|
| Другие датчики на той же шине I2C | MPU6050, APDS9960 |
| Передача измерений по радио | xfarm — тепличная телеметрия |
| Погрешность и статистика измерений | WarWalk — урок про медиану |
Урок вводит шину I2C, на которой дальше работает большинство датчиков курса. Стоит проговорить: с этого момента подключение нового датчика почти не требует новых проводов — только новый адрес.
Чек-лист педагога перед уроком
- Оба датчика отвечают, адреса
0x38и0x77видны сканером - Текущее QNH записано на доске
- Высота этажа и высота школы над уровнем моря известны
- Влажная тряпка или стакан воды под рукой
- Расчёт «этаж = 0,36 гПа» подготовлен заранее
- Карточки заданий A / B / C распечатаны
Презентация: AHT20 + BMP280 — метеостанция на I2C
Слайд 1: Цель проекта
Собрать компактный модуль для измерения параметров воздуха: температуры, влажности, атмосферного давления и оценочной высоты над уровнем моря — двумя независимыми цифровыми датчиками на одной шине I2C.
Слайд 2: Используемые компоненты
- ESP32 — читает оба датчика по I2C и выводит показания в Serial.
- AHT20 — цифровой датчик влажности и температуры (Aosong).
- BMP280 — цифровой датчик давления и температуры (Bosch Sensortec).
Слайд 3: Один физический модуль — два независимых датчика
- Экономия пинов: оба датчика используют одни и те же 2 линии (SDA/SCL), различаются только адресом на шине (
0x38и0x76/0x77). - Независимость: каждый датчик — отдельный класс-драйвер (
Aht20Driver,Bmp280Driver), который можно взять и использовать в другом проекте без второго. - Два источника температуры: оба чипа измеряют температуру независимо — расхождение между ними полезно как быстрая проверка на неисправность одного из датчиков.
Слайд 4: Программная архитектура
- Один класс-драйвер на чип, с общим для репозитория API:
begin()/update()/getData()/isAlive(). isAlive()— вотчдог связи: если датчик перестал отвечать (обрыв провода, отвалившийся модуль), это сразу видно в диагностике, а не тихо зависает в старых данных.src/main.cpp— тестовый стенд: опрашивает оба датчика раз в 2 секунды и печатает показания и статус связи в Serial.
Слайд 5: Результаты
- Стабильное чтение обоих датчиков на одной шине I2C.
- Расчёт высоты по барометрической формуле (с оговоркой про давление на уровне моря — см. THEORY.md).
- Собирается под esp32dev и esp32s3; esp32c6 упирается в известный баг Arduino-ядра с макросом
Serial/USBSerial, см. COMPONENT_STANDARD.md.