界面实现,然后称重还有问题,灯改为手动控制

This commit is contained in:
Wang Beihong
2026-04-18 02:03:01 +08:00
parent 990abc210c
commit 98ea274985
22 changed files with 39154 additions and 73 deletions

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "scale_controller.c"
INCLUDE_DIRS "include"
)

View File

@@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief 称重控制器配置
*/
typedef struct {
float calibration_factor; // 校准系数
int32_t tare_offset; // 初始皮重偏移
} scale_config_t;
/**
* @brief 初始化称重控制器
* @param config 配置参数
*/
void scale_controller_init(const scale_config_t *config);
/**
* @brief 更新皮重偏移(去皮)
* @param raw_avg 测量的多次原始值平均值
*/
void scale_controller_set_tare(int32_t raw_avg);
/**
* @brief 原始值转换为重量(带简单均值滤波)
* @param raw_val 采集到的最新 ADC 原始值
* @return float 转换并滤波后的重量g
*/
float scale_controller_raw_to_weight(int16_t raw_val);
/**
* @brief 重置滤波器缓冲区
*/
void scale_controller_filter_reset(void);
/**
* @brief 设置校准系数
* @param factor 校准系数
*/
void scale_controller_set_factor(float factor);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,69 @@
#include "scale_controller.h"
#include "esp_log.h"
static const char *TAG = "scale_controller";
#define FILTER_SIZE 10 // 均值滤波窗口大小
static int32_t s_filter_buf[FILTER_SIZE] = {0};
static int s_filter_idx = 0;
static bool s_buf_filled = false;
static int32_t s_tare_offset = 0;
static float s_calib_factor = 1.0f;
// 重置滤波器缓冲区
void scale_controller_filter_reset(void)
{
for (int i = 0; i < FILTER_SIZE; i++) s_filter_buf[i] = 0;
s_filter_idx = 0;
s_buf_filled = false;
}
// 初始化函数,接受配置参数
void scale_controller_init(const scale_config_t *config)
{
if (config != NULL) {
s_tare_offset = config->tare_offset; // 设置初始皮重偏移
s_calib_factor = config->calibration_factor; // 设置校准系数
scale_controller_filter_reset();
ESP_LOGI(TAG, "Initialized with offset: %ld, factor: %f", (long)s_tare_offset, s_calib_factor);
}
}
// 更新皮重偏移(去皮)
void scale_controller_set_tare(int32_t raw_avg)
{
s_tare_offset = raw_avg; // 更新皮重偏移为当前测量的平均原始值
ESP_LOGI(TAG, "Tare updated to offset: %ld", (long)s_tare_offset);
}
// 原始值转换为重量 (带 10 点滑动均值滤波)
float scale_controller_raw_to_weight(int16_t raw_val)
{
// 1. 更新滑动滤波缓冲区
s_filter_buf[s_filter_idx] = (int32_t)raw_val;
s_filter_idx = (s_filter_idx + 1) % FILTER_SIZE;
if (s_filter_idx == 0) s_buf_filled = true;
// 2. 计算缓冲区内的平均值
int32_t sum = 0;
int count = s_buf_filled ? FILTER_SIZE : s_filter_idx;
if (count == 0) return 0.0f;
for (int i = 0; i < count; i++) {
sum += s_filter_buf[i];
}
float avg_raw = (float)sum / count;
// 3. 应用去皮和校准系数
float diff = avg_raw - (float)s_tare_offset;
return diff * s_calib_factor;
}
// 设置校准系数 (外部调用以调整称重精度)
void scale_controller_set_factor(float factor)
{
s_calib_factor = factor; // 更新校准系数
ESP_LOGI(TAG, "Calibration factor updated: %f", factor);
}

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "sgm8031_use.c"
INCLUDE_DIRS "include"
REQUIRES esp-idf-lib__sgm58031)

View File

@@ -0,0 +1,61 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <esp_err.h>
/**
* @brief 数据结构体:存放重量和电压值
*/
typedef struct {
float weight; // 校准后的重量值
} scale_data_t;
/**
* @brief 初始化 SGM58031 ADC 以及 I2C 设备
*
* @param i2c_port I2C外设端口号通常为 0
* @param sda_pin SDA 引脚号
* @param scl_pin SCL 引脚号
* @return esp_err_t 初始化结果
*/
esp_err_t sgm8031_use_init(int i2c_port, int sda_pin, int scl_pin);
/**
* @brief 触发单次转换并读取此时的重量和电压值
*
* @param out_data 读取到的数据将会存放到这边
* @return esp_err_t
*/
esp_err_t sgm8031_use_read_data(scale_data_t *out_data);
/**
* @brief 去皮(空载归零)
* 调用时保证秤面没有物品,系统会读取多次后均值认定为现在的零点基准值。
*
* @return esp_err_t
*/
esp_err_t sgm8031_use_tare(void);
/**
* @brief 设置称重传感器的校准系数(即:实际重量 / ADC变化量
*
* @param factor 浮点校准系数
*/
void sgm8031_use_set_calibration_factor(float factor);
/**
* @brief (调试用)直接读取最原始的差分 ADC 值
*
* @param raw_out 输出的原始ADC整数值
* @return esp_err_t
*/
esp_err_t sgm8031_use_read_raw_weight(int16_t *raw_out);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,85 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "sgm8031_use.h"
#include "sgm58031.h"
static const char *TAG = "sgm8031_use";
static i2c_dev_t s_device;
static bool s_initialized = false;
esp_err_t sgm8031_use_init(int i2c_port, int sda_pin, int scl_pin)
{
// Initialize I2C driver if not already done. (i2cdev_init doesn't hurt to call multiple times)
ESP_ERROR_CHECK_WITHOUT_ABORT(i2cdev_init());
memset(&s_device, 0, sizeof(i2c_dev_t));
// 使用 GND 地址针脚
esp_err_t err = sgm58031_init_desc(&s_device, SGM58031_ADDR_GND, i2c_port, sda_pin, scl_pin);
if (err != ESP_OK) {
ESP_LOGE(TAG, "SGM58031 init desc failed");
return err;
}
uint8_t id, version;
if (sgm58031_get_chip_id(&s_device, &id, &version) == ESP_OK) {
ESP_LOGI(TAG, "SGM58031 Found! ID: %d, Version: %d", id, version);
} else {
ESP_LOGW(TAG, "Failed to get SGM58031 Chip ID");
}
// 设置为单次转换模式,以便我们在不同通道间切换
ESP_ERROR_CHECK_WITHOUT_ABORT(sgm58031_set_conv_mode(&s_device, SGM58031_CONV_MODE_SINGLE_SHOT));
ESP_ERROR_CHECK_WITHOUT_ABORT(sgm58031_set_data_rate(&s_device, SGM58031_DATA_RATE_100)); // 适当的速度 100SPS
s_initialized = true;
return ESP_OK;
}
// 内部函数读取指定通道和增益下的ADC值
static esp_err_t read_channel(sgm58031_mux_t mux, sgm58031_gain_t gain, int16_t *out_val)
{
if (!s_initialized) return ESP_ERR_INVALID_STATE;
// 配置 MUX 和 增益
esp_err_t err = sgm58031_set_input_mux(&s_device, mux);
if (err != ESP_OK) return err;
err = sgm58031_set_gain(&s_device, gain);
if (err != ESP_OK) return err;
// 启动单次转换
err = sgm58031_start_conversion(&s_device);
if (err != ESP_OK) return err;
// 直接延时足够的时间跳过 busy 检查 (8 SPS 时大约 125ms100SPS只需 10ms我们延时 50ms 保底)
vTaskDelay(pdMS_TO_TICKS(50));
// 读取值
return sgm58031_get_value(&s_device, out_val);
}
esp_err_t sgm8031_use_read_data(scale_data_t *out_data)
{
if (out_data == NULL) return ESP_ERR_INVALID_ARG;
int16_t weight_raw = 0;
esp_err_t err = read_channel(SGM58031_MUX_AIN0_AIN1, SGM58031_GAIN_0V256, &weight_raw);
if (err != ESP_OK) return err;
out_data->weight = (float)weight_raw; // 现在直接输出原始值供外部处理
return ESP_OK;
}
esp_err_t sgm8031_use_tare(void)
{
// 该函数已被外部 controller 取代,仅作为兼容占位或直接废弃
return ESP_OK;
}
void sgm8031_use_set_calibration_factor(float factor)
{
// 该函数已被外部 controller 取代
}

View File

@@ -13,6 +13,10 @@
"styles.h",
"ui.c",
"ui.h",
"ui_font_chinese32.c",
"ui_font_chinese64.c",
"ui_font_num.c",
"ui_font_num2.c",
"vars.h"
]
}

View File

@@ -5,7 +5,12 @@
#ifdef __cplusplus
extern "C" {
#endif
#endif
extern const lv_font_t ui_font_num;
extern const lv_font_t ui_font_num2;
extern const lv_font_t ui_font_chinese64;
extern const lv_font_t ui_font_chinese32;
#ifndef EXT_FONT_DESC_T
#define EXT_FONT_DESC_T

View File

@@ -13,7 +13,7 @@
objects_t objects;
static const char *screen_names[] = { "Main" };
static const char *object_names[] = { "main" };
static const char *object_names[] = { "main", "obj0", "obj1", "obj2" };
//
// Event handlers
@@ -32,14 +32,36 @@ void create_screen_main() {
objects.main = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 240, 240);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff075d00), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
{
lv_obj_t *parent_obj = obj;
{
lv_obj_t *obj = lv_label_create(parent_obj);
lv_obj_set_pos(obj, 75, 103);
objects.obj0 = obj;
lv_obj_set_pos(obj, 217, 123);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_text(obj, "Hello, world!");
lv_obj_set_style_text_font(obj, &ui_font_num, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "g");
}
{
lv_obj_t *obj = lv_label_create(parent_obj);
objects.obj1 = obj;
lv_obj_set_pos(obj, 5, 94);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_style_text_font(obj, &ui_font_num2, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(obj, lv_color_hex(0xffffe503), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_align(obj, LV_TEXT_ALIGN_RIGHT, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "");
}
{
lv_obj_t *obj = lv_label_create(parent_obj);
objects.obj2 = obj;
lv_obj_set_pos(obj, 40, 7);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_style_text_font(obj, &ui_font_chinese32, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "智能电子称");
}
}
@@ -49,6 +71,15 @@ void create_screen_main() {
void tick_screen_main() {
void *flowState = getFlowState(0, 0);
(void)flowState;
{
const char *new_val = evalTextProperty(flowState, 2, 3, "Failed to evaluate Text in Label widget");
const char *cur_val = lv_label_get_text(objects.obj1);
if (strcmp(new_val, cur_val) != 0) {
tick_value_change_obj = objects.obj1;
lv_label_set_text(objects.obj1, new_val);
tick_value_change_obj = NULL;
}
}
}
typedef void (*tick_screen_func_t)();
@@ -67,6 +98,10 @@ void tick_screen_by_id(enum ScreensEnum screenId) {
//
ext_font_desc_t fonts[] = {
{ "Num", &ui_font_num },
{ "Num2", &ui_font_num2 },
{ "chinese64", &ui_font_chinese64 },
{ "chinese32", &ui_font_chinese32 },
#if LV_FONT_MONTSERRAT_8
{ "MONTSERRAT_8", &lv_font_montserrat_8 },
#endif

View File

@@ -17,6 +17,9 @@ enum ScreensEnum {
typedef struct _objects_t {
lv_obj_t *main;
lv_obj_t *obj0;
lv_obj_t *obj1;
lv_obj_t *obj2;
} objects_t;
extern objects_t objects;

View File

@@ -5,25 +5,33 @@
#include "vars.h"
// ASSETS DEFINITION
const uint8_t assets[332] = {
const uint8_t assets[460] = {
0x7E, 0x45, 0x45, 0x5A, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xF0, 0x00, 0xF0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x08, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x30, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x31, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, 0x00, 0x10, 0x00, 0x00, 0x00,
0x2C, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x30, 0x75, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x31, 0x75, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x30, 0x75, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x30, 0x75, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x00, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
@@ -31,6 +39,7 @@ const uint8_t assets[332] = {
native_var_t native_vars[] = {
{ NATIVE_VAR_TYPE_NONE, 0, 0 },
{ NATIVE_VAR_TYPE_FLOAT, get_var_weigt_ui, set_var_weigt_ui },
};
ActionExecFunc actions[] = {

View File

@@ -9,7 +9,7 @@
extern "C" {
#endif
extern const uint8_t assets[332];
extern const uint8_t assets[460];
void ui_init();
void ui_tick();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

3293
components/ui/ui_font_num.c Normal file

File diff suppressed because it is too large Load Diff

11151
components/ui/ui_font_num2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,13 @@
#include <string.h>
#include <stdint.h>
#include "vars.h"
float weigt_ui;
float get_var_weigt_ui() {
return weigt_ui;
}
void set_var_weigt_ui(float value) {
weigt_ui = value;
}

View File

@@ -16,7 +16,10 @@ enum FlowGlobalVariables {
FLOW_GLOBAL_VARIABLE_NONE
};
// Native global variables
// Native global variables
extern float get_var_weigt_ui();
extern void set_var_weigt_ui(float value);
#ifdef __cplusplus
}

View File

@@ -2,7 +2,38 @@
extern "C" {
#endif
void ws2812_start_task(void);
#include <stdint.h>
#include "esp_err.h"
// 预设颜色枚举
typedef enum {
WS2812_COLOR_RED = 0,
WS2812_COLOR_GREEN,
WS2812_COLOR_BLUE,
WS2812_COLOR_YELLOW,
WS2812_COLOR_CYAN,
WS2812_COLOR_MAGENTA,
WS2812_COLOR_WHITE,
WS2812_COLOR_ORANGE,
WS2812_COLOR_PURPLE,
WS2812_COLOR_PINK,
WS2812_COLOR_LIME,
WS2812_COLOR_SKYBLUE,
WS2812_COLOR_OFF,
WS2812_COLOR_MAX
} ws2812_color_t;
// 初始化 LED调用一次
esp_err_t ws2812_init(void);
// 设置 RGB 颜色0-255
esp_err_t ws2812_set_color(uint8_t r, uint8_t g, uint8_t b);
// 使用预设颜色快速设置
esp_err_t ws2812_set_preset_color(ws2812_color_t color);
// 熄灭 LED
esp_err_t ws2812_off(void);
#ifdef __cplusplus
}

View File

@@ -1,3 +1,5 @@
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -10,6 +12,55 @@ extern "C" {
#include "esp_log.h"
#include "esp_err.h"
// 提前声明 ws2812_set_color避免隐式声明
esp_err_t ws2812_set_color(uint8_t r, uint8_t g, uint8_t b);
// 预设颜色枚举
typedef enum {
WS2812_COLOR_RED = 0,
WS2812_COLOR_GREEN,
WS2812_COLOR_BLUE,
WS2812_COLOR_YELLOW,
WS2812_COLOR_CYAN,
WS2812_COLOR_MAGENTA,
WS2812_COLOR_WHITE,
WS2812_COLOR_ORANGE,
WS2812_COLOR_PURPLE,
WS2812_COLOR_PINK,
WS2812_COLOR_LIME,
WS2812_COLOR_SKYBLUE,
WS2812_COLOR_OFF,
WS2812_COLOR_MAX
} ws2812_color_t;
// 预设颜色表GRB 顺序)
static const uint8_t ws2812_color_table[WS2812_COLOR_MAX][3] = {
{0, 50, 0}, // RED (G,R,B)
{50, 0, 0}, // GREEN
{0, 0, 50}, // BLUE
{50, 50, 0}, // YELLOW
{50, 0, 50}, // CYAN
{0, 50, 50}, // MAGENTA
{50, 50, 50}, // WHITE
{25, 50, 0}, // ORANGE
{25, 0, 50}, // PURPLE
{0, 25, 50}, // PINK
{50, 25, 0}, // LIME
{50, 0, 25}, // SKYBLUE
{0, 0, 0}, // OFF
};
// 快捷设置预设颜色接口
esp_err_t ws2812_set_preset_color(ws2812_color_t color)
{
if (color < 0 || color >= WS2812_COLOR_MAX) {
return ESP_ERR_INVALID_ARG;
}
const uint8_t *grb = ws2812_color_table[color];
// 注意 GRB 顺序
return ws2812_set_color(grb[1], grb[0], grb[2]);
}
static const char *TAG = "led_strip";
// --- 针对 ESP32-C3 和单颗 LED 的配置 ---
@@ -30,8 +81,14 @@ static const char *TAG = "led_strip";
// 内存块大小:单颗 LED 需要的数据非常少,设为 0 让驱动自动分配最合适的内存
#define LED_STRIP_MEMORY_BLOCK_WORDS 0
led_strip_handle_t configure_led(void)
static led_strip_handle_t s_led_strip = NULL;
esp_err_t ws2812_init(void)
{
if (s_led_strip) {
return ESP_OK; // 已初始化
}
// 1. LED 灯带通用配置
led_strip_config_t strip_config = {
.strip_gpio_num = LED_STRIP_GPIO_PIN, // GPIO 0
@@ -54,64 +111,45 @@ led_strip_handle_t configure_led(void)
};
// 3. 创建 LED 灯带对象
led_strip_handle_t led_strip;
// 初始化 RMT 设备
esp_err_t ret = led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip);
esp_err_t ret = led_strip_new_rmt_device(&strip_config, &rmt_config, &s_led_strip);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to create LED strip object: %s", esp_err_to_name(ret));
while (1); // 初始化失败则卡死
s_led_strip = NULL;
return ret;
}
ESP_LOGI(TAG, "Created LED strip object with RMT backend on GPIO %d", LED_STRIP_GPIO_PIN);
return led_strip;
return ESP_OK;
}
static void ws2812_blink_task(void *pvParameters)
esp_err_t ws2812_set_color(uint8_t r, uint8_t g, uint8_t b)
{
(void)pvParameters;
// 初始化 LED 灯带
led_strip_handle_t led_strip = configure_led();
uint8_t r = 0, g = 0, b = 0;
int color_state = 0; // 0:红, 1:绿, 2:蓝
ESP_LOGI(TAG, "Start RGB cycling");
while (1) {
// 根据状态设置颜色
if (color_state == 0) {
r = 50; g = 0; b = 0; // 红色
ESP_LOGI(TAG, "Color: RED");
} else if (color_state == 1) {
r = 0; g = 50; b = 0; // 绿色
ESP_LOGI(TAG, "Color: GREEN");
} else {
r = 0; g = 0; b = 50; // 蓝色
ESP_LOGI(TAG, "Color: BLUE");
}
// 设置像素 (索引0, R, G, B)
ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, 0, r, g, b));
// 刷新显示
ESP_ERROR_CHECK(led_strip_refresh(led_strip));
// 更新状态0->1->2->0...
color_state = (color_state + 1) % 3;
// 延时 500ms
vTaskDelay(pdMS_TO_TICKS(1600));
if (!s_led_strip) {
ESP_LOGE(TAG, "LED strip not initialized");
return ESP_ERR_INVALID_STATE;
}
esp_err_t ret = led_strip_set_pixel(s_led_strip, 0, r, g, b);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set pixel: %s", esp_err_to_name(ret));
return ret;
}
ret = led_strip_refresh(s_led_strip);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to refresh strip: %s", esp_err_to_name(ret));
return ret;
}
return ESP_OK;
}
void ws2812_start_task(void)
// 熄灭 LED快捷接口
esp_err_t ws2812_off(void)
{
BaseType_t ret = xTaskCreate(ws2812_blink_task, "ws2812_blink_task", 4096, NULL, 5, NULL);
if (ret != pdPASS) {
ESP_LOGE(TAG, "Failed to create ws2812 blink task");
}
return ws2812_set_color(0, 0, 0);
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,3 +1,3 @@
idf_component_register(SRCS "main.cpp"
INCLUDE_DIRS "."
REQUIRES ws2812 wifi-connect esp_lvgl_port lvgl_st7789_use ui)
REQUIRES sgm8031_use ws2812 wifi-connect esp_lvgl_port scale_controller lvgl_st7789_use ui )

View File

@@ -2,13 +2,18 @@
#include "freertos/task.h"
#include "wifi-connect.h"
#include "ws2812.h"
#include "esp_lvgl_port.h" // 包含 LVGL 端口头文件,提供 LVGL 相关的类型定义和函数声明
#include "lvgl_st7789_use.h" // 使用EEZStudio提供的LVGL和ST7789驱动便于后续扩展
#include "ui.h" // 使用EEZStudio提供的ui组件便于后续扩展
#include "screens.h" // 包含屏幕ID定义
#include "esp_lvgl_port.h" // 包含 LVGL 端口头文件,提供 LVGL 相关的类型定义和函数声明
#include "lvgl_st7789_use.h" // 使用EEZStudio提供的LVGL和ST7789驱动便于后续扩展
#include "ui.h" // 使用EEZStudio提供的ui组件便于后续扩展
#include "vars.h" // 包含全局变量定义和访问函数
#include "screens.h" // 包含屏幕ID定义
#include "sgm8031_use.h" // 引入SGM58031 ADC 硬件包装
#include "scale_controller.h" // 接入独立称重控制逻辑模块
#include "esp_log.h"
static void ui_task(void *arg); // 声明UI更新任务函数
static const char *MAIN_TAG = "main";
static void scale_task(void *arg); // 声明称重读取任务函数
static void ui_task(void *arg); // 声明UI更新任务函数
extern "C" void app_main(void)
{
@@ -21,7 +26,36 @@ extern "C" void app_main(void)
lvgl_port_unlock();
// 创建一个 FreeRTOS 任务来更新 UI 显示(字符串拼接需要更多栈空间)
xTaskCreate(ui_task, "ui_task", 4096, NULL, 10, NULL);
ws2812_start_task(); // 启动 WS2812 LED 灯控制任务,大小为 4096 字节,优先级为 5
// 初始化称重传感器硬件。
if (sgm8031_use_init(0, 4, 5) == ESP_OK)
{
// 根据 20Kg 量程初步估算系数 (20000g / 844 ADC)
scale_config_t cfg = {.calibration_factor = 23.69f, .tare_offset = 0};
scale_controller_init(&cfg);
printf("Hardware init OK, starting scale task...\n");
// 开启一个后台任务专门读取重量数据
xTaskCreate(scale_task, "scale_task", 4096, NULL, 5, NULL);
}
else
{
printf("SGM58031 hardware init Failed!\n");
}
// 初始化 WS2812 LED 控制器并设置初始颜色为白色
if (ws2812_init() == ESP_OK)
{
ws2812_set_preset_color(WS2812_COLOR_WHITE);
vTaskDelay(pdMS_TO_TICKS(2000)); // 等待 2 秒后切换到绿色,表示系统已准备就绪
ws2812_off(); // 直接熄灭 LED表示系统已准备就绪
}
else
{
printf("ws2812 init failed\n");
}
for (;;)
{
vTaskDelay(100000);
@@ -47,4 +81,52 @@ static void ui_task(void *arg)
lvgl_port_unlock();
vTaskDelay(pdMS_TO_TICKS(20));
}
}
}
/**
* @brief 称重传感器数据采集任务
*/
static void scale_task(void *arg)
{
(void)arg;
scale_data_t data;
int32_t tare_sum = 0;
const int tare_samples = 15;
const int discard_samples = 5;
// --- 在任务开始初进行异步去皮 ---
printf("【任务】正在去皮,请保持秤面空载...\n");
for (int i = 0; i < (tare_samples + discard_samples); i++)
{
if (sgm8031_use_read_data(&data) == ESP_OK)
{
if (i >= discard_samples)
{
tare_sum += (int32_t)data.weight;
}
}
vTaskDelay(pdMS_TO_TICKS(60));
}
scale_controller_set_tare(tare_sum / tare_samples);
printf("【任务】去皮完成!开始正常读取数据...\n");
for (;;)
{
if (sgm8031_use_read_data(&data) == ESP_OK)
{
// 通过 Controller 处理算法层面的数据
float final_weight = scale_controller_raw_to_weight((int16_t)data.weight);
// 限制为1位小数避免UI刷新过快和末位跳动
final_weight = (float)((int)(final_weight * 10 + 0.5f)) / 10.0f;
printf("【称重数据】原始ADC: %6d, 最终重量: %8.2f g\n", (int)data.weight, final_weight);
set_var_weigt_ui(final_weight); // 将读取到的重量数据同步给 UI
}
else
{
ESP_LOGW(MAIN_TAG, "读取传感器失败");
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}