Compare commits
2 Commits
f6f33a6f84
...
0eb428aaa5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0eb428aaa5 | ||
|
|
4e829bc56f |
@@ -80,10 +80,21 @@ dependencies:
|
|||||||
registry_url: https://components.espressif.com
|
registry_url: https://components.espressif.com
|
||||||
type: service
|
type: service
|
||||||
version: 9.5.0
|
version: 9.5.0
|
||||||
|
supcik/hx711:
|
||||||
|
component_hash: 38de09d1a896b3eda3cbb8c259979deed77fa0c517516c2b344dc55ae04f4fb6
|
||||||
|
dependencies:
|
||||||
|
- name: idf
|
||||||
|
require: private
|
||||||
|
version: '>=5.3'
|
||||||
|
source:
|
||||||
|
registry_url: https://components.espressif.com/
|
||||||
|
type: service
|
||||||
|
version: 1.1.3
|
||||||
direct_dependencies:
|
direct_dependencies:
|
||||||
- espressif/aht30
|
- espressif/aht30
|
||||||
- espressif/esp_lvgl_port
|
- espressif/esp_lvgl_port
|
||||||
- idf
|
- idf
|
||||||
manifest_hash: 15dd4fd3d660b11406a1dde8c0ec0b63f12e3cd4064ff9026e70648e3f7bc8a3
|
- supcik/hx711
|
||||||
|
manifest_hash: 09736a2502ce314a6733743671e919311d43e602eb74410732a63f10ed3aa60a
|
||||||
target: esp32s3
|
target: esp32s3
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
idf_component_register(SRCS "main.cpp"
|
idf_component_register(SRCS "main.cpp"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES nvs_flash esp_wifi sntp_time aht30 esp_event esp_system wifi-connect ui lvgl_st7789_use efuse relay_ctrl bh1750 MQ-2 JW01 human_door fire_sensor)
|
REQUIRES nvs_flash esp_wifi sntp_time aht30 esp_event esp_system wifi-connect ui lvgl_st7789_use efuse relay_ctrl bh1750 MQ-2 JW01 human_door fire_sensor hx711)
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ dependencies:
|
|||||||
# public: true
|
# public: true
|
||||||
espressif/esp_lvgl_port: ^2.7.2
|
espressif/esp_lvgl_port: ^2.7.2
|
||||||
espressif/aht30: ^1.0.0
|
espressif/aht30: ^1.0.0
|
||||||
|
supcik/hx711: ^1.1.3
|
||||||
|
|||||||
162
main/main.cpp
162
main/main.cpp
@@ -1,6 +1,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
#include "wifi-connect.h"
|
#include "wifi-connect.h"
|
||||||
#include "esp_lvgl_port.h"
|
#include "esp_lvgl_port.h"
|
||||||
#include "lvgl_st7789_use.h"
|
#include "lvgl_st7789_use.h"
|
||||||
@@ -12,21 +13,39 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include "esp_task_wdt.h"
|
||||||
#include "sntp_time.h"
|
#include "sntp_time.h"
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_efuse.h"
|
#include "esp_efuse.h"
|
||||||
#include "esp_efuse_table.h"
|
#include "esp_efuse_table.h"
|
||||||
|
#include "sntp_time.h"
|
||||||
#include "bh1750_use.h"
|
#include "bh1750_use.h"
|
||||||
#include "aht30.h"
|
#include "aht30.h"
|
||||||
#include "MQ-2.h"
|
#include "MQ-2.h"
|
||||||
#include "JW01.h"
|
#include "JW01.h"
|
||||||
#include "human_door.h"
|
#include "human_door.h"
|
||||||
#include "fire_sensor.h"
|
#include "fire_sensor.h"
|
||||||
|
#include "hx711.hpp"
|
||||||
|
|
||||||
#define TAG "MAIN"
|
#define TAG "MAIN"
|
||||||
#define CO2_SPOILAGE_THRESHOLD_PPM 1500.0f
|
#define CO2_SPOILAGE_THRESHOLD_PPM 1500.0f
|
||||||
#define FIRE_DANGER_THRESHOLD_PERCENT 35.0f
|
#define FIRE_DANGER_THRESHOLD_PERCENT 35.0f
|
||||||
|
static const gpio_num_t kClockPin = GPIO_NUM_13;
|
||||||
|
static const gpio_num_t kDataPin = GPIO_NUM_14;
|
||||||
|
|
||||||
|
#define HX711_TARE_SAMPLES 24
|
||||||
|
#define HX711_READ_TIMEOUT_MS 350
|
||||||
|
#define HX711_REFRESH_MS 120
|
||||||
|
#define HX711_COUNTS_PER_GRAM 430.0f
|
||||||
|
#define HX711_ZERO_DEADBAND_G 2.0f
|
||||||
|
#define HX711_FILTER_ALPHA 0.15f
|
||||||
|
#define HX711_STABLE_BAND_G 0.30f
|
||||||
|
#define HX711_UNLOCK_DELTA_G 2.00f
|
||||||
|
#define HX711_UPDATE_MIN_STEP_G 0.05f
|
||||||
|
#define HX711_STABLE_SAMPLES 15
|
||||||
|
#define TWDT_NORMAL_TIMEOUT_MS 5000
|
||||||
|
#define TWDT_UI_INIT_TIMEOUT_MS 120000
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -38,6 +57,7 @@ typedef struct
|
|||||||
float tvoc;
|
float tvoc;
|
||||||
float hcho;
|
float hcho;
|
||||||
float co2;
|
float co2;
|
||||||
|
float ice_weight;
|
||||||
float fire_percent;
|
float fire_percent;
|
||||||
bool fire_danger;
|
bool fire_danger;
|
||||||
bool human_present;
|
bool human_present;
|
||||||
@@ -48,6 +68,20 @@ static env_data_t s_env_data;
|
|||||||
static SemaphoreHandle_t s_env_data_lock = NULL;
|
static SemaphoreHandle_t s_env_data_lock = NULL;
|
||||||
static volatile bool s_ui_ready = false;
|
static volatile bool s_ui_ready = false;
|
||||||
|
|
||||||
|
static void reconfigure_twdt(uint32_t timeout_ms, uint32_t idle_core_mask)
|
||||||
|
{
|
||||||
|
const esp_task_wdt_config_t twdt_cfg = {
|
||||||
|
.timeout_ms = timeout_ms,
|
||||||
|
.idle_core_mask = idle_core_mask,
|
||||||
|
.trigger_panic = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t ret = esp_task_wdt_reconfigure(&twdt_cfg);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "TWDT reconfigure failed: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool wait_for_wifi_connected(TickType_t timeout_ticks)
|
static bool wait_for_wifi_connected(TickType_t timeout_ticks)
|
||||||
{
|
{
|
||||||
const TickType_t start_ticks = xTaskGetTickCount();
|
const TickType_t start_ticks = xTaskGetTickCount();
|
||||||
@@ -98,11 +132,14 @@ static void ui_init_task(void *arg)
|
|||||||
{
|
{
|
||||||
(void)arg;
|
(void)arg;
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "UI init start");
|
||||||
lvgl_port_lock(100 / portTICK_PERIOD_MS);
|
lvgl_port_lock(100 / portTICK_PERIOD_MS);
|
||||||
ui_init();
|
ui_init();
|
||||||
lvgl_port_unlock();
|
lvgl_port_unlock();
|
||||||
|
ESP_LOGI(TAG, "UI init done");
|
||||||
|
|
||||||
s_ui_ready = true;
|
s_ui_ready = true;
|
||||||
|
reconfigure_twdt(TWDT_NORMAL_TIMEOUT_MS, (1U << portNUM_PROCESSORS) - 1U);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +166,116 @@ static void status_task(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sntp_task(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
if (wait_for_wifi_connected(pdMS_TO_TICKS(15000))) {
|
||||||
|
esp_err_t sntp_ret = sntp_timp_sync_time(10000);
|
||||||
|
if (sntp_ret != ESP_OK) {
|
||||||
|
ESP_LOGW(TAG, "SNTP sync failed: %s", esp_err_to_name(sntp_ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hx711_task(void *arg)
|
||||||
|
{
|
||||||
|
(void)arg;
|
||||||
|
|
||||||
|
HX711 hx711(kClockPin, kDataPin, HX711::Mode::kChannelA128);
|
||||||
|
int64_t tare_sum = 0;
|
||||||
|
int tare_ok_count = 0;
|
||||||
|
|
||||||
|
// 上电空载自动去皮:当前重量作为 0g 基准
|
||||||
|
for (int i = 0; i < HX711_TARE_SAMPLES; ++i) {
|
||||||
|
int32_t raw = hx711.Read(pdMS_TO_TICKS(HX711_READ_TIMEOUT_MS));
|
||||||
|
if (raw != HX711::kUndefined) {
|
||||||
|
tare_sum += raw;
|
||||||
|
tare_ok_count++;
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(40));
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t tare_offset = 0;
|
||||||
|
if (tare_ok_count > 0) {
|
||||||
|
tare_offset = (int32_t)(tare_sum / tare_ok_count);
|
||||||
|
ESP_LOGI(TAG, "HX711 tare done: raw0=%ld, samples=%d", (long)tare_offset, tare_ok_count);
|
||||||
|
} else {
|
||||||
|
ESP_LOGW(TAG, "HX711 tare failed, use 0 as offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
float filtered_weight_g = 0.0f;
|
||||||
|
float display_weight_g = 0.0f;
|
||||||
|
bool display_initialized = false;
|
||||||
|
bool display_locked = false;
|
||||||
|
uint32_t stable_count = 0;
|
||||||
|
uint32_t err_cnt = 0;
|
||||||
|
for (;;) {
|
||||||
|
int32_t value = hx711.Read(pdMS_TO_TICKS(HX711_READ_TIMEOUT_MS));
|
||||||
|
if (value != HX711::kUndefined) {
|
||||||
|
float weight_g = ((float)(value - tare_offset)) / HX711_COUNTS_PER_GRAM;
|
||||||
|
if (fabsf(weight_g) < HX711_ZERO_DEADBAND_G) {
|
||||||
|
weight_g = 0.0f;
|
||||||
|
}
|
||||||
|
if (weight_g < 0.0f) {
|
||||||
|
weight_g = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 一阶低通,减小抖动
|
||||||
|
filtered_weight_g = filtered_weight_g * (1.0f - HX711_FILTER_ALPHA) + weight_g * HX711_FILTER_ALPHA;
|
||||||
|
float rounded_weight_g = roundf(filtered_weight_g * 100.0f) / 100.0f;
|
||||||
|
|
||||||
|
if (!display_initialized) {
|
||||||
|
display_weight_g = rounded_weight_g;
|
||||||
|
display_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float diff_from_display = fabsf(rounded_weight_g - display_weight_g);
|
||||||
|
|
||||||
|
// 稳定后锁定显示,重量明显变化时再解锁并继续更新
|
||||||
|
if (display_locked) {
|
||||||
|
if (diff_from_display >= HX711_UNLOCK_DELTA_G) {
|
||||||
|
display_locked = false;
|
||||||
|
stable_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!display_locked) {
|
||||||
|
if (diff_from_display <= HX711_STABLE_BAND_G) {
|
||||||
|
if (stable_count < HX711_STABLE_SAMPLES) {
|
||||||
|
stable_count++;
|
||||||
|
}
|
||||||
|
if (stable_count >= HX711_STABLE_SAMPLES) {
|
||||||
|
display_locked = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stable_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff_from_display >= HX711_UPDATE_MIN_STEP_G) {
|
||||||
|
display_weight_g = rounded_weight_g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_var_ice_weight(display_weight_g);
|
||||||
|
|
||||||
|
if (s_env_data_lock) {
|
||||||
|
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
|
||||||
|
s_env_data.ice_weight = display_weight_g;
|
||||||
|
xSemaphoreGive(s_env_data_lock);
|
||||||
|
}
|
||||||
|
err_cnt = 0;
|
||||||
|
} else {
|
||||||
|
if ((++err_cnt % 20) == 0) {
|
||||||
|
ESP_LOGW(TAG, "HX711 read timeout, check DOUT/SCK wiring and power");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(HX711_REFRESH_MS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void app_main(void)
|
extern "C" void app_main(void)
|
||||||
{
|
{
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
@@ -141,6 +288,9 @@ extern "C" void app_main(void)
|
|||||||
// 2. 初始化显示屏和 LVGL
|
// 2. 初始化显示屏和 LVGL
|
||||||
start_lvgl_demo();
|
start_lvgl_demo();
|
||||||
|
|
||||||
|
// UI 初始化期间,临时放宽 TWDT(仅监控 CPU0 空闲任务)
|
||||||
|
reconfigure_twdt(TWDT_UI_INIT_TIMEOUT_MS, 1U << 0);
|
||||||
|
|
||||||
// 3. 在 CPU1 上执行 UI 初始化,避免 app_main 长时间占用 CPU0
|
// 3. 在 CPU1 上执行 UI 初始化,避免 app_main 长时间占用 CPU0
|
||||||
xTaskCreatePinnedToCore(ui_init_task, "ui_init_task", 8192, NULL, 8, NULL, 1);
|
xTaskCreatePinnedToCore(ui_init_task, "ui_init_task", 8192, NULL, 8, NULL, 1);
|
||||||
set_var_food_status("良好");
|
set_var_food_status("良好");
|
||||||
@@ -154,12 +304,18 @@ extern "C" void app_main(void)
|
|||||||
set_var_system_ip(wifi_connect_get_ip());
|
set_var_system_ip(wifi_connect_get_ip());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. 独立 SNTP 对时任务
|
||||||
|
xTaskCreate(sntp_task, "sntp_task", 4096, NULL, 4, NULL);
|
||||||
|
|
||||||
|
// HX711 电子秤:GPIO13(SCK) / GPIO14(DOUT)
|
||||||
|
xTaskCreate(hx711_task, "hx711_task", 4096, NULL, 6, NULL);
|
||||||
|
|
||||||
// 初始化继电器 (独立配置每个通道)
|
// 初始化继电器 (独立配置每个通道)
|
||||||
const relay_config_t relay_cfg[RELAY_CTRL_ID_MAX] = {
|
const relay_config_t relay_cfg[RELAY_CTRL_ID_MAX] = {
|
||||||
{.pin = GPIO_NUM_9, .active_high = false},
|
|
||||||
{.pin = GPIO_NUM_10, .active_high = false},
|
|
||||||
{.pin = GPIO_NUM_11, .active_high = true},
|
|
||||||
{.pin = GPIO_NUM_12, .active_high = true},
|
{.pin = GPIO_NUM_12, .active_high = true},
|
||||||
|
{.pin = GPIO_NUM_11, .active_high = true},
|
||||||
|
{.pin = GPIO_NUM_10, .active_high = true},
|
||||||
|
{.pin = GPIO_NUM_9, .active_high = true},
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(relay_ctrl_init(relay_cfg));
|
ESP_ERROR_CHECK(relay_ctrl_init(relay_cfg));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user