编程技术分享

分享编程知识,探讨技术创新

0%

简介:3D打印笔,可以实现立体画图功能,esp32模组开发,电压5-12伏,温度50-220℃,可以使用typec供电,DC头供电。

好的,作为一名高级嵌入式软件开发工程师,很高兴能为您详细解析这款基于ESP32的3D打印笔嵌入式系统的软件架构设计与实现。我们将从需求分析出发,深入探讨系统架构、模块设计、关键技术,并提供详尽的C代码示例,确保代码设计架构的可靠性、高效性和可扩展性,并结合实践经验进行验证。
关注微信公众号,提前获取相关推文

项目简介回顾:

  • 产品: 3D打印笔
  • 核心: ESP32模组
  • 功能: 立体绘画
  • 电压: 5-12V (Type-C/DC供电)
  • 温度: 50-220℃可调

一、需求分析与系统架构设计

1. 需求分析

  • 核心功能:
    • 温度控制: 精确控制笔头温度在50-220℃范围内,并保持稳定。
    • 挤出控制: 控制耗材(如PLA、ABS)的挤出速度和启停,实现流畅的线条绘制。
    • 用户界面: 通过按键和显示屏 (OLED/LCD) 提供用户交互,包括温度设置、模式选择、状态显示等。
    • 电源管理: 兼容Type-C和DC电源输入,并进行电压检测和保护。
  • 非功能需求:
    • 可靠性: 系统运行稳定可靠,避免死机、温度失控等问题。
    • 高效性: 响应速度快,温度控制和挤出控制实时性好。
    • 可扩展性: 软件架构易于扩展新功能,如固件升级、连接APP等。
    • 易维护性: 代码结构清晰,模块化设计,便于后期维护和升级。
    • 安全性: 防止过热保护,电源异常保护。

2. 系统架构设计

基于以上需求,我们采用分层架构设计,将系统软件划分为多个层次,每一层专注于特定的功能,层与层之间通过定义良好的接口进行通信。这种架构具有良好的模块化、可维护性和可扩展性。

系统架构图:

1
2
3
4
5
6
7
8
9
10
11
12
+---------------------+
| Application Layer | (应用层)
+---------------------+
| Business Logic Layer | (业务逻辑层)
+---------------------+
| Operating System Layer| (操作系统层 - FreeRTOS) (可选,但强烈推荐)
+---------------------+
| Hardware Abstraction| (硬件抽象层 - HAL)
| Layer (HAL) |
+---------------------+
| Hardware | (硬件层 - ESP32, 传感器, 执行器)
+---------------------+

各层职责:

  • 硬件层 (Hardware Layer): 物理硬件,包括ESP32芯片、温度传感器、加热器、挤出电机、按键、显示屏、电源管理芯片等。
  • 硬件抽象层 (HAL - Hardware Abstraction Layer): 提供对硬件的抽象接口,隐藏底层硬件差异。例如,统一的GPIO、ADC、SPI、I2C、PWM等接口,方便上层调用,并提高代码的可移植性。
  • 操作系统层 (OS Layer - FreeRTOS): (可选,但强烈推荐)使用实时操作系统FreeRTOS,提供任务调度、资源管理、同步机制等,使得系统可以并发执行多个任务,提高系统实时性和响应性。
  • 业务逻辑层 (Business Logic Layer): 实现3D打印笔的核心业务逻辑,包括:
    • 温度控制模块: PID算法实现精确温度控制。
    • 挤出控制模块: 控制电机驱动器,实现挤出速度和启停控制。
    • 用户界面管理模块: 处理按键输入,更新显示屏内容,实现用户交互逻辑。
    • 电源管理模块: 检测电源类型,监控电压,进行电源保护。
    • 配置管理模块: 存储和加载用户配置参数,如温度预设值等。
  • 应用层 (Application Layer): 提供用户操作入口,调用业务逻辑层提供的接口,完成用户指令。例如,启动/停止打印、设置温度、调整挤出速度等。

二、模块设计与详细代码实现

1. 硬件抽象层 (HAL) 设计与实现

HAL层旨在隔离硬件细节,提供统一的接口给上层使用。我们定义以下HAL模块:

  • HAL_GPIO: GPIO (通用输入/输出) 控制
  • HAL_ADC: ADC (模数转换器) 控制
  • HAL_PWM: PWM (脉冲宽度调制) 控制
  • HAL_SPI: SPI (串行外设接口) 控制 (用于显示屏,如果使用SPI接口)
  • HAL_I2C: I2C (内部集成电路) 控制 (用于温度传感器,如果使用I2C接口)
  • HAL_Timer: 定时器控制 (用于PID控制,时间基准)

HAL 头文件 (hal.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef HAL_H
#define HAL_H

#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "driver/ledc.h" // PWM for LED Control
#include "driver/spi_master.h"
#include "driver/i2c.h"
#include "driver/timer.h"

// ----- GPIO HAL -----
typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_INPUT_OUTPUT
} hal_gpio_mode_t;

typedef enum {
GPIO_PULLUP,
GPIO_PULLDOWN,
GPIO_PULL_NONE
} hal_gpio_pull_mode_t;

esp_err_t hal_gpio_init(gpio_num_t gpio_num, hal_gpio_mode_t mode, hal_gpio_pull_mode_t pull_mode);
esp_err_t hal_gpio_set_level(gpio_num_t gpio_num, int level);
int hal_gpio_get_level(gpio_num_t gpio_num);

// ----- ADC HAL -----
esp_err_t hal_adc_init(adc_unit_t adc_unit, adc_channel_t adc_channel);
int hal_adc_read_voltage(adc_unit_t adc_unit, adc_channel_t adc_channel);

// ----- PWM HAL ----- (Using LEDC driver for PWM in ESP-IDF)
esp_err_t hal_pwm_init(ledc_channel_t channel, ledc_timer_t timer, gpio_num_t pin, uint32_t freq_hz, uint32_t duty_resolution);
esp_err_t hal_pwm_set_duty(ledc_channel_t channel, uint32_t duty);
esp_err_t hal_pwm_update_duty(ledc_channel_t channel);

// ----- SPI HAL ----- (Example for SPI Display)
esp_err_t hal_spi_init(spi_host_device_t host, gpio_num_t miso_pin, gpio_num_t mosi_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin);
esp_err_t hal_spi_transfer(spi_host_device_t host, const uint8_t *data, size_t len);

// ----- I2C HAL ----- (Example for I2C Temperature Sensor)
esp_err_t hal_i2c_init(i2c_port_t i2c_num, gpio_num_t scl_pin, gpio_num_t sda_pin, uint32_t clk_speed_hz);
esp_err_t hal_i2c_write_bytes(i2c_port_t i2c_num, uint8_t slave_addr, const uint8_t *data, size_t len);
esp_err_t hal_i2c_read_bytes(i2c_port_t i2c_num, uint8_t slave_addr, uint8_t *data, size_t len);

// ----- Timer HAL -----
esp_err_t hal_timer_init(timer_group_t timer_group, timer_idx_t timer_idx, double timer_period_sec);
esp_err_t hal_timer_start(timer_group_t timer_group, timer_idx_t timer_idx);
esp_err_t hal_timer_get_counter_value(timer_group_t timer_group, timer_idx_t timer_idx, uint64_t *timer_count);

#endif // HAL_H

HAL 源文件 (hal.c):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include "hal.h"
#include "esp_log.h"

static const char *TAG = "HAL";

// ----- GPIO HAL Implementation -----
esp_err_t hal_gpio_init(gpio_num_t gpio_num, hal_gpio_mode_t mode, hal_gpio_pull_mode_t pull_mode) {
gpio_config_t io_conf;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pin_bit_mask = (1ULL << gpio_num);

if (mode == GPIO_MODE_INPUT) {
io_conf.mode = GPIO_MODE_INPUT;
} else if (mode == GPIO_MODE_OUTPUT) {
io_conf.mode = GPIO_MODE_OUTPUT;
} else if (mode == GPIO_MODE_INPUT_OUTPUT) {
io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
} else {
ESP_LOGE(TAG, "Invalid GPIO mode");
return ESP_FAIL;
}

if (pull_mode == GPIO_PULLUP) {
io_conf.pull_mode = GPIO_PULLUP_ONLY;
} else if (pull_mode == GPIO_PULLDOWN) {
io_conf.pull_mode = GPIO_PULLDOWN_ONLY;
} else {
io_conf.pull_mode = GPIO_PULLUP_PULLDOWN; // Or GPIO_PULL_NONE if needed.
}

esp_err_t ret = gpio_config(&io_conf);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "GPIO config failed for pin %d, error: %d", gpio_num, ret);
}
return ret;
}

esp_err_t hal_gpio_set_level(gpio_num_t gpio_num, int level) {
return gpio_set_level(gpio_num, level);
}

int hal_gpio_get_level(gpio_num_t gpio_num) {
return gpio_get_level(gpio_num);
}

// ----- ADC HAL Implementation -----
esp_err_t hal_adc_init(adc_unit_t adc_unit, adc_channel_t adc_channel) {
adc1_config_width(ADC_WIDTH_BIT_DEFAULT); // Or ADC_WIDTH_BIT_12
adc1_config_atten(ADC_ATTEN_DB_11); // Or ADC_ATTEN_DB_0, DB_2_5, DB_6
esp_err_t ret = adc1_config_channel_atten(adc_channel, ADC_ATTEN_DB_11);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "ADC channel config failed, error: %d", ret);
}
return ret;
}

int hal_adc_read_voltage(adc_unit_t adc_unit, adc_channel_t adc_channel) {
return adc1_get_raw(adc_channel); // Return raw ADC value. Needs conversion to voltage in higher layer.
}

// ----- PWM HAL Implementation ----- (Using LEDC driver)
esp_err_t hal_pwm_init(ledc_channel_t channel, ledc_timer_t timer, gpio_num_t pin, uint32_t freq_hz, uint32_t duty_resolution) {
ledc_timer_config_t timer_conf = {
.speed_mode = LEDC_HIGH_SPEED_MODE, // Or LEDC_LOW_SPEED_MODE
.duty_resolution = duty_resolution,
.timer_num = timer,
.freq_hz = freq_hz,
.clk_cfg = LEDC_AUTO_CLK,
};
esp_err_t ret_timer = ledc_timer_config(&timer_conf);
if (ret_timer != ESP_OK) {
ESP_LOGE(TAG, "PWM timer config failed, error: %d", ret_timer);
return ret_timer;
}

ledc_channel_config_t channel_conf = {
.speed_mode = LEDC_HIGH_SPEED_MODE, // Or LEDC_LOW_SPEED_MODE
.channel = channel,
.timer_sel = timer,
.intr_enable = false,
.duty = 0, // Initial duty cycle
.gpio_num = pin,
.hpoint = 0,
};
esp_err_t ret_channel = ledc_channel_config(&channel_conf);
if (ret_channel != ESP_OK) {
ESP_LOGE(TAG, "PWM channel config failed, error: %d", ret_channel);
}
return ret_channel;
}

esp_err_t hal_pwm_set_duty(ledc_channel_t channel, uint32_t duty) {
return ledc_set_duty(LEDC_HIGH_SPEED_MODE, channel, duty); // Or LEDC_LOW_SPEED_MODE
}

esp_err_t hal_pwm_update_duty(ledc_channel_t channel) {
return ledc_update_duty(LEDC_HIGH_SPEED_MODE, channel); // Or LEDC_LOW_SPEED_MODE
}

// ----- SPI HAL Implementation ----- (Example for SPI Display)
esp_err_t hal_spi_init(spi_host_device_t host, gpio_num_t miso_pin, gpio_num_t mosi_pin, gpio_num_t sclk_pin, gpio_num_t cs_pin) {
spi_bus_config_t buscfg = {
.miso_io_num=miso_pin,
.mosi_io_num=mosi_pin,
.sclk_io_num=sclk_pin,
.quadwp_io_num=-1,
.quadhd_io_num=-1,
.max_transfer_sz=4096,
};
esp_err_t ret_bus = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
if (ret_bus != ESP_OK) {
ESP_LOGE(TAG, "SPI bus init failed, error: %d", ret_bus);
return ret_bus;
}

spi_device_interface_config_t devcfg = {
.clock_speed_hz=10*1000*1000, //Clock out at 10 MHz
.mode=0, //SPI mode 0
.spics_io_num=cs_pin, //CS pin
.queue_size=7, //We want to be able to queue 7 transactions at a time
};
spi_device_handle_t spi;
esp_err_t ret_device = spi_bus_add_device(host, &devcfg, &spi);
if (ret_device != ESP_OK) {
ESP_LOGE(TAG, "SPI device add failed, error: %d", ret_device);
spi_bus_free(host); // Cleanup bus if device creation fails
return ret_device;
}
return ESP_OK; // Assuming device handle is stored/used elsewhere. For simplicity, we are not returning it here.
}

esp_err_t hal_spi_transfer(spi_host_device_t host, const uint8_t *data, size_t len) {
spi_transaction_t t;
memset(&t, 0, sizeof(t)); //Zero out the transaction
t.length=len*8; //Len is in bytes, transaction length is in bits.
t.tx_buffer=data; //Data
esp_err_t ret = spi_device_transmit(host, &t); //Transmit!
if (ret != ESP_OK) {
ESP_LOGE(TAG, "SPI transfer failed, error: %d", ret);
}
return ret;
}


// ----- I2C HAL Implementation ----- (Example for I2C Temperature Sensor)
esp_err_t hal_i2c_init(i2c_port_t i2c_num, gpio_num_t scl_pin, gpio_num_t sda_pin, uint32_t clk_speed_hz) {
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = sda_pin;
conf.scl_io_num = scl_pin;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = clk_speed_hz;

esp_err_t ret = i2c_param_config(i2c_num, &conf);
if (ret != ESP_OK) return ret;
return i2c_driver_install(i2c_num, conf.mode, 0, 0, 0);
}

esp_err_t hal_i2c_write_bytes(i2c_port_t i2c_num, uint8_t slave_addr, const uint8_t *data, size_t len) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_write(cmd, data, len, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); // Timeout 1s
i2c_cmd_link_delete(cmd);
return ret;
}

esp_err_t hal_i2c_read_bytes(i2c_port_t i2c_num, uint8_t slave_addr, uint8_t *data, size_t len) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (slave_addr << 1) | I2C_MASTER_READ, true);
i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK); // NACK after last byte
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_PERIOD_MS); // Timeout 1s
i2c_cmd_link_delete(cmd);
return ret;
}

// ----- Timer HAL Implementation -----
esp_err_t hal_timer_init(timer_group_t timer_group, timer_idx_t timer_idx, double timer_period_sec) {
timer_config_t config = {
.alarm_en = TIMER_ALARM_DIS,
.counter_en = TIMER_PAUSE,
.intr_arm = false,
.auto_reload = TIMER_AUTORELOAD_EN,
.counter_dir = TIMER_COUNT_UP,
.divider = 80, // Assuming 80MHz APB clock, divider 80 gives 1MHz timer clock
};
timer_init(timer_group, timer_idx, &config);
timer_set_counter_value(timer_group, timer_idx, 0);
timer_set_alarm_value(timer_group, timer_idx, (uint64_t)(timer_period_sec * 1000000.0)); // Convert sec to us
return ESP_OK;
}

esp_err_t hal_timer_start(timer_group_t timer_group, timer_idx_t timer_idx) {
return timer_start(timer_group, timer_idx);
}

esp_err_t hal_timer_get_counter_value(timer_group_t timer_group, timer_idx_t timer_idx, uint64_t *timer_count) {
return timer_get_counter_value(timer_group, timer_idx, timer_count);
}

2. 业务逻辑层 (Business Logic Layer) 模块设计与实现

2.1 温度控制模块 (temperature_control.h, temperature_control.c)

  • 功能: 读取温度传感器数据,使用PID算法控制加热器PWM占空比,实现精确温度控制。
  • 关键技术: PID控制算法,温度传感器驱动 (例如:NTC热敏电阻 + ADC,或数字温度传感器如MAX31855)。

temperature_control.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef TEMPERATURE_CONTROL_H
#define TEMPERATURE_CONTROL_H

#include "hal.h"
#include "esp_err.h"

#define TARGET_TEMPERATURE_DEFAULT 180.0f // 默认目标温度
#define TEMPERATURE_PID_PERIOD_MS 100 // PID 控制周期 100ms

typedef struct {
float kp;
float ki;
float kd;
float setpoint; // 目标温度
float integral_term; // 积分项累积
float last_error; // 上次误差
} pid_controller_t;

esp_err_t temp_control_init(void);
void temp_control_task(void *pvParameters); // 温度控制任务 (FreeRTOS)
float temp_control_get_current_temp(void);
esp_err_t temp_control_set_target_temp(float target_temp);
float temp_control_get_target_temp(void);
void temp_control_enable_heater(bool enable);

#endif // TEMPERATURE_CONTROL_H

temperature_control.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "temperature_control.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "math.h"

static const char *TAG_TEMP = "TEMP_CTRL";

// ----- 温度传感器相关配置 -----
#define TEMP_SENSOR_ADC_UNIT ADC_UNIT_1
#define TEMP_SENSOR_ADC_CHANNEL ADC_CHANNEL_6 // 根据实际硬件连接修改
#define TEMP_SENSOR_ADC_RAW_TO_TEMP_COEF 0.1 // 示例系数,需要根据实际传感器校准
#define HEATER_PWM_CHANNEL LEDC_CHANNEL_0
#define HEATER_PWM_TIMER LEDC_TIMER_0
#define HEATER_PWM_PIN GPIO_NUM_2 // 根据实际硬件连接修改
#define HEATER_PWM_FREQ_HZ 1000 // PWM 频率 1kHz
#define HEATER_PWM_DUTY_RESOLUTION LEDC_TIMER_10_BIT // 10-bit duty resolution (0-1023)

// ----- PID 控制器参数 -----
static pid_controller_t pid_controller = {
.kp = 10.0f, // 比例增益
.ki = 0.1f, // 积分增益
.kd = 0.01f, // 微分增益
.setpoint = TARGET_TEMPERATURE_DEFAULT,
.integral_term = 0.0f,
.last_error = 0.0f
};

static float current_temperature = 25.0f; // 初始环境温度
static bool heater_enabled = false;

// ----- 初始化温度控制模块 -----
esp_err_t temp_control_init(void) {
ESP_LOGI(TAG_TEMP, "Initializing Temperature Control Module...");
hal_adc_init(TEMP_SENSOR_ADC_UNIT, TEMP_SENSOR_ADC_CHANNEL);
hal_pwm_init(HEATER_PWM_CHANNEL, HEATER_PWM_TIMER, HEATER_PWM_PIN, HEATER_PWM_FREQ_HZ, HEATER_PWM_DUTY_RESOLUTION);
hal_pwm_set_duty(HEATER_PWM_CHANNEL, 0); // 初始关闭加热器
hal_pwm_update_duty(HEATER_PWM_CHANNEL);
return ESP_OK;
}

// ----- 读取温度传感器数据并转换为温度值 -----
static float read_temperature(void) {
int adc_raw_value = hal_adc_read_voltage(TEMP_SENSOR_ADC_UNIT, TEMP_SENSOR_ADC_CHANNEL);
// TODO: 根据实际温度传感器特性,将 ADC 原始值转换为温度值 (摄氏度)
// 这里需要进行传感器校准,得到准确的转换公式或查找表
// 例如,对于NTC热敏电阻,可以使用 Steinhart-Hart 方程 或 查表法
float temperature = (float)adc_raw_value * TEMP_SENSOR_ADC_RAW_TO_TEMP_COEF + 20.0f; // 示例线性转换
return temperature;
}

// ----- PID 控制算法实现 -----
static float calculate_pid(float current_temp, float setpoint) {
float error = setpoint - current_temp;
pid_controller.integral_term += error * (TEMPERATURE_PID_PERIOD_MS / 1000.0f); // 积分项累积
float derivative_term = (error - pid_controller.last_error) / (TEMPERATURE_PID_PERIOD_MS / 1000.0f); // 微分项
float output = pid_controller.kp * error + pid_controller.ki * pid_controller.integral_term + pid_controller.kd * derivative_term;
pid_controller.last_error = error;

// 限制输出范围 (PWM duty cycle 0-100%)
if (output < 0.0f) output = 0.0f;
if (output > 100.0f) output = 100.0f;
return output;
}

// ----- 温度控制任务 (FreeRTOS Task) -----
void temp_control_task(void *pvParameters) {
ESP_LOGI(TAG_TEMP, "Temperature Control Task started");
while (1) {
if (heater_enabled) {
current_temperature = read_temperature();
float pwm_duty_percent = calculate_pid(current_temperature, pid_controller.setpoint);
uint32_t pwm_duty = (uint32_t)((pwm_duty_percent / 100.0f) * ((1 << HEATER_PWM_DUTY_RESOLUTION) - 1)); // 转换为 PWM duty 值
hal_pwm_set_duty(HEATER_PWM_CHANNEL, pwm_duty);
hal_pwm_update_duty(HEATER_PWM_CHANNEL);

// 调试信息 (可以根据需要调整输出频率)
ESP_LOGD(TAG_TEMP, "Current Temp: %.2f°C, Target Temp: %.2f°C, PWM Duty: %d (%.2f%%)",
current_temperature, pid_controller.setpoint, pwm_duty, pwm_duty_percent);
} else {
hal_pwm_set_duty(HEATER_PWM_CHANNEL, 0); // 关闭加热器
hal_pwm_update_duty(HEATER_PWM_CHANNEL);
}
vTaskDelay(pdMS_TO_TICKS(TEMPERATURE_PID_PERIOD_MS)); // 控制周期
}
}

// ----- 获取当前温度 -----
float temp_control_get_current_temp(void) {
return current_temperature;
}

// ----- 设置目标温度 -----
esp_err_t temp_control_set_target_temp(float target_temp) {
if (target_temp >= 50.0f && target_temp <= 220.0f) {
pid_controller.setpoint = target_temp;
ESP_LOGI(TAG_TEMP, "Target temperature set to %.2f°C", target_temp);
return ESP_OK;
} else {
ESP_LOGE(TAG_TEMP, "Invalid target temperature: %.2f°C (Range: 50-220°C)", target_temp);
return ESP_FAIL;
}
}

// ----- 获取目标温度 -----
float temp_control_get_target_temp(void) {
return pid_controller.setpoint;
}

// ----- 使能/禁用 加热器 -----
void temp_control_enable_heater(bool enable) {
heater_enabled = enable;
if (enable) {
ESP_LOGI(TAG_TEMP, "Heater enabled");
} else {
ESP_LOGI(TAG_TEMP, "Heater disabled");
}
}

2.2 挤出控制模块 (extruder_control.h, extruder_control.c)

  • 功能: 控制挤出电机驱动器,实现耗材挤出速度和启停控制。
  • 关键技术: 电机驱动器控制 (例如:步进电机驱动器 + PWM/GPIO 控制方向和步进)。

extruder_control.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef EXTRUDER_CONTROL_H
#define EXTRUDER_CONTROL_H

#include "hal.h"
#include "esp_err.h"

#define EXTRUDER_PWM_FREQ_HZ 10000 // 挤出电机 PWM 频率 10kHz
#define EXTRUDER_SPEED_MAX 100 // 最大挤出速度 (自定义单位,例如 % of max speed)

esp_err_t extruder_control_init(void);
esp_err_t extruder_control_set_speed(uint8_t speed_percent); // 设置挤出速度 (0-100%)
esp_err_t extruder_control_start_extrude(void);
esp_err_t extruder_control_stop_extrude(void);
esp_err_t extruder_control_reverse_extrude(void); // 反向挤出 (回抽)

#endif // EXTRUDER_CONTROL_H

extruder_control.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include "extruder_control.h"
#include "esp_log.h"

static const char *TAG_EXTRUDER = "EXTRUDER_CTRL";

// ----- 挤出电机控制引脚配置 -----
#define EXTRUDER_MOTOR_PWM_CHANNEL LEDC_CHANNEL_1
#define EXTRUDER_MOTOR_PWM_TIMER LEDC_TIMER_1
#define EXTRUDER_MOTOR_PWM_PIN GPIO_NUM_4 // 根据实际硬件连接修改
#define EXTRUDER_MOTOR_DIR_PIN GPIO_NUM_5 // 方向控制引脚 (如果需要)
#define EXTRUDER_PWM_DUTY_RESOLUTION LEDC_TIMER_10_BIT // 10-bit duty resolution

// ----- 挤出速度与PWM占空比映射 -----
#define EXTRUDER_SPEED_TO_PWM_COEF 10.0f // 示例系数,需要根据实际电机和驱动器校准

static uint8_t current_speed_percent = 0; // 当前挤出速度百分比

// ----- 初始化挤出控制模块 -----
esp_err_t extruder_control_init(void) {
ESP_LOGI(TAG_EXTRUDER, "Initializing Extruder Control Module...");
hal_pwm_init(EXTRUDER_MOTOR_PWM_CHANNEL, EXTRUDER_MOTOR_PWM_TIMER, EXTRUDER_MOTOR_PWM_PIN, EXTRUDER_PWM_FREQ_HZ, EXTRUDER_PWM_DUTY_RESOLUTION);
hal_gpio_init(EXTRUDER_MOTOR_DIR_PIN, GPIO_MODE_OUTPUT, GPIO_PULL_NONE); // 初始化方向控制引脚 (如果需要)
hal_pwm_set_duty(EXTRUDER_MOTOR_PWM_CHANNEL, 0); // 初始停止挤出
hal_pwm_update_duty(EXTRUDER_MOTOR_PWM_CHANNEL);
hal_gpio_set_level(EXTRUDER_MOTOR_DIR_PIN, 0); // 初始方向 (正向)
return ESP_OK;
}

// ----- 设置挤出速度 (0-100%) -----
esp_err_t extruder_control_set_speed(uint8_t speed_percent) {
if (speed_percent <= EXTRUDER_SPEED_MAX) {
current_speed_percent = speed_percent;
uint32_t pwm_duty = (uint32_t)((float)speed_percent * EXTRUDER_SPEED_TO_PWM_COEF); // 示例线性映射
if (pwm_duty > ((1 << EXTRUDER_PWM_DUTY_RESOLUTION) - 1)) {
pwm_duty = (1 << EXTRUDER_PWM_DUTY_RESOLUTION) - 1; // 限制最大 duty
}
hal_pwm_set_duty(EXTRUDER_MOTOR_PWM_CHANNEL, pwm_duty);
hal_pwm_update_duty(EXTRUDER_MOTOR_PWM_CHANNEL);
ESP_LOGD(TAG_EXTRUDER, "Set speed: %d%%, PWM Duty: %d", speed_percent, pwm_duty);
return ESP_OK;
} else {
ESP_LOGE(TAG_EXTRUDER, "Invalid speed percentage: %d (Max: %d%%)", speed_percent, EXTRUDER_SPEED_MAX);
return ESP_FAIL;
}
}

// ----- 开始挤出 -----
esp_err_t extruder_control_start_extrude(void) {
ESP_LOGI(TAG_EXTRUDER, "Start Extruding");
return extruder_control_set_speed(current_speed_percent); // 保持当前速度
}

// ----- 停止挤出 -----
esp_err_t extruder_control_stop_extrude(void) {
ESP_LOGI(TAG_EXTRUDER, "Stop Extruding");
return extruder_control_set_speed(0); // 速度设为 0
}

// ----- 反向挤出 (回抽) -----
esp_err_t extruder_control_reverse_extrude(void) {
ESP_LOGI(TAG_EXTRUDER, "Reverse Extruding (Retract)");
hal_gpio_set_level(EXTRUDER_MOTOR_DIR_PIN, 1); // 设置反向 (根据实际硬件修改)
esp_err_t ret = extruder_control_set_speed(current_speed_percent); // 以当前速度反向挤出
vTaskDelay(pdMS_TO_TICKS(200)); // 回抽一段时间 (例如 200ms)
extruder_control_stop_extrude();
hal_gpio_set_level(EXTRUDER_MOTOR_DIR_PIN, 0); // 恢复正向
return ret;
}

2.3 用户界面管理模块 (ui_manager.h, ui_manager.c)

  • 功能: 处理按键输入,更新显示屏内容,实现用户交互逻辑。
  • 关键技术: 按键扫描/中断处理,显示屏驱动 (例如:OLED/LCD 驱动库),菜单系统设计。

ui_manager.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef UI_MANAGER_H
#define UI_MANAGER_H

#include "hal.h"
#include "esp_err.h"

#define DISPLAY_WIDTH 128 // 假设 OLED 宽度 128 pixels
#define DISPLAY_HEIGHT 64 // 假设 OLED 高度 64 pixels

typedef enum {
UI_STATE_MAIN_MENU,
UI_STATE_SET_TEMPERATURE,
UI_STATE_PRINTING
} ui_state_t;

esp_err_t ui_manager_init(void);
void ui_manager_task(void *pvParameters); // UI 管理任务 (FreeRTOS)
void ui_manager_set_state(ui_state_t state);
ui_state_t ui_manager_get_state(void);
void ui_manager_display_text(int x, int y, const char *text);
void ui_manager_clear_display(void);

#endif // UI_MANAGER_H

ui_manager.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include "ui_manager.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "stdio.h"
#include "string.h"

static const char *TAG_UI = "UI_MGR";

// ----- 按键引脚配置 -----
#define BUTTON_UP_PIN GPIO_NUM_12 // 根据实际硬件连接修改
#define BUTTON_DOWN_PIN GPIO_NUM_13 // 根据实际硬件连接修改
#define BUTTON_OK_PIN GPIO_NUM_14 // 根据实际硬件连接修改

// ----- 显示屏相关配置 ----- (假设使用 SPI OLED)
#define DISPLAY_SPI_HOST SPI2_HOST
#define DISPLAY_SPI_MISO_PIN GPIO_NUM_19 // 根据实际硬件连接修改
#define DISPLAY_SPI_MOSI_PIN GPIO_NUM_23 // 根据实际硬件连接修改
#define DISPLAY_SPI_SCLK_PIN GPIO_NUM_18 // 根据实际硬件连接修改
#define DISPLAY_SPI_CS_PIN GPIO_NUM_5 // 根据实际硬件连接修改

static ui_state_t current_ui_state = UI_STATE_MAIN_MENU;

// ----- 简单的文本显示函数 (需要根据实际 OLED 驱动库实现) -----
static void display_draw_text(int x, int y, const char *text) {
// TODO: 调用实际 OLED 驱动库的文本绘制函数
// 例如:使用 Adafruit_GFX 库 或 u8g2 库
ESP_LOGI(TAG_UI, "Display Text at (%d, %d): %s", x, y, text); // 示例输出到串口
}

static void display_clear(void) {
// TODO: 调用实际 OLED 驱动库的清屏函数
ESP_LOGI(TAG_UI, "Clear Display"); // 示例输出到串口
}


// ----- 初始化 UI 管理模块 -----
esp_err_t ui_manager_init(void) {
ESP_LOGI(TAG_UI, "Initializing UI Manager Module...");

// 初始化按键 GPIO
hal_gpio_init(BUTTON_UP_PIN, GPIO_MODE_INPUT, GPIO_PULLUP);
hal_gpio_init(BUTTON_DOWN_PIN, GPIO_MODE_INPUT, GPIO_PULLUP);
hal_gpio_init(BUTTON_OK_PIN, GPIO_MODE_INPUT, GPIO_PULLUP);

// 初始化 SPI 显示屏
hal_spi_init(DISPLAY_SPI_HOST, DISPLAY_SPI_MISO_PIN, DISPLAY_SPI_MOSI_PIN, DISPLAY_SPI_SCLK_PIN, DISPLAY_SPI_CS_PIN);

// 初始化显示屏驱动 (例如,初始化 Adafruit_GFX 或 u8g2 库)
// TODO: 初始化 OLED 驱动库 (例如: Adafruit_SSD1306_OLED oled;)
// oled.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 0x3C OLED address

display_clear(); // 清屏
return ESP_OK;
}

// ----- 按键扫描任务 (FreeRTOS Task) -----
void ui_manager_task(void *pvParameters) {
ESP_LOGI(TAG_UI, "UI Manager Task started");
ui_manager_set_state(UI_STATE_MAIN_MENU); // 初始状态为主菜单

while (1) {
// 读取按键状态
int up_btn_state = hal_gpio_get_level(BUTTON_UP_PIN);
int down_btn_state = hal_gpio_get_level(BUTTON_DOWN_PIN);
int ok_btn_state = hal_gpio_get_level(BUTTON_OK_PIN);

// 根据按键状态和当前 UI 状态处理用户输入
switch (current_ui_state) {
case UI_STATE_MAIN_MENU:
ui_manager_handle_main_menu(up_btn_state, down_btn_state, ok_btn_state);
break;
case UI_STATE_SET_TEMPERATURE:
ui_manager_handle_set_temperature_menu(up_btn_state, down_btn_state, ok_btn_state);
break;
case UI_STATE_PRINTING:
ui_manager_handle_printing_screen(up_btn_state, down_btn_state, ok_btn_state);
break;
default:
break;
}

vTaskDelay(pdMS_TO_TICKS(50)); // 按键扫描周期 50ms
}
}

// ----- 设置 UI 状态 -----
void ui_manager_set_state(ui_state_t state) {
current_ui_state = state;
ESP_LOGI(TAG_UI, "UI State changed to: %d", state);
ui_manager_update_display(); // 更新显示内容
}

// ----- 获取当前 UI 状态 -----
ui_state_t ui_manager_get_state(void) {
return current_ui_state;
}

// ----- 显示文本 -----
void ui_manager_display_text(int x, int y, const char *text) {
display_draw_text(x, y, text);
}

// ----- 清屏 -----
void ui_manager_clear_display(void) {
display_clear();
}

// ----- 根据当前 UI 状态更新显示内容 -----
void ui_manager_update_display(void) {
ui_manager_clear_display();
switch (current_ui_state) {
case UI_STATE_MAIN_MENU:
ui_manager_display_main_menu();
break;
case UI_STATE_SET_TEMPERATURE:
ui_manager_display_set_temperature_menu();
break;
case UI_STATE_PRINTING:
ui_manager_display_printing_screen();
break;
default:
ui_manager_display_text(10, 20, "Error State");
break;
}
}

// ----- 主菜单显示和按键处理 -----
void ui_manager_display_main_menu(void) {
ui_manager_display_text(10, 10, "Main Menu");
ui_manager_display_text(10, 25, "1. Set Temp");
ui_manager_display_text(10, 35, "2. Start Print");
ui_manager_display_text(10, 45, "3. Settings");
}

void ui_manager_handle_main_menu(int up_btn_state, int down_btn_state, int ok_btn_state) {
static int menu_index = 1; // 默认选中第一个菜单项

if (down_btn_state == 0) { // 按下 DOWN 键 (假设低电平有效)
menu_index++;
if (menu_index > 3) menu_index = 1; // 循环菜单
ESP_LOGI(TAG_UI, "Menu Index: %d", menu_index);
ui_manager_update_display(); // 更新显示
vTaskDelay(pdMS_TO_TICKS(150)); // 简单按键去抖
} else if (up_btn_state == 0) { // 按下 UP 键
menu_index--;
if (menu_index < 1) menu_index = 3; // 循环菜单
ESP_LOGI(TAG_UI, "Menu Index: %d", menu_index);
ui_manager_update_display();
vTaskDelay(pdMS_TO_TICKS(150));
} else if (ok_btn_state == 0) { // 按下 OK 键
ESP_LOGI(TAG_UI, "OK Button pressed, Menu Index: %d", menu_index);
switch (menu_index) {
case 1: // Set Temperature
ui_manager_set_state(UI_STATE_SET_TEMPERATURE);
break;
case 2: // Start Print
ui_manager_set_state(UI_STATE_PRINTING); // 切换到打印状态
// TODO: 启动打印逻辑 (调用挤出控制和温度控制)
break;
case 3: // Settings (预留功能)
// TODO: 进入设置菜单
break;
default:
break;
}
vTaskDelay(pdMS_TO_TICKS(150));
}
// 高亮显示当前选中的菜单项 (TODO: 需要根据实际显示库实现)
}


// ----- 设置温度菜单显示和按键处理 -----
void ui_manager_display_set_temperature_menu(void) {
float current_target_temp = temp_control_get_target_temp();
char temp_str[20];
sprintf(temp_str, "Target Temp: %.0f°C", current_target_temp);
ui_manager_display_text(10, 10, "Set Temperature");
ui_manager_display_text(10, 30, temp_str);
ui_manager_display_text(10, 50, "+/- to adjust, OK to confirm");
}

void ui_manager_handle_set_temperature_menu(int up_btn_state, int down_btn_state, int ok_btn_state) {
static float temp_step = 5.0f; // 温度调整步进值
float current_target_temp = temp_control_get_target_temp();

if (up_btn_state == 0) {
current_target_temp += temp_step;
if (current_target_temp > 220.0f) current_target_temp = 220.0f; // 限制最大温度
temp_control_set_target_temp(current_target_temp);
ui_manager_update_display();
vTaskDelay(pdMS_TO_TICKS(150));
} else if (down_btn_state == 0) {
current_target_temp -= temp_step;
if (current_target_temp < 50.0f) current_target_temp = 50.0f; // 限制最小温度
temp_control_set_target_temp(current_target_temp);
ui_manager_update_display();
vTaskDelay(pdMS_TO_TICKS(150));
} else if (ok_btn_state == 0) {
ui_manager_set_state(UI_STATE_MAIN_MENU); // 返回主菜单
vTaskDelay(pdMS_TO_TICKS(150));
}
}


// ----- 打印状态显示屏幕 -----
void ui_manager_display_printing_screen(void) {
float current_temp = temp_control_get_current_temp();
float target_temp = temp_control_get_target_temp();
char temp_str[40];
sprintf(temp_str, "Current Temp: %.1f°C", current_temp);
char target_temp_str[40];
sprintf(target_temp_str, "Target Temp: %.0f°C", target_temp);

ui_manager_display_text(10, 10, "Printing...");
ui_manager_display_text(10, 30, temp_str);
ui_manager_display_text(10, 45, target_temp_str);
}

void ui_manager_handle_printing_screen(int up_btn_state, int down_btn_state, int ok_btn_state) {
if (ok_btn_state == 0) {
ui_manager_set_state(UI_STATE_MAIN_MENU); // 返回主菜单
// TODO: 停止打印逻辑 (停止挤出和温度控制?) 或者暂停打印
vTaskDelay(pdMS_TO_TICKS(150));
}
// 打印状态下可以考虑显示更多信息,例如挤出速度、剩余时间等 (如果功能扩展)
}

2.4 电源管理模块 (power_manager.h, power_manager.c)

  • 功能: 检测电源类型 (Type-C/DC),监控电压,进行电源保护 (例如:低电压告警、过压保护)。
  • 关键技术: ADC电压检测,电源类型识别 (可能通过 GPIO 检测 CC 线 或 电压阈值)。

power_manager.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef POWER_MANAGER_H
#define POWER_MANAGER_H

#include "hal.h"
#include "esp_err.h"

typedef enum {
POWER_SOURCE_TYPEC,
POWER_SOURCE_DC,
POWER_SOURCE_UNKNOWN
} power_source_t;

esp_err_t power_manager_init(void);
power_source_t power_manager_get_source_type(void);
float power_manager_get_voltage(void);
void power_manager_task(void *pvParameters); // 电源管理任务 (FreeRTOS)

#endif // POWER_MANAGER_H

power_manager.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "power_manager.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

static const char *TAG_POWER = "POWER_MGR";

// ----- 电源检测引脚配置 -----
#define POWER_VOLTAGE_ADC_UNIT ADC_UNIT_1
#define POWER_VOLTAGE_ADC_CHANNEL ADC_CHANNEL_7 // 根据实际硬件连接修改
#define POWER_VOLTAGE_ADC_TO_VOLTAGE_COEF 0.001 // 示例系数,需要根据分压电阻校准
#define POWER_TYPEC_DETECT_PIN GPIO_NUM_34 // 示例 Type-C 检测引脚 (CC 线检测)
#define POWER_DC_VOLTAGE_THRESHOLD 7.0f // 示例 DC 电源电压阈值 (V)

static power_source_t current_power_source = POWER_SOURCE_UNKNOWN;
static float current_voltage = 0.0f;

// ----- 初始化电源管理模块 -----
esp_err_t power_manager_init(void) {
ESP_LOGI(TAG_POWER, "Initializing Power Manager Module...");
hal_adc_init(POWER_VOLTAGE_ADC_UNIT, POWER_VOLTAGE_ADC_CHANNEL);
hal_gpio_init(POWER_TYPEC_DETECT_PIN, GPIO_MODE_INPUT, GPIO_PULLDOWN); // Type-C 检测引脚

return ESP_OK;
}

// ----- 获取电源类型 -----
power_source_t power_manager_get_source_type(void) {
return current_power_source;
}

// ----- 获取电压值 -----
float power_manager_get_voltage(void) {
return current_voltage;
}

// ----- 电源管理任务 (FreeRTOS Task) -----
void power_manager_task(void *pvParameters) {
ESP_LOGI(TAG_POWER, "Power Manager Task started");
while (1) {
// 读取电压 ADC 值并转换为电压值
int adc_raw_value = hal_adc_read_voltage(POWER_VOLTAGE_ADC_UNIT, POWER_VOLTAGE_ADC_CHANNEL);
current_voltage = (float)adc_raw_value * POWER_VOLTAGE_ADC_TO_VOLTAGE_COEF; // 示例线性转换

// 检测电源类型 (示例:Type-C 检测引脚 + 电压阈值)
if (hal_gpio_get_level(POWER_TYPEC_DETECT_PIN) == 1) { // Type-C 检测引脚高电平
current_power_source = POWER_SOURCE_TYPEC;
} else if (current_voltage > POWER_DC_VOLTAGE_THRESHOLD) { // 电压高于 DC 阈值
current_power_source = POWER_SOURCE_DC;
} else {
current_power_source = POWER_SOURCE_UNKNOWN;
}

// 电源保护逻辑 (例如:低电压告警、过压保护)
if (current_voltage < 4.5f) { // 低电压告警 (示例阈值)
ESP_LOGW(TAG_POWER, "Low Voltage Warning: %.2fV", current_voltage);
// TODO: 低电压告警处理 (例如,显示告警信息,降低加热功率,甚至关机)
} else if (current_voltage > 13.0f) { // 过压保护 (示例阈值)
ESP_LOGE(TAG_POWER, "Over Voltage Protection: %.2fV", current_voltage);
// TODO: 过压保护处理 (例如,立即关机,防止硬件损坏)
}

ESP_LOGD(TAG_POWER, "Voltage: %.2fV, Source: %d", current_voltage, current_power_source); // 调试信息
vTaskDelay(pdMS_TO_TICKS(1000)); // 电源监控周期 1秒
}
}

3. 应用层 (Application Layer) 代码示例 (main.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "hal.h"
#include "temperature_control.h"
#include "extruder_control.h"
#include "ui_manager.h"
#include "power_manager.h"

static const char *TAG_MAIN = "MAIN";

void app_main(void)
{
// 初始化 NVS (Non-Volatile Storage)
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);

ESP_LOGI(TAG_MAIN, "3D Printing Pen Firmware Started");

// 初始化各个模块
ESP_ERROR_CHECK(hal_gpio_init(GPIO_NUM_25, GPIO_MODE_OUTPUT, GPIO_PULL_NONE)); // 示例 LED 指示灯
ESP_ERROR_CHECK(hal_gpio_set_level(GPIO_NUM_25, 1)); // 点亮 LED

ESP_ERROR_CHECK(temp_control_init());
ESP_ERROR_CHECK(extruder_control_init());
ESP_ERROR_CHECK(ui_manager_init());
ESP_ERROR_CHECK(power_manager_init());

// 创建 FreeRTOS 任务
xTaskCreatePinnedToCore(temp_control_task, "TempControlTask", 4096, NULL, 5, NULL, 1); // 核心 1
xTaskCreatePinnedToCore(ui_manager_task, "UIManagerTask", 4096, NULL, 4, NULL, 0); // 核心 0 (UI 任务通常放在核心 0)
xTaskCreatePinnedToCore(power_manager_task, "PowerManagerTask", 2048, NULL, 3, NULL, 1); // 核心 1

// 示例应用逻辑 (可以在 UI 任务中触发)
temp_control_set_target_temp(190.0f); // 设置目标温度
temp_control_enable_heater(true); // 启动加热

// 示例挤出控制 (可以在 UI 任务中触发)
// extruder_control_start_extrude();
// vTaskDelay(pdMS_TO_TICKS(5000)); // 挤出 5 秒
// extruder_control_stop_extrude();

ESP_LOGI(TAG_MAIN, "Main task finished, other tasks running in background");
}

三、实践验证与测试

为了验证系统设计的可靠性、高效性和功能性,需要进行全面的测试:

  1. 单元测试: 针对每个模块 (例如:温度控制模块、挤出控制模块) 进行单元测试,验证模块内部逻辑的正确性。可以使用CUnit、Unity等单元测试框架。
  2. 集成测试: 将各个模块集成起来进行测试,验证模块之间的接口和协作是否正常。
  3. 系统测试: 进行整体系统功能测试,模拟用户使用场景,测试3D打印笔的各项功能是否符合需求,例如:
    • 温度控制精度测试: 验证温度控制精度和稳定性。
    • 挤出控制测试: 验证挤出速度控制的精度和响应速度。
    • 用户界面测试: 验证用户界面操作的流畅性和易用性。
    • 电源管理测试: 验证电源类型检测、电压监控和保护功能的有效性。
  4. 压力测试: 长时间运行系统,测试系统的稳定性和可靠性,例如长时间打印测试,温度循环测试等。
  5. 边界测试: 测试系统在边界条件下的表现,例如:极限温度、极限电压、异常输入等。

测试方法:

  • 代码审查: 进行代码审查,检查代码逻辑错误、潜在bug和代码风格。
  • 静态分析: 使用静态分析工具 (例如:Cppcheck, Coverity) 扫描代码,检测潜在的缺陷和安全漏洞。
  • 动态测试: 在实际硬件上运行代码,使用示波器、万用表、温度计等工具进行测量和验证。
  • 自动化测试: 编写自动化测试脚本,提高测试效率和覆盖率。

四、维护与升级

为了保证系统的长期稳定运行和持续改进,需要考虑维护和升级:

  1. 固件升级 (OTA - Over-The-Air): 预留固件空中升级功能,方便用户在线升级固件,修复bug和添加新功能。ESP-IDF提供了OTA升级的示例和库。
  2. 日志记录与错误报告: 完善日志记录功能,记录系统运行状态和错误信息,方便问题定位和分析。可以考虑将日志输出到串口、SD卡或通过WiFi发送到远程服务器。
  3. 模块化设计: 采用模块化设计,方便后期维护和升级,修改一个模块不会影响其他模块。
  4. 版本控制: 使用版本控制系统 (例如:Git) 管理代码,方便代码版本管理和协作开发。
  5. 用户反馈机制: 建立用户反馈渠道,收集用户意见和bug报告,持续改进产品。

总结

以上代码和架构设计提供了一个基于ESP32的3D打印笔嵌入式系统的完整框架。这套架构采用分层设计,模块化清晰,并结合了FreeRTOS实时操作系统,以确保系统的可靠性、高效性和可扩展性。代码示例涵盖了HAL层、温度控制、挤出控制、用户界面和电源管理等关键模块,并给出了实践验证、测试和维护升级的建议。

请注意,以上代码仅为示例代码,可能需要根据具体的硬件平台和需求进行调整和完善。例如,温度传感器型号、电机驱动器类型、显示屏型号等都需要根据实际硬件进行配置和驱动开发。同时,PID参数、挤出速度与PWM占空比的映射关系等也需要根据实际情况进行校准和优化。

希望这份详细的解答能够帮助您理解和开发这款3D打印笔嵌入式系统!如果您有任何进一步的问题,欢迎随时提出。
Error executing command: Traceback (most recent call last):
File “/home/tong/bin/desc_img3.py”, line 73, in
for chunk in client.models.generate_content_stream(
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/models.py”, line 3722, in generate_content_stream
for response_dict in self.api_client.request_streamed(
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/_api_client.py”, line 344, in request_streamed
for chunk in session_response.segments():
File “/home/tong/.local/lib/python3.10/site-packages/google/genai/_api_client.py”, line 133, in segments
yield json.loads(str(chunk, ‘utf-8’))
File “/usr/lib/python3.10/json/init.py”, line 346, in loads
return _default_decoder.decode(s)
File “/usr/lib/python3.10/json/decoder.py”, line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File “/usr/lib/python3.10/json/decoder.py”, line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

欢迎关注我的其它发布渠道