diff --git a/components/MQ-2/CMakeLists.txt b/components/MQ-2/CMakeLists.txt new file mode 100644 index 0000000..b70ccb8 --- /dev/null +++ b/components/MQ-2/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "MQ-2.c" + INCLUDE_DIRS "include" + REQUIRES esp_adc) diff --git a/components/MQ-2/MQ-2.c b/components/MQ-2/MQ-2.c new file mode 100644 index 0000000..c455e4b --- /dev/null +++ b/components/MQ-2/MQ-2.c @@ -0,0 +1,67 @@ +#include "MQ-2.h" + +#include "esp_adc/adc_oneshot.h" +#include "esp_check.h" + +#define MQ2_ADC_UNIT ADC_UNIT_1 +#define MQ2_ADC_CHANNEL ADC_CHANNEL_7 +#define MQ2_SAMPLE_COUNT 8 + +static const char *TAG = "MQ2"; +static adc_oneshot_unit_handle_t s_adc_handle = NULL; +static bool s_inited = false; + +esp_err_t mq2_init(void) +{ + if (s_inited) { + return ESP_OK; + } + + adc_oneshot_unit_init_cfg_t init_cfg = { + .unit_id = MQ2_ADC_UNIT, + .ulp_mode = ADC_ULP_MODE_DISABLE, + }; + ESP_RETURN_ON_ERROR(adc_oneshot_new_unit(&init_cfg, &s_adc_handle), TAG, "adc new unit failed"); + + adc_oneshot_chan_cfg_t chan_cfg = { + .atten = ADC_ATTEN_DB_12, + .bitwidth = ADC_BITWIDTH_DEFAULT, + }; + ESP_RETURN_ON_ERROR(adc_oneshot_config_channel(s_adc_handle, MQ2_ADC_CHANNEL, &chan_cfg), + TAG, "adc channel config failed"); + + s_inited = true; + return ESP_OK; +} + +esp_err_t mq2_read_raw(int *raw_out) +{ + ESP_RETURN_ON_FALSE(raw_out != NULL, ESP_ERR_INVALID_ARG, TAG, "raw_out is null"); + ESP_RETURN_ON_FALSE(s_inited, ESP_ERR_INVALID_STATE, TAG, "mq2 not inited"); + + int sum = 0; + for (int i = 0; i < MQ2_SAMPLE_COUNT; ++i) { + int sample = 0; + ESP_RETURN_ON_ERROR(adc_oneshot_read(s_adc_handle, MQ2_ADC_CHANNEL, &sample), + TAG, "adc read failed"); + sum += sample; + } + + *raw_out = sum / MQ2_SAMPLE_COUNT; + return ESP_OK; +} + +esp_err_t mq2_read_percent(float *percent_out) +{ + ESP_RETURN_ON_FALSE(percent_out != NULL, ESP_ERR_INVALID_ARG, TAG, "percent_out is null"); + + int raw = 0; + ESP_RETURN_ON_ERROR(mq2_read_raw(&raw), TAG, "read raw failed"); + *percent_out = (raw * 100.0f) / 4095.0f; + return ESP_OK; +} + +bool mq2_is_alarm(float percent, float threshold_percent) +{ + return percent >= threshold_percent; +} diff --git a/components/MQ-2/include/MQ-2.h b/components/MQ-2/include/MQ-2.h new file mode 100644 index 0000000..a871b76 --- /dev/null +++ b/components/MQ-2/include/MQ-2.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ESP32-S3: GPIO8 -> ADC1_CHANNEL_7 +#define MQ2_ADC_GPIO 8 + +/** + * @brief 初始化 MQ-2 ADC 通道 + */ +esp_err_t mq2_init(void); + +/** + * @brief 读取 MQ-2 原始 ADC 值(0~4095) + */ +esp_err_t mq2_read_raw(int *raw_out); + +/** + * @brief 读取 MQ-2 归一化百分比(0~100) + */ +esp_err_t mq2_read_percent(float *percent_out); + +/** + * @brief 根据阈值判断是否疑似有害气体/烟雾超标 + */ +bool mq2_is_alarm(float percent, float threshold_percent); + +#ifdef __cplusplus +} +#endif diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 8da7334..0ea6506 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,3 +1,3 @@ idf_component_register(SRCS "main.cpp" INCLUDE_DIRS "." - REQUIRES nvs_flash esp_wifi sntp_time aht30 esp_event esp_system wifi-connect ui lvgl_st7789_use efuse relay_ctrl bh1750) + REQUIRES nvs_flash esp_wifi sntp_time aht30 esp_event esp_system wifi-connect ui lvgl_st7789_use efuse relay_ctrl bh1750 MQ-2) diff --git a/main/main.cpp b/main/main.cpp index f826c9c..55fb85b 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -19,6 +19,7 @@ #include "esp_efuse_table.h" #include "bh1750_use.h" #include "aht30.h" +#include "MQ-2.h" #define TAG "MAIN" @@ -28,6 +29,7 @@ typedef struct float lux; float temp; float humidity; + float gas_percent; } env_data_t; static env_data_t s_env_data; @@ -109,12 +111,15 @@ extern "C" void app_main(void) aht30_handle_t aht30_dev = NULL; ESP_ERROR_CHECK(aht30_create(i2c_bus, AHT30_I2C_ADDRESS, &aht30_dev)); + // MQ-2 使用 ADC(GPIO8) + ESP_ERROR_CHECK(mq2_init()); + // 6. 创建传感器读取任务 xTaskCreate([](void *arg) { aht30_handle_t aht30 = (aht30_handle_t)arg; for (;;) { - float lux = 0.0f, temp = 0.0f, hum = 0.0f; + float lux = 0.0f, temp = 0.0f, hum = 0.0f, gas_percent = 0.0f; // 读取 BH1750 if (bh1750_user_read(&lux) == ESP_OK) { set_var_light_val(lux); @@ -124,6 +129,17 @@ extern "C" void app_main(void) set_var_temp(temp); set_var_humity_val(hum); } + + // 读取 MQ-2,更新空气质量变量 + if (mq2_read_percent(&gas_percent) == ESP_OK) { + set_var_air_quity(gas_percent); + + if (s_env_data_lock) { + xSemaphoreTake(s_env_data_lock, portMAX_DELAY); + s_env_data.gas_percent = gas_percent; + xSemaphoreGive(s_env_data_lock); + } + } // 数据存入共享结构体