После эксперимента с мониторингом СО2 на Arduino Nano и MQ-135 и крайне странными полученными данными были докуплены новые датчики — MH-Z19B модуль инфракрасного датчика CO2 и SCD40 модуль измерения CO2, температуры и влажности, но руки как-то все не доходили, пока не подвернулась лабораторная работа по дисциплине «Разработка микроконтроллерных устройств Интернета вещей» на базе ESP32 C3 Super Mini. Незамедлительно был закуплен контроллер и заброшен на полку до лучших времен, которые все же настали, а потом и появилось время зафиксировать результат.
И так, имеется:
- ESP32 C3 Super Mini — микроконтроллер с WiFi/BLE
- LCD1602C — текстовый дисплей 16×2 символов (I2C интерфейс)
- SCD40 — датчик CO₂, температуры и влажности (I2C интерфейс Sensirion)
- Макетная плата 830
- Модуль питания MB-102 (3.3V/5V)
Задача:
Разработать проект — схему подключения компонентов, разработать код с учетом новых компонентов и требований к мониторингу параметров через веб-интерфейс по WiFi, подготовить описание по монтажу и программированию контроллера. Необходимые данные — текущие измеряемые значения датчика, все доступные параметры компонентов — энергопотребление, токи, напряжения. Если базовый набор компонентов не позволяет выполнить все требования в части данных, то необходимо разработать два варианта проекта — из базового набора и с дополнительными компонентами.
Будем работать от самой простой реализации с постепенным усложнением функционала.
Базовый вариант:
Измерение CO₂, температуры, влажности от SCD40 и параметров которые возможно получить/измерить без дополнительных датчиков на ESP32 с отображением данных на LCD1602.
Этап 2:
Добавить веб-интерфейс с текущими показаниями.
Этап 3:
Добавить дополнительный модуль измерителя тока/напряжения для измерения:
- Напряжение питания системы
- Потребляемого тока
- Мощности энергопотребления
- Напряжения на каждом компоненте
Базовый вариант
Принципиальную схему и макетную плату готовим в Fritzing. Компоненты нашел тут SCD40, LCD1602, ESP32 C3 Super Mini, MB-102 (YwRobot). Попутно нашел STL модели корпусов.


Файл проекта Lab ESP32-SCD40-LCD1602 Sketch
Код получился следующим:
/*
* Проект: Монитор качества воздуха ESP32-C3
* Датчики: SCD40 (CO2, температура, влажность)
* Дисплей: LCD1602 I2C
*/
#include <Wire.h>
#include <LCDI2C_Multilingual_MCD.h>
#include <SparkFun_SCD4x_Arduino_Library.h>
// ===== НАСТРОЙКИ I2C =====
#define I2C_SDA 8 // GPIO8 - SDA
#define I2C_SCL 9 // GPIO9 - SCL
#define LCD_ADDR 0x27 // Адрес LCD
// ===== НАСТРОЙКИ ADC ДЛЯ ИЗМЕРЕНИЯ НАПРЯЖЕНИЯ =====
#define ADC_PIN 4 // GPIO4 - аналоговый вход
#define ADC_VREF 3.3 // Опорное напряжение АЦП
#define ADC_RESOLUTION 4095.0 // 12-бит АЦП
// ===== ОБЪЕКТЫ =====
LCDI2C_Russian lcd(LCD_ADDR, 16, 2); // LCD 16x2
SCD4x scd40; // Датчик SCD40
// ===== ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ =====
float co2 = 0; // CO2 в ppm
float temperature = 0; // Температура в °C
float humidity = 0; // Влажность в %
float voltage = 0; // Напряжение питания
unsigned long lastUpdate = 0;
const unsigned long UPDATE_INTERVAL = 5000; // Обновление каждые 5 секунд
// ===== СИМВОЛЫ ДЛЯ LCD =====
byte degreeSymbol[8] = { // Символ градуса
0b01100,
0b10010,
0b10010,
0b01100,
0b00000,
0b00000,
0b00000,
0b00000
};
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("=== ESP32-C3 Monitor - Запуск ===");
// Инициализация I2C
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("I2C инициализирован");
// Инициализация LCD
lcd.init();
lcd.backlight();
lcd.createChar(0, degreeSymbol);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ESP32-C3 Monitor");
lcd.setCursor(0, 1);
lcd.print("Starting...");
Serial.println("LCD инициализирован");
// Инициализация SCD40
if(!scd40.begin()) {
Serial.println("ОШИБКА: SCD40 не найден!");
lcd.clear();
lcd.print("SCD40: Error!");
while(1) {
delay(1000);
}
}
// Запуск периодических измерений SCD40
if(scd40.startPeriodicMeasurement()) {
Serial.println("SCD40 инициализирован успешно");
} else {
Serial.println("ОШИБКА запуска измерений SCD40");
}
delay(1000);
lcd.clear();
lcd.print("System ready");
Serial.println("Система готова к работе");
delay(2000);
}
void loop() {
// Обновление данных с датчиков
if(millis() - lastUpdate >= UPDATE_INTERVAL) {
lastUpdate = millis();
updateSensors();
updateDisplay();
}
delay(10);
}
// ===== ФУНКЦИЯ ОБНОВЛЕНИЯ ДАННЫХ С ДАТЧИКОВ =====
void updateSensors() {
// Чтение данных SCD40
if(scd40.readMeasurement()) {
co2 = scd40.getCO2();
temperature = scd40.getTemperature();
humidity = scd40.getHumidity();
Serial.println("--- Новые данные ---");
Serial.print("CO2: "); Serial.print(co2); Serial.println(" ppm");
Serial.print("Температура: "); Serial.print(temperature); Serial.println(" °C");
Serial.print("Влажность: "); Serial.print(humidity); Serial.println(" %");
} else {
Serial.println("Нет новых данных от SCD40");
}
// Измерение напряжения питания
int adcValue = analogRead(ADC_PIN);
voltage = (adcValue / ADC_RESOLUTION) * ADC_VREF * 2.0; // Делитель 1:2
Serial.print("Напряжение: "); Serial.print(voltage); Serial.println(" V");
}
// ===== ФУНКЦИЯ ОБНОВЛЕНИЯ ДИСПЛЕЯ =====
void updateDisplay() {
lcd.clear();
// Первая строка: CO2 и температура
lcd.setCursor(0, 0);
lcd.print("CO2:");
lcd.print((int)co2);
lcd.print("ppm ");
lcd.print((int)temperature);
lcd.write(0); // Символ градуса
lcd.print("C");
// Вторая строка: Влажность и напряжение
lcd.setCursor(0, 1);
lcd.print("RH:");
lcd.print((int)humidity);
lcd.print("% U:");
lcd.print(voltage, 1);
lcd.print("V");
}
Собранное устройство:
